/** * API Login via basic-auth or OAuth */ function api_login(&$a) { $record = null; require_once 'include/oauth.php'; // login with oauth try { $oauth = new ZotOAuth1(); $req = OAuth1Request::from_request(); list($consumer, $token) = $oauth->verify_request($req); if (!is_null($token)) { $oauth->loginUser($token->uid); App::set_oauth_key($consumer->key); call_hooks('logged_in', App::$user); return; } killme(); } catch (Exception $e) { logger($e->getMessage()); } // workarounds for HTTP-auth in CGI mode if (x($_SERVER, 'REDIRECT_REMOTE_USER')) { $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)); if (strlen($userpass)) { list($name, $password) = explode(':', $userpass); $_SERVER['PHP_AUTH_USER'] = $name; $_SERVER['PHP_AUTH_PW'] = $password; } } if (x($_SERVER, 'HTTP_AUTHORIZATION')) { $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)); if (strlen($userpass)) { list($name, $password) = explode(':', $userpass); $_SERVER['PHP_AUTH_USER'] = $name; $_SERVER['PHP_AUTH_PW'] = $password; } } require_once 'include/auth.php'; require_once 'include/security.php'; // process normal login request if (isset($_SERVER['PHP_AUTH_USER'])) { $channel_login = 0; $record = account_verify_password($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']); if ($record && $record['channel']) { $channel_login = $record['channel']['channel_id']; } } if ($record['account']) { authenticate_success($record['account']); if ($channel_login) { change_channel($channel_login); } $_SESSION['allow_api'] = true; return true; } else { $_SERVER['PHP_AUTH_PW'] = '*****'; logger('API_login failure: ' . print_r($_SERVER, true), LOGGER_DEBUG); log_failed_login('API login failure'); retry_basic_auth(); } }
/** * @brief Verify login credentials. * * If system <i>authlog</i> is set a log entry will be added for failed login * attempts. * * @param string $email * The email address to verify. * @param string $pass * The provided password to verify. * @return array|null * Returns account record on success, null on failure. */ function account_verify_password($email, $pass) { $email_verify = get_config('system', 'verify_email'); $register_policy = get_config('system', 'register_policy'); // Currently we only verify email address if there is an open registration policy. // This isn't because of any policy - it's because the workflow gets too complicated if // you have to verify the email and then go through the account approval workflow before // letting them login. if ($email_verify && $register_policy == REGISTER_OPEN && $record['account_flags'] & ACCOUNT_UNVERIFIED) { return null; } $r = q("select * from account where account_email = '%s'", dbesc($email)); if (!($r && count($r))) { return null; } foreach ($r as $record) { if ($record['account_flags'] == ACCOUNT_OK && hash('whirlpool', $record['account_salt'] . $pass) === $record['account_password']) { logger('password verified for ' . $email); return $record; } } $error = 'password failed for ' . $email; logger($error); if ($record['account_flags'] & ACCOUNT_UNVERIFIED) { logger('Account is unverified. account_flags = ' . $record['account_flags']); } if ($record['account_flags'] & ACCOUNT_BLOCKED) { logger('Account is blocked. account_flags = ' . $record['account_flags']); } if ($record['account_flags'] & ACCOUNT_EXPIRED) { logger('Account is expired. account_flags = ' . $record['account_flags']); } if ($record['account_flags'] & ACCOUNT_REMOVED) { logger('Account is removed. account_flags = ' . $record['account_flags']); } if ($record['account_flags'] & ACCOUNT_PENDING) { logger('Account is pending. account_flags = ' . $record['account_flags']); } log_failed_login($error); return null; }
/** * @brief Verify login credentials. * * If system.authlog is set a log entry will be added for failed login * attempts. * * @param string $login * The login to verify (channel address, account email or guest login token). * @param string $pass * The provided password to verify. * @return array|null * Returns account record on success, null on failure. * The return array is dependent on the login mechanism. * $ret['account'] will be set if either an email or channel address validation was successful (local login). * $ret['channel'] will be set if a channel address validation was successful. * $ret['xchan'] will be set if a guest access token validation was successful. * Keys will exist for invalid return arrays but will be set to null. * This function does not perform a login. It merely validates systems passwords and tokens. * */ function account_verify_password($login, $pass) { $ret = ['account' => null, 'channel' => null, 'xchan' => null]; $email_verify = get_config('system', 'verify_email'); $register_policy = get_config('system', 'register_policy'); if (!$login) { return null; } $account = null; $channel = null; $xchan = null; if (!strpos($login, '@')) { $channel = channelx_by_nick($login); if (!$channel) { $x = q("select * from atoken where atoken_name = '%s' and atoken_token = '%s' limit 1", dbesc($login), dbesc($pass)); if ($x) { $ret['xchan'] = atoken_xchan($x[0]); atoken_create_xchan($ret['xchan']); return $ret; } } } if ($channel) { $where = " where account_id = " . intval($channel['channel_account_id']) . " "; } else { $where = " where account_email = '" . dbesc($login) . "' "; } $a = q("select * from account {$where}"); if (!$a) { return null; } $account = $a[0]; // Currently we only verify email address if there is an open registration policy. // This isn't because of any policy - it's because the workflow gets too complicated if // you have to verify the email and then go through the account approval workflow before // letting them login. if ($email_verify && $register_policy == REGISTER_OPEN && $account['account_flags'] & ACCOUNT_UNVERIFIED) { logger('email verification required for ' . $login); return null; } if ($account['account_flags'] == ACCOUNT_OK && hash('whirlpool', $account['account_salt'] . $pass) === $account['account_password']) { logger('password verified for ' . $login); $ret['account'] = $account; if ($channel) { $ret['channel'] = $channel; } return $ret; } $error = 'password failed for ' . $login; logger($error); if ($account['account_flags'] & ACCOUNT_UNVERIFIED) { logger('Account is unverified. account_flags = ' . $account['account_flags']); } if ($account['account_flags'] & ACCOUNT_BLOCKED) { logger('Account is blocked. account_flags = ' . $account['account_flags']); } if ($account['account_flags'] & ACCOUNT_EXPIRED) { logger('Account is expired. account_flags = ' . $account['account_flags']); } if ($account['account_flags'] & ACCOUNT_REMOVED) { logger('Account is removed. account_flags = ' . $account['account_flags']); } if ($account['account_flags'] & ACCOUNT_PENDING) { logger('Account is pending. account_flags = ' . $account['account_flags']); } log_failed_login($error); return null; }
/** * @brief Validates a username and password. * * Guest access is granted with the password "+++". * * @see \Sabre\DAV\Auth\Backend\AbstractBasic::validateUserPass * @param string $username * @param string $password * @return bool */ protected function validateUserPass($username, $password) { require_once 'include/auth.php'; $record = account_verify_password($username, $password); if ($record && $record['account_default_channel']) { $r = q("SELECT * FROM channel WHERE channel_account_id = %d AND channel_id = %d LIMIT 1", intval($record['account_id']), intval($record['account_default_channel'])); if ($r) { return $this->setAuthenticated($r[0]); } } $r = q("SELECT * FROM channel WHERE channel_address = '%s' LIMIT 1", dbesc($username)); if ($r) { $x = q("SELECT account_flags, account_salt, account_password FROM account WHERE account_id = %d LIMIT 1", intval($r[0]['channel_account_id'])); if ($x) { // @fixme this foreach should not be needed? foreach ($x as $record) { if (($record['account_flags'] == ACCOUNT_OK || $record['account_flags'] == ACCOUNT_UNVERIFIED) && hash('whirlpool', $record['account_salt'] . $password) === $record['account_password']) { logger('password verified for ' . $username); return $this->setAuthenticated($r[0]); } } } } $error = 'password failed for ' . $username; logger($error); log_failed_login($error); return false; }
/** * @brief Validates a username and password. * * * @see \Sabre\DAV\Auth\Backend\AbstractBasic::validateUserPass * @param string $username * @param string $password * @return bool */ protected function validateUserPass($username, $password) { require_once 'include/auth.php'; $record = account_verify_password($username, $password); if ($record && $record['account']) { if ($record['channel']) { $channel = $record['channel']; } else { $r = q("SELECT * FROM channel WHERE channel_account_id = %d AND channel_id = %d LIMIT 1", intval($record['account']['account_id']), intval($record['account']['account_default_channel'])); if ($r) { $channel = $r[0]; } } } if ($channel && $this->check_module_access($channel['channel_id'])) { return $this->setAuthenticated($channel); } if ($this->module_disabled) { $error = 'module not enabled for ' . $username; } else { $error = 'password failed for ' . $username; } logger($error); log_failed_login($error); return false; }