function Login2() { global $txt, $scripturl, $user_info, $user_settings, $smcFunc; global $cookiename, $maintenance, $modSettings, $context, $sc, $sourcedir; // Load cookie authentication stuff. require_once $sourcedir . '/Subs-Auth.php'; if (isset($_GET['sa']) && $_GET['sa'] == 'salt' && !$user_info['is_guest']) { if (isset($_COOKIE[$cookiename]) && preg_match('~^a:[34]:\\{i:0;(i:\\d{1,6}|s:[1-8]:"\\d{1,8}");i:1;s:(0|40):"([a-fA-F0-9]{40})?";i:2;[id]:\\d{1,14};(i:3;i:\\d;)?\\}$~', $_COOKIE[$cookiename]) === 1) { list(, , $timeout) = @unserialize($_COOKIE[$cookiename]); } elseif (isset($_SESSION['login_' . $cookiename])) { list(, , $timeout) = @unserialize($_SESSION['login_' . $cookiename]); } else { trigger_error('Login2(): Cannot be logged in without a session or cookie', E_USER_ERROR); } $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4); updateMemberData($user_info['id'], array('password_salt' => $user_settings['password_salt'])); setLoginCookie($timeout - time(), $user_info['id'], sha1($user_settings['passwd'] . $user_settings['password_salt'])); redirectexit('action=login2;sa=check;member=' . $user_info['id'], $context['server']['needs_login_fix']); } elseif (isset($_GET['sa']) && $_GET['sa'] == 'check') { // Strike! You're outta there! if ($_GET['member'] != $user_info['id']) { fatal_lang_error('login_cookie_error', false); } // Some whitelisting for login_url... if (empty($_SESSION['login_url'])) { redirectexit(); } else { // Best not to clutter the session data too much... $temp = $_SESSION['login_url']; unset($_SESSION['login_url']); redirectexit($temp); } } // Beyond this point you are assumed to be a guest trying to login. if (!$user_info['is_guest']) { redirectexit(); } // Set the login_url if it's not already set (but careful not to send us to an attachment). if (empty($_SESSION['login_url']) && isset($_SESSION['old_url']) && strpos($_SESSION['old_url'], 'dlattach') === false && preg_match('~(board|topic)[=,]~', $_SESSION['old_url']) != 0) { $_SESSION['login_url'] = $_SESSION['old_url']; } // Are you guessing with a script that doesn't keep the session id? spamProtection('login'); // Been guessing a lot, haven't we? if (isset($_SESSION['failed_login']) && $_SESSION['failed_login'] >= $modSettings['failed_login_threshold'] * 3) { fatal_lang_error('login_threshold_fail', 'critical'); } // Set up the cookie length. (if it's invalid, just fall through and use the default.) if (isset($_POST['cookieneverexp']) || !empty($_POST['cookielength']) && $_POST['cookielength'] == -1) { $modSettings['cookieTime'] = 3153600; } elseif (!empty($_POST['cookielength']) && ($_POST['cookielength'] >= 1 || $_POST['cookielength'] <= 525600)) { $modSettings['cookieTime'] = (int) $_POST['cookielength']; } loadLanguage('Login'); // Load the template stuff - wireless or normal. if (WIRELESS) { $context['sub_template'] = WIRELESS_PROTOCOL . '_login'; } else { loadTemplate('Login'); $context['sub_template'] = 'login'; } // Set up the default/fallback stuff. $context['default_username'] = isset($_REQUEST['user']) ? preg_replace('~&#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', htmlspecialchars($_REQUEST['user'])) : ''; $context['default_password'] = ''; $context['never_expire'] = $modSettings['cookieTime'] == 525600 || $modSettings['cookieTime'] == 3153600; $context['login_errors'] = array($txt['error_occured']); $context['page_title'] = $txt['login']; // Add the login chain to the link tree. $context['linktree'][] = array('url' => $scripturl . '?action=login', 'name' => $txt['login']); if (!empty($_REQUEST['openid_identifier']) && !empty($modSettings['enableOpenID'])) { require_once $sourcedir . '/Subs-OpenID.php'; return smf_openID_validate($_REQUEST['openid_identifier']); } // You forgot to type your username, dummy! if (!isset($_REQUEST['user']) || $_REQUEST['user'] == '') { $context['login_errors'] = array($txt['need_username']); return; } // Hmm... maybe 'admin' will login with no password. Uhh... NO! if ((!isset($_POST['passwrd']) || $_POST['passwrd'] == '') && (!isset($_REQUEST['hash_passwrd']) || strlen($_REQUEST['hash_passwrd']) != 40)) { $context['login_errors'] = array($txt['no_password']); return; } // No funky symbols either. if (preg_match('~[<>&"\'=\\\\]~', preg_replace('~(&#(\\d{1,7}|x[0-9a-fA-F]{1,6});)~', '', $_REQUEST['user'])) != 0) { $context['login_errors'] = array($txt['error_invalid_characters_username']); return; } // Are we using any sort of integration to validate the login? if (isset($modSettings['integrate_validate_login']) && is_callable($modSettings['integrate_validate_login'])) { if (call_user_func(strpos($modSettings['integrate_validate_login'], '::') === false ? $modSettings['integrate_validate_login'] : explode('::', $modSettings['integrate_validate_login']), $_REQUEST['user'], isset($_REQUEST['hash_passwrd']) && strlen($_REQUEST['hash_passwrd']) == 40 ? $_REQUEST['hash_passwrd'] : null, $modSettings['cookieTime']) == 'retry') { $context['login_errors'] = array($txt['login_hash_error']); $context['disable_login_hashing'] = true; return; } } // Load the data up! $request = $smcFunc['db_query']('', ' SELECT passwd, id_member, id_group, lngfile, is_activated, email_address, additional_groups, member_name, password_salt, openid_uri, passwd_flood FROM {db_prefix}members WHERE ' . ($smcFunc['db_case_sensitive'] ? 'LOWER(member_name) = LOWER({string:user_name})' : 'member_name = {string:user_name}') . ' LIMIT 1', array('user_name' => $smcFunc['db_case_sensitive'] ? strtolower($_REQUEST['user']) : $_REQUEST['user'])); // Probably mistyped or their email, try it as an email address. (member_name first, though!) if ($smcFunc['db_num_rows']($request) == 0) { $smcFunc['db_free_result']($request); $request = $smcFunc['db_query']('', ' SELECT passwd, id_member, id_group, lngfile, is_activated, email_address, additional_groups, member_name, password_salt, openid_uri, passwd_flood FROM {db_prefix}members WHERE email_address = {string:user_name} LIMIT 1', array('user_name' => $_REQUEST['user'])); // Let them try again, it didn't match anything... if ($smcFunc['db_num_rows']($request) == 0) { $context['login_errors'] = array($txt['username_no_exist']); return; } } $user_settings = $smcFunc['db_fetch_assoc']($request); $smcFunc['db_free_result']($request); // Figure out the password using SMF's encryption - if what they typed is right. if (isset($_REQUEST['hash_passwrd']) && strlen($_REQUEST['hash_passwrd']) == 40) { // Needs upgrading? if (strlen($user_settings['passwd']) != 40) { $context['login_errors'] = array($txt['login_hash_error']); $context['disable_login_hashing'] = true; unset($user_settings); return; } elseif ($_REQUEST['hash_passwrd'] == sha1($user_settings['passwd'] . $sc)) { $sha_passwd = $user_settings['passwd']; } else { // Don't allow this! validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood']); $_SESSION['failed_login'] = @$_SESSION['failed_login'] + 1; if ($_SESSION['failed_login'] >= $modSettings['failed_login_threshold']) { redirectexit('action=reminder'); } else { log_error($txt['incorrect_password'] . ' - <span class="remove">' . $user_settings['member_name'] . '</span>', 'user'); $context['disable_login_hashing'] = true; $context['login_errors'] = array($txt['incorrect_password']); unset($user_settings); return; } } } else { $sha_passwd = sha1(strtolower($user_settings['member_name']) . un_htmlspecialchars($_POST['passwrd'])); } // Bad password! Thought you could fool the database?! if ($user_settings['passwd'] != $sha_passwd) { // Let's be cautious, no hacking please. thanx. validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood']); // Maybe we were too hasty... let's try some other authentication methods. $other_passwords = array(); // None of the below cases will be used most of the time (because the salt is normally set.) if ($user_settings['password_salt'] == '') { // YaBB SE, Discus, MD5 (used a lot), SHA-1 (used some), SMF 1.0.x, IkonBoard, and none at all. $other_passwords[] = crypt($_POST['passwrd'], substr($_POST['passwrd'], 0, 2)); $other_passwords[] = crypt($_POST['passwrd'], substr($user_settings['passwd'], 0, 2)); $other_passwords[] = md5($_POST['passwrd']); $other_passwords[] = sha1($_POST['passwrd']); $other_passwords[] = md5_hmac($_POST['passwrd'], strtolower($user_settings['member_name'])); $other_passwords[] = md5($_POST['passwrd'] . strtolower($user_settings['member_name'])); $other_passwords[] = $_POST['passwrd']; // This one is a strange one... MyPHP, crypt() on the MD5 hash. $other_passwords[] = crypt(md5($_POST['passwrd']), md5($_POST['passwrd'])); // Snitz style - SHA-256. Technically, this is a downgrade, but most PHP configurations don't support sha256 anyway. if (strlen($user_settings['passwd']) == 64 && function_exists('mhash') && defined('MHASH_SHA256')) { $other_passwords[] = bin2hex(mhash(MHASH_SHA256, $_POST['passwrd'])); } // phpBB3 users new hashing. We now support it as well ;). $other_passwords[] = phpBB3_password_check($_POST['passwrd'], $user_settings['passwd']); // APBoard 2 Login Method. $other_passwords[] = md5(crypt($_REQUEST['passwrd'], 'CRYPT_MD5')); } elseif (strlen($user_settings['passwd']) == 32) { // vBulletin 3 style hashing? Let's welcome them with open arms \o/. $other_passwords[] = md5(md5($_POST['passwrd']) . $user_settings['password_salt']); // Hmm.. p'raps it's Invision 2 style? $other_passwords[] = md5(md5($user_settings['password_salt']) . md5($_POST['passwrd'])); // Some common md5 ones. $other_passwords[] = md5($user_settings['password_salt'] . $_POST['passwrd']); $other_passwords[] = md5($_POST['passwrd'] . $user_settings['password_salt']); $other_passwords[] = md5($_POST['passwrd']); $other_passwords[] = md5(md5($_POST['passwrd'])); } elseif (strlen($user_settings['passwd']) == 40) { // Maybe they are using a hash from before the password fix. $other_passwords[] = sha1(strtolower($user_settings['member_name']) . un_htmlspecialchars($_POST['passwrd'])); // BurningBoard3 style of hashing. $other_passwords[] = sha1($user_settings['password_salt'] . sha1($user_settings['password_salt'] . sha1($_REQUEST['passwrd']))); // Perhaps we converted to UTF-8 and have a valid password being hashed differently. if ($context['character_set'] == 'utf8' && !empty($modSettings['previousCharacterSet']) && $modSettings['previousCharacterSet'] != 'utf8') { // Try iconv first, for no particular reason. if (function_exists('iconv')) { $other_passwords['iconv'] = sha1(strtolower(iconv('UTF-8', $modSettings['previousCharacterSet'], $user_settings['member_name'])) . un_htmlspecialchars(iconv('UTF-8', $modSettings['previousCharacterSet'], $_POST['passwrd']))); } // Say it aint so, iconv failed! if (empty($other_passwords['iconv']) && function_exists('mb_convert_encoding')) { $other_passwords[] = sha1(strtolower(mb_convert_encoding($user_settings['member_name'], 'UTF-8', $modSettings['previousCharacterSet'])) . un_htmlspecialchars(mb_convert_encoding($_POST['passwrd'], 'UTF-8', $modSettings['previousCharacterSet']))); } } } // SMF's sha1 function can give a funny result on Linux (Not our fault!). If we've now got the real one let the old one be valid! if (strpos(strtolower(PHP_OS), 'win') !== 0) { require_once $sourcedir . '/Subs-Compat.php'; $other_passwords[] = sha1_smf(strtolower($user_settings['member_name']) . un_htmlspecialchars($_POST['passwrd'])); } // Whichever encryption it was using, let's make it use SMF's now ;). if (in_array($user_settings['passwd'], $other_passwords)) { $user_settings['passwd'] = $sha_passwd; $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4); // Update the password and set up the hash. updateMemberData($user_settings['id_member'], array('passwd' => $user_settings['passwd'], 'password_salt' => $user_settings['password_salt'])); } else { // They've messed up again - keep a count to see if they need a hand. $_SESSION['failed_login'] = @$_SESSION['failed_login'] + 1; // Hmm... don't remember it, do you? Here, try the password reminder ;). if ($_SESSION['failed_login'] >= $modSettings['failed_login_threshold']) { redirectexit('action=reminder'); } else { // Log an error so we know that it didn't go well in the error log. log_error($txt['incorrect_password'] . ' - <span class="remove">' . $user_settings['member_name'] . '</span>', 'user'); $context['login_errors'] = array($txt['incorrect_password']); return; } } } elseif (!empty($user_settings['passwd_flood'])) { // Let's be sure they wern't a little hacker. validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood'], true); // If we got here then we can reset the flood counter. updateMemberData($user_settings['id_member'], array('passwd_flood' => '')); } // Correct password, but they've got no salt; fix it! if ($user_settings['password_salt'] == '') { $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4); updateMemberData($user_settings['id_member'], array('password_salt' => $user_settings['password_salt'])); } // Check their activation status. if (!checkActivation()) { return; } DoLogin(); }
/** * Actually logs you in. * * What it does: * - checks credentials and checks that login was successful. * - it employs protection against a specific IP or user trying to brute force * a login to an account. * - upgrades password encryption on login, if necessary. * - after successful login, redirects you to $_SESSION['login_url']. * - accessed from ?action=login2, by forms. * * On error, uses the same templates action_login() uses. */ public function action_login2() { global $txt, $scripturl, $user_info, $user_settings, $modSettings, $context, $sc; // Load cookie authentication and all stuff. require_once SUBSDIR . '/Auth.subs.php'; // Beyond this point you are assumed to be a guest trying to login. if (!$user_info['is_guest']) { redirectexit(); } // Are you guessing with a script? checkSession('post'); validateToken('login'); spamProtection('login'); // Set the login_url if it's not already set (but careful not to send us to an attachment). if (empty($_SESSION['login_url']) && isset($_SESSION['old_url']) && strpos($_SESSION['old_url'], 'dlattach') === false && preg_match('~(board|topic)[=,]~', $_SESSION['old_url']) != 0 || isset($_GET['quicklogin']) && isset($_SESSION['old_url']) && strpos($_SESSION['old_url'], 'login') === false) { $_SESSION['login_url'] = $_SESSION['old_url']; } // Been guessing a lot, haven't we? if (isset($_SESSION['failed_login']) && $_SESSION['failed_login'] >= $modSettings['failed_login_threshold'] * 3) { fatal_lang_error('login_threshold_fail', 'critical'); } // Set up the cookie length. (if it's invalid, just fall through and use the default.) if (isset($_POST['cookieneverexp']) || !empty($_POST['cookielength']) && $_POST['cookielength'] == -1) { $modSettings['cookieTime'] = 3153600; } elseif (!empty($_POST['cookielength']) && ($_POST['cookielength'] >= 1 || $_POST['cookielength'] <= 525600)) { $modSettings['cookieTime'] = (int) $_POST['cookielength']; } loadLanguage('Login'); // Load the template stuff loadTemplate('Login'); loadJavascriptFile('sha256.js', array('defer' => true)); $context['sub_template'] = 'login'; // Set up the default/fallback stuff. $context['default_username'] = isset($_POST['user']) ? preg_replace('~&#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', htmlspecialchars($_POST['user'], ENT_COMPAT, 'UTF-8')) : ''; $context['default_password'] = ''; $context['never_expire'] = $modSettings['cookieTime'] == 525600 || $modSettings['cookieTime'] == 3153600; $context['login_errors'] = array($txt['error_occurred']); $context['page_title'] = $txt['login']; // Add the login chain to the link tree. $context['linktree'][] = array('url' => $scripturl . '?action=login', 'name' => $txt['login']); // This is an OpenID login. Let's validate... if (!empty($_POST['openid_identifier']) && !empty($modSettings['enableOpenID'])) { require_once SUBSDIR . '/OpenID.subs.php'; $open_id = new OpenID(); if ($open_id->validate($_POST['openid_identifier']) !== 'no_data') { return $open_id; } else { $context['login_errors'] = array($txt['openid_not_found']); return; } } // You forgot to type your username, dummy! if (!isset($_POST['user']) || $_POST['user'] == '') { $context['login_errors'] = array($txt['need_username']); return; } // No one needs a username that long, plus we only support 80 chars in the db if (Util::strlen($_POST['user']) > 80) { $_POST['user'] = Util::substr($_POST['user'], 0, 80); } // Can't use a password > 64 characters sorry, to long and only good for a DoS attack // Plus we expect a 64 character one from SHA-256 if (isset($_POST['passwrd']) && strlen($_POST['passwrd']) > 64 || isset($_POST['hash_passwrd']) && strlen($_POST['hash_passwrd']) > 64) { $context['login_errors'] = array($txt['improper_password']); return; } // Hmm... maybe 'admin' will login with no password. Uhh... NO! if ((!isset($_POST['passwrd']) || $_POST['passwrd'] == '') && (!isset($_POST['hash_passwrd']) || strlen($_POST['hash_passwrd']) != 64)) { $context['login_errors'] = array($txt['no_password']); return; } // No funky symbols either. if (preg_match('~[<>&"\'=\\\\]~', preg_replace('~(&#(\\d{1,7}|x[0-9a-fA-F]{1,6});)~', '', $_POST['user'])) != 0) { $context['login_errors'] = array($txt['error_invalid_characters_username']); return; } // Are we using any sort of integration to validate the login? if (in_array('retry', call_integration_hook('integrate_validate_login', array($_POST['user'], isset($_POST['hash_passwrd']) && strlen($_POST['hash_passwrd']) == 40 ? $_POST['hash_passwrd'] : null, $modSettings['cookieTime'])), true)) { $context['login_errors'] = array($txt['login_hash_error']); $context['disable_login_hashing'] = true; return; } // Find them... if we can $user_settings = loadExistingMember($_POST['user']); // Let them try again, it didn't match anything... if (empty($user_settings)) { $context['login_errors'] = array($txt['username_no_exist']); return; } // Figure out if the password is using Elk's encryption - if what they typed is right. if (isset($_POST['hash_passwrd']) && strlen($_POST['hash_passwrd']) === 64) { // Challenge what was passed $valid_password = validateLoginPassword($_POST['hash_passwrd'], $user_settings['passwd']); // Let them in if ($valid_password) { $sha_passwd = $_POST['hash_passwrd']; $valid_password = true; } elseif (preg_match('/^[0-9a-f]{40}$/i', $user_settings['passwd']) && isset($_POST['old_hash_passwrd']) && $_POST['old_hash_passwrd'] === hash('sha1', $user_settings['passwd'] . $sc)) { // Old password passed, turn off hashing and ask for it again so we can update the db to something more secure. $context['login_errors'] = array($txt['login_hash_error']); $context['disable_login_hashing'] = true; unset($user_settings); return; } else { // Don't allow this! validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood']); $_SESSION['failed_login'] = isset($_SESSION['failed_login']) ? $_SESSION['failed_login'] + 1 : 1; // To many tries, maybe they need a reminder if ($_SESSION['failed_login'] >= $modSettings['failed_login_threshold']) { redirectexit('action=reminder'); } else { log_error($txt['incorrect_password'] . ' - <span class="remove">' . $user_settings['member_name'] . '</span>', 'user'); // Wrong password, lets enable plain text responses in case form hashing is causing problems $context['disable_login_hashing'] = true; $context['login_errors'] = array($txt['incorrect_password']); unset($user_settings); return; } } } else { // validateLoginPassword will hash this like the form normally would and check its valid $sha_passwd = $_POST['passwrd']; $valid_password = validateLoginPassword($sha_passwd, $user_settings['passwd'], $user_settings['member_name']); } // Bad password! Thought you could fool the database?! if ($valid_password === false) { // Let's be cautious, no hacking please. thanx. validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood']); // Maybe we were too hasty... let's try some other authentication methods. $other_passwords = $this->_other_passwords($user_settings); // Whichever encryption it was using, let's make it use ElkArte's now ;). if (in_array($user_settings['passwd'], $other_passwords)) { $user_settings['passwd'] = validateLoginPassword($sha_passwd, '', '', true); $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4); // Update the password hash and set up the salt. updateMemberData($user_settings['id_member'], array('passwd' => $user_settings['passwd'], 'password_salt' => $user_settings['password_salt'], 'passwd_flood' => '')); } else { // They've messed up again - keep a count to see if they need a hand. $_SESSION['failed_login'] = isset($_SESSION['failed_login']) ? $_SESSION['failed_login'] + 1 : 1; // Hmm... don't remember it, do you? Here, try the password reminder ;). if ($_SESSION['failed_login'] >= $modSettings['failed_login_threshold']) { redirectexit('action=reminder'); } else { // Log an error so we know that it didn't go well in the error log. log_error($txt['incorrect_password'] . ' - <span class="remove">' . $user_settings['member_name'] . '</span>', 'user'); $context['login_errors'] = array($txt['incorrect_password']); return; } } } elseif (!empty($user_settings['passwd_flood'])) { // Let's be sure they weren't a little hacker. validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood'], true); // If we got here then we can reset the flood counter. updateMemberData($user_settings['id_member'], array('passwd_flood' => '')); } // Correct password, but they've got no salt; fix it! if ($user_settings['password_salt'] == '') { $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4); updateMemberData($user_settings['id_member'], array('password_salt' => $user_settings['password_salt'])); } // Check their activation status. if (!checkActivation()) { return; } doLogin(); }
/** * Callback action handler for OpenID */ public function action_openidreturn() { global $modSettings, $context, $user_settings; // We'll need our subs. require_once SUBSDIR . '/OpenID.subs.php'; // Is OpenID even enabled? if (empty($modSettings['enableOpenID'])) { fatal_lang_error('no_access', false); } // The OpenID provider did not respond with the OpenID mode? Throw an error.. if (!isset($_GET['openid_mode'])) { fatal_lang_error('openid_return_no_mode', false); } // @todo Check for error status! if ($_GET['openid_mode'] != 'id_res') { fatal_lang_error('openid_not_resolved'); } // this has annoying habit of removing the + from the base64 encoding. So lets put them back. foreach (array('openid_assoc_handle', 'openid_invalidate_handle', 'openid_sig', 'sf') as $key) { if (isset($_GET[$key])) { $_GET[$key] = str_replace(' ', '+', $_GET[$key]); } } $openID = new OpenID(); // Did they tell us to remove any associations? if (!empty($_GET['openid_invalidate_handle'])) { $openID->removeAssociation($_GET['openid_invalidate_handle']); } // Get the OpenID server info. $server_info = $openID->getServerInfo($_GET['openid_identity']); // Get the association data. $assoc = $openID->getAssociation($server_info['server'], $_GET['openid_assoc_handle'], true); if ($assoc === null) { fatal_lang_error('openid_no_assoc'); } $secret = base64_decode($assoc['secret']); $signed = explode(',', $_GET['openid_signed']); $verify_str = ''; foreach ($signed as $sign) { $verify_str .= $sign . ':' . strtr($_GET['openid_' . str_replace('.', '_', $sign)], array('&' => '&')) . "\n"; } $verify_str = base64_encode(hash_hmac('sha1', $verify_str, $secret, true)); // Verify the OpenID signature. if ($verify_str != $_GET['openid_sig']) { fatal_lang_error('openid_sig_invalid', 'critical'); } if (!isset($_SESSION['openid']['saved_data'][$_GET['t']])) { fatal_lang_error('openid_load_data'); } $openid_uri = $_SESSION['openid']['saved_data'][$_GET['t']]['openid_uri']; $modSettings['cookieTime'] = $_SESSION['openid']['saved_data'][$_GET['t']]['cookieTime']; if (empty($openid_uri)) { fatal_lang_error('openid_load_data'); } // Any save fields to restore? $context['openid_save_fields'] = isset($_GET['sf']) ? unserialize(base64_decode($_GET['sf'])) : array(); $context['openid_claimed_id'] = $_GET['openid_claimed_id']; // Is there a user with this OpenID_uri? $member_found = memberByOpenID($context['openid_claimed_id']); if (empty($member_found) && isset($_GET['sa']) && $_GET['sa'] == 'change_uri' && !empty($_SESSION['new_openid_uri']) && $_SESSION['new_openid_uri'] == $context['openid_claimed_id']) { // Update the member. updateMemberData($user_settings['id_member'], array('openid_uri' => $context['openid_claimed_id'])); unset($_SESSION['new_openid_uri']); $_SESSION['openid'] = array('verified' => true, 'openid_uri' => $context['openid_claimed_id']); // Send them back to profile. redirectexit('action=profile;area=authentication;updated'); } elseif (empty($member_found)) { // Store the received openid info for the user when returned to the registration page. $_SESSION['openid'] = array('verified' => true, 'openid_uri' => $context['openid_claimed_id']); if (isset($_GET['openid_sreg_nickname'])) { $_SESSION['openid']['nickname'] = $_GET['openid_sreg_nickname']; } if (isset($_GET['openid_sreg_email'])) { $_SESSION['openid']['email'] = $_GET['openid_sreg_email']; } if (isset($_GET['openid_sreg_dob'])) { $_SESSION['openid']['dob'] = $_GET['openid_sreg_dob']; } if (isset($_GET['openid_sreg_gender'])) { $_SESSION['openid']['gender'] = $_GET['openid_sreg_gender']; } // Were we just verifying the registration state? if (isset($_GET['sa']) && $_GET['sa'] == 'register2') { require_once CONTROLLERDIR . '/Register.controller.php'; $controller = new Register_Controller(); return $controller->action_register2(true); } else { redirectexit('action=register'); } } elseif (isset($_GET['sa']) && $_GET['sa'] == 'revalidate' && $user_settings['openid_uri'] == $openid_uri) { $_SESSION['openid_revalidate_time'] = time(); // Restore the get data. require_once SUBSDIR . '/Auth.subs.php'; $_SESSION['openid']['saved_data'][$_GET['t']]['get']['openid_restore_post'] = $_GET['t']; $query_string = construct_query_string($_SESSION['openid']['saved_data'][$_GET['t']]['get']); redirectexit($query_string); } else { $user_settings = $member_found; // @Todo: this seems outdated? $user_settings['passwd'] = sha1(strtolower($user_settings['member_name']) . $secret); $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4); updateMemberData($user_settings['id_member'], array('passwd' => $user_settings['passwd'], 'password_salt' => $user_settings['password_salt'])); // Cleanup on Aisle 5. $_SESSION['openid'] = array('verified' => true, 'openid_uri' => $context['openid_claimed_id']); require_once CONTROLLERDIR . '/Auth.controller.php'; // Activation required? if (!checkActivation()) { return; } // Finally do the login. doLogin(); } }
function smf_openID_return() { global $smcFunc, $user_info, $user_profile, $sourcedir, $modSettings, $context, $sc, $user_settings; // Is OpenID even enabled? if (empty($modSettings['enableOpenID'])) { fatal_lang_error('no_access', false); } if (!isset($_GET['openid_mode'])) { fatal_lang_error('openid_return_no_mode', false); } // @todo Check for error status! if ($_GET['openid_mode'] != 'id_res') { fatal_lang_error('openid_not_resolved'); } // SMF has this annoying habit of removing the + from the base64 encoding. So lets put them back. foreach (array('openid_assoc_handle', 'openid_invalidate_handle', 'openid_sig', 'sf') as $key) { if (isset($_GET[$key])) { $_GET[$key] = str_replace(' ', '+', $_GET[$key]); } } // Did they tell us to remove any associations? if (!empty($_GET['openid_invalidate_handle'])) { smf_openid_removeAssociation($_GET['openid_invalidate_handle']); } $server_info = smf_openid_getServerInfo($_GET['openid_identity']); // Get the association data. $assoc = smf_openID_getAssociation($server_info['server'], $_GET['openid_assoc_handle'], true); if ($assoc === null) { fatal_lang_error('openid_no_assoc'); } $secret = base64_decode($assoc['secret']); $signed = explode(',', $_GET['openid_signed']); $verify_str = ''; foreach ($signed as $sign) { $verify_str .= $sign . ':' . strtr($_GET['openid_' . str_replace('.', '_', $sign)], array('&' => '&')) . "\n"; } $verify_str = base64_encode(sha1_hmac($verify_str, $secret)); if ($verify_str != $_GET['openid_sig']) { fatal_lang_error('openid_sig_invalid', 'critical'); } if (!isset($_SESSION['openid']['saved_data'][$_GET['t']])) { fatal_lang_error('openid_load_data'); } $openid_uri = $_SESSION['openid']['saved_data'][$_GET['t']]['openid_uri']; $modSettings['cookieTime'] = $_SESSION['openid']['saved_data'][$_GET['t']]['cookieTime']; if (empty($openid_uri)) { fatal_lang_error('openid_load_data'); } // Any save fields to restore? $context['openid_save_fields'] = isset($_GET['sf']) ? unserialize(base64_decode($_GET['sf'])) : array(); // Is there a user with this OpenID_uri? $result = $smcFunc['db_query']('', ' SELECT passwd, id_member, id_group, lngfile, is_activated, email_address, additional_groups, member_name, password_salt, openid_uri FROM {db_prefix}members WHERE openid_uri = {string:openid_uri}', array('openid_uri' => $openid_uri)); $member_found = $smcFunc['db_num_rows']($result); if (!$member_found && isset($_GET['sa']) && $_GET['sa'] == 'change_uri' && !empty($_SESSION['new_openid_uri']) && $_SESSION['new_openid_uri'] == $openid_uri) { // Update the member. updateMemberData($user_settings['id_member'], array('openid_uri' => $openid_uri)); unset($_SESSION['new_openid_uri']); $_SESSION['openid'] = array('verified' => true, 'openid_uri' => $openid_uri); // Send them back to profile. redirectexit('action=profile;area=authentication;updated'); } elseif (!$member_found) { // Store the received openid info for the user when returned to the registration page. $_SESSION['openid'] = array('verified' => true, 'openid_uri' => $openid_uri); if (isset($_GET['openid_sreg_nickname'])) { $_SESSION['openid']['nickname'] = $_GET['openid_sreg_nickname']; } if (isset($_GET['openid_sreg_email'])) { $_SESSION['openid']['email'] = $_GET['openid_sreg_email']; } if (isset($_GET['openid_sreg_dob'])) { $_SESSION['openid']['dob'] = $_GET['openid_sreg_dob']; } if (isset($_GET['openid_sreg_gender'])) { $_SESSION['openid']['gender'] = $_GET['openid_sreg_gender']; } // Were we just verifying the registration state? if (isset($_GET['sa']) && $_GET['sa'] == 'register2') { require_once $sourcedir . '/Register.php'; return Register2(true); } else { redirectexit('action=register'); } } elseif (isset($_GET['sa']) && $_GET['sa'] == 'revalidate' && $user_settings['openid_uri'] == $openid_uri) { $_SESSION['openid_revalidate_time'] = time(); // Restore the get data. require_once $sourcedir . '/Subs-Auth.php'; $_SESSION['openid']['saved_data'][$_GET['t']]['get']['openid_restore_post'] = $_GET['t']; $query_string = construct_query_string($_SESSION['openid']['saved_data'][$_GET['t']]['get']); redirectexit($query_string); } else { $user_settings = $smcFunc['db_fetch_assoc']($result); $smcFunc['db_free_result']($result); $user_settings['passwd'] = sha1(strtolower($user_settings['member_name']) . $secret); $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4); updateMemberData($user_settings['id_member'], array('passwd' => $user_settings['passwd'], 'password_salt' => $user_settings['password_salt'])); // Cleanup on Aisle 5. $_SESSION['openid'] = array('verified' => true, 'openid_uri' => $openid_uri); require_once $sourcedir . '/LogInOut.php'; if (!checkActivation()) { return; } DoLogin(); } }
/** * Attempt to authenticate them with HybridAuth * * What it does: * - takes the provider ID from GET var and attempts HybridAuth login. */ public function action_extlogin() { global $context, $user_settings, $user_info, $modSettings; require_once SUBSDIR . '/Extauth.subs.php'; // No provider? Not the user's fault. Silently go back to login. if (!isset($_GET['provider'])) { redirectexit('action=login'); } // Include the HybridAuth external libaray and configuration $config = EXTDIR . '/hybridauth/config.php'; require_once EXTDIR . '/hybridauth/Hybrid/Auth.php'; try { $hybridauth = new Hybrid_Auth($config); // If it exists, go ahead and try it $provider = $_GET['provider']; $adapter = $hybridauth->authenticate($provider); $profile = $adapter->getUserProfile(); $member_found = memberByExtUID($provider, $profile->identifier); // Test here whether it already exists or not and if so, login the user if ($member_found) { // Here, stuff happens to log the person in $user_settings = $member_found; require_once CONTROLLERDIR . '/Auth.controller.php'; // Activation required? if (!checkActivation()) { return; } // And then do the login. Bye! doLogin(); } elseif (isset($_GET['member'])) { checkSession('get'); $member = $_GET['member']; // Create an authentication addAuth($member, $provider, $profile->identifier, $profile->displayName); redirectexit('action=profile;area=extauth'); } else { $_SESSION['extauth_info'] = array('provider' => $provider, 'uid' => $profile->identifier, 'name' => $profile->displayName); redirectexit('action=extauth;sa=register;provider=' . $provider); } } catch (Exception $e) { // In case we have errors 6 or 7, then we have to use Hybrid_Provider_Adapter::logout() to // let hybridauth forget all about the user so we can try to authenticate again. // Display the received error, // to know more please refer to Exceptions handling section on the userguide switch ($e->getCode()) { case 0: echo "Unspecified error."; break; case 1: echo "Hybridauth configuration error."; break; case 2: echo "Provider not properly configured."; break; case 3: redirectexit('action=login'); break; // Unknown or disabled provider // Unknown or disabled provider case 4: echo "Missing provider application credentials."; break; case 5: echo "Authentication failed. " . "The user has canceled the authentication or the provider refused the connection."; break; case 6: echo "User profile request failed. Most likely the user is not connected " . "to the provider and he should to authenticate again."; $adapter->logout(); break; case 7: echo "User not connected to the provider."; $adapter->logout(); break; case 8: echo "Provider does not support this feature."; break; } } }