/** * Authenticates the user if authentication headers are present * * Our handling of the speedlimit here requires some explanation ... * Atompub clients will usually try to do everything without logging in first. * Since that would mean that we can't provide feeds for drafts, items with * special permissions, etc. we ask them to log in (PLG_RET_AUTH_FAILED). * That, however, means that every request from an Atompub client will count * as one failed login attempt. So doing a couple of requests in quick * succession will surely get the client blocked. Therefore * - a request without any login credentials counts as one failed login attempt * - a request with wrong login credentials counts as two failed login attempts * - if, after a successful login, we have only one failed attempt on record, * we reset the speedlimit * This still ensures that * - repeated failed logins (without or with invalid credentials) will cause the * client to be blocked eventually * - this can not be used for dictionary attacks * */ function WS_authenticate() { global $_CONF, $_TABLES, $_USER, $_GROUPS, $_RIGHTS, $WS_VERBOSE; $uid = ''; $username = ''; $password = ''; $status = -1; if (isset($_SERVER['PHP_AUTH_USER'])) { $username = COM_applyBasicFilter($_SERVER['PHP_AUTH_USER']); $password = $_SERVER['PHP_AUTH_PW']; if ($WS_VERBOSE) { COM_errorLog("WS: Attempting to log in user '{$username}'"); } /** this does not work! ******************************************************* } elseif (!empty($_SERVER['HTTP_X_WSSE']) && (strpos($_SERVER['HTTP_X_WSSE'], 'UsernameToken') !== false)) { // this is loosely based on a code snippet taken from Elgg (elgg.org) $wsse = str_replace('UsernameToken', '', $_SERVER['HTTP_X_WSSE']); $wsse = explode(',', $wsse); $username = ''; $pwdigest = ''; $created = ''; $nonce = ''; foreach ($wsse as $element) { $element = explode('=', $element); $key = array_shift($element); if (count($element) == 1) { $val = $element[0]; } else { $val = implode('=', $element); } $key = trim($key); $val = trim($val, "\x22\x27"); if ($key == 'Username') { $username = COM_applyBasicFilter($val); } elseif ($key == 'PasswordDigest') { $pwdigest = $val; } elseif ($key == 'Created') { $created = $val; } elseif ($key == 'Nonce') { $nonce = $val; } } if (!empty($username) && !empty($pwdigest) && !empty($created) && !empty($nonce)) { $uname = DB_escapeString($username); $pwd = DB_getItem($_TABLES['users'], 'passwd', "username = '******'"); // ... and here we would need the _unencrypted_ password if (!empty($pwd)) { $mydigest = pack('H*', sha1($nonce . $created . $pwd)); $mydigest = base64_encode($mydigest); if ($pwdigest == $mydigest) { $password = $pwd; } } } if ($WS_VERBOSE) { COM_errorLog("WS: Attempting to log in user '$username' (via WSSE)"); } ******************************************************************************/ } elseif (!empty($_SERVER['REMOTE_USER'])) { /* PHP installed as CGI may not have access to authorization headers of * Apache. In that case, use .htaccess to store the auth header as * explained at * http://wiki.geeklog.net/wiki/index.php/Webservices_API#Authentication */ list($auth_type, $auth_data) = explode(' ', $_SERVER['REMOTE_USER']); list($username, $password) = explode(':', base64_decode($auth_data)); $username = COM_applyBasicFilter($username); if ($WS_VERBOSE) { COM_errorLog("WS: Attempting to log in user '{$username}' (via \$_SERVER['REMOTE_USER'])"); } } else { if ($WS_VERBOSE) { COM_errorLog("WS: No login given"); } // fallthrough (see below) } COM_clearSpeedlimit($_CONF['login_speedlimit'], 'wsauth'); if (COM_checkSpeedlimit('wsauth', $_CONF['login_attempts']) > 0) { WS_error(PLG_RET_PERMISSION_DENIED, 'Speed Limit exceeded'); } if (!empty($username) && !empty($password)) { if ($_CONF['user_login_method']['3rdparty']) { // remote users will have to use username@servicename $u = explode('@', $username); if (count($u) > 1) { $sv = $u[count($u) - 1]; if (!empty($sv)) { $modules = SEC_collectRemoteAuthenticationModules(); foreach ($modules as $smod) { if (strcasecmp($sv, $smod) == 0) { array_pop($u); // drop the service name $uname = implode('@', $u); $status = SEC_remoteAuthentication($uname, $password, $smod, $uid); break; } } } } } if ($status == -1 && $_CONF['user_login_method']['standard']) { $status = SEC_authenticate($username, $password, $uid); } } if ($status == USER_ACCOUNT_ACTIVE) { $_USER = SESS_getUserDataFromId($uid); PLG_loginUser($_USER['uid']); // Global array of groups current user belongs to $_GROUPS = SEC_getUserGroups($_USER['uid']); // Global array of current user permissions [read,edit] $_RIGHTS = explode(',', SEC_getUserPermissions()); if ($_CONF['restrict_webservices']) { if (!SEC_hasRights('webservices.atompub')) { COM_updateSpeedlimit('wsauth'); if ($WS_VERBOSE) { COM_errorLog("WS: User '{$_USER['username']}' ({$_USER['uid']}) does not have permission to use the webservices"); } // reset user, groups, and rights, just in case ... $_USER = array(); $_GROUPS = array(); $_RIGHTS = array(); WS_error(PLG_RET_AUTH_FAILED); } } if ($WS_VERBOSE) { COM_errorLog("WS: User '{$_USER['username']}' ({$_USER['uid']}) successfully logged in"); } // if there were less than 2 failed login attempts, reset speedlimit if (COM_checkSpeedlimit('wsauth', 2) == 0) { if ($WS_VERBOSE) { COM_errorLog("WS: Successful login - resetting speedlimit"); } COM_resetSpeedlimit('wsauth'); } } else { COM_updateSpeedlimit('wsauth'); if (!empty($username) && !empty($password)) { COM_updateSpeedlimit('wsauth'); if ($WS_VERBOSE) { COM_errorLog("WS: Wrong login credentials - counting as 2 failed attempts"); } } elseif ($WS_VERBOSE) { COM_errorLog("WS: Empty login credentials - counting as 1 failed attempt"); } WS_error(PLG_RET_AUTH_FAILED); } }
/* Authenticate the user IF credentials are present */ WS_authenticate(); /** * Global array of groups current user belongs to */ if (!COM_isAnonUser()) { $_GROUPS = SEC_getUserGroups($_USER['uid']); } else { $_GROUPS = SEC_getUserGroups(1); } /** * Global array of current user permissions [read,edit] */ $_RIGHTS = explode(',', SEC_getUserPermissions()); switch ($_SERVER['REQUEST_METHOD']) { case 'POST': WS_post(); break; case 'PUT': WS_put(); break; case 'GET': WS_get(); break; case 'DELETE': WS_delete(); break; default: WS_error(PLG_RET_ERROR); } WS_writeSync();
/** * Authenticates the user if authentication headers are present * * Our handling of the speedlimit here requires some explanation ... * Atompub clients will usually try to do everything without logging in first. * Since that would mean that we can't provide feeds for drafts, items with * special permissions, etc. we ask them to log in (PLG_RET_AUTH_FAILED). * That, however, means that every request from an Atompub client will count * as one failed login attempt. So doing a couple of requests in quick * succession will surely get the client blocked. Therefore * - a request without any login credentials counts as one failed login attempt * - a request with wrong login credentials counts as two failed login attempts * - if, after a successful login, we have only one failed attempt on record, * we reset the speedlimit * This still ensures that * - repeated failed logins (without or with invalid credentials) will cause the * client to be blocked eventually * - this can not be used for dictionary attacks * */ function WS_authenticate() { global $_CONF, $_TABLES, $_USER, $_GROUPS, $_RIGHTS, $WS_VERBOSE; $uid = ''; $username = ''; $password = ''; $status = -1; if (isset($_SERVER['PHP_AUTH_USER'])) { $username = $_SERVER['PHP_AUTH_USER']; $password = $_SERVER['PHP_AUTH_PW']; $username = COM_applyFilter($username); $password = COM_applyFilter($password); if ($WS_VERBOSE) { COM_errorLog("WS: Attempting to log in user '{$username}'"); } } elseif (!empty($_SERVER['REMOTE_USER'])) { /* PHP installed as CGI may not have access to authorization headers of * Apache. In that case, use .htaccess to store the auth header */ list($auth_type, $auth_data) = explode(' ', $_SERVER['REMOTE_USER']); list($username, $password) = explode(':', base64_decode($auth_data)); $username = COM_applyFilter($username); $password = COM_applyFilter($password); if ($WS_VERBOSE) { COM_errorLog("WS: Attempting to log in user '{$username}' (via \$_SERVER['REMOTE_USER'])"); } } else { if ($WS_VERBOSE) { COM_errorLog("WS: No login given"); } // fallthrough (see below) } COM_clearSpeedlimit($_CONF['login_speedlimit'], 'wsauth'); if (COM_checkSpeedlimit('wsauth', $_CONF['login_attempts']) > 0) { WS_error(PLG_RET_PERMISSION_DENIED, 'Speed Limit exceeded'); } if (!empty($username) && !empty($password)) { if ($_CONF['user_login_method']['3rdparty']) { // remote users will have to use username@servicename $u = explode('@', $username); if (count($u) > 1) { $sv = $u[count($u) - 1]; if (!empty($sv)) { $modules = SEC_collectRemoteAuthenticationModules(); foreach ($modules as $smod) { if (strcasecmp($sv, $smod) == 0) { array_pop($u); // drop the service name $uname = implode('@', $u); $status = SEC_remoteAuthentication($uname, $password, $smod, $uid); break; } } } } } if ($status == -1 && $_CONF['user_login_method']['standard']) { $status = SEC_authenticate($username, $password, $uid); } } if ($status == USER_ACCOUNT_ACTIVE) { $_USER = SESS_getUserDataFromId($uid); PLG_loginUser($_USER['uid']); // Global array of groups current user belongs to $_GROUPS = SEC_getUserGroups($_USER['uid']); // Global array of current user permissions [read,edit] $_RIGHTS = explode(',', SEC_getUserPermissions()); if ($_CONF['restrict_webservices']) { if (!SEC_hasRights('webservices.atompub')) { COM_updateSpeedlimit('wsauth'); if ($WS_VERBOSE) { COM_errorLog("WS: User '{$_USER['username']}' ({$_USER['uid']}) does not have permission to use the webservices"); } // reset user, groups, and rights, just in case ... $_USER = array(); $_GROUPS = array(); $_RIGHTS = array(); WS_error(PLG_RET_AUTH_FAILED); } } if ($WS_VERBOSE) { COM_errorLog("WS: User '{$_USER['username']}' ({$_USER['uid']}) successfully logged in"); } // if there were less than 2 failed login attempts, reset speedlimit if (COM_checkSpeedlimit('wsauth', 2) == 0) { if ($WS_VERBOSE) { COM_errorLog("WS: Successful login - resetting speedlimit"); } COM_resetSpeedlimit('wsauth'); } } else { COM_updateSpeedlimit('wsauth'); if (!empty($username) && !empty($password)) { COM_updateSpeedlimit('wsauth'); if ($WS_VERBOSE) { COM_errorLog("WS: Wrong login credentials - counting as 2 failed attempts"); } } elseif ($WS_VERBOSE) { COM_errorLog("WS: Empty login credentials - counting as 1 failed attempt"); } WS_error(PLG_RET_AUTH_FAILED); } }