public function index($user_id = 0) { // Set messages to display on the login page for the user $message = FALSE; $message_class = 'login_error'; $auth = Auth::instance(); // If already logged in redirect to user account page $insufficient_role = FALSE; if ($auth->logged_in()) { // Redirect users to the relevant dashboard if ($auth->logged_in('login')) { url::redirect($auth->get_user()->dashboard()); } $insufficient_role = TRUE; $message_class = 'login_error'; $message = Kohana::lang('ui_main.insufficient_role'); } // setup and initialize form field names $form = array('action' => '', 'username' => '', 'password' => '', 'password_again' => '', 'name' => '', 'email' => '', 'resetemail' => '', 'confirmation_email' => ''); // copy the form as errors, so the errors will be stored with keys corresponding to the form field names $errors = $form; $form_error = FALSE; $openid_error = FALSE; $success = FALSE; $change_pw_success = FALSE; $new_confirm_email_form = FALSE; $action = isset($_POST["action"]) ? $_POST["action"] : ""; // Override success variable if change_pw_success GET var is set if (isset($_GET["change_pw_success"])) { $change_pw_success = TRUE; $message_class = 'login_success'; $message = Kohana::lang('ui_main.password_changed_successfully'); } // Show send new confirm email form if (isset($_GET["new_confirm_email"])) { $new_confirm_email_form = TRUE; $message_class = 'login_error'; $message = Kohana::lang('ui_main.must_confirm_email_address'); } // Show send new confirm email form if (isset($_GET["confirmation_failure"])) { $new_confirm_email_form = TRUE; $message_class = 'login_error'; $message = Kohana::lang('ui_main.confirm_email_failed'); } // Show that confirming the email address was a success if (isset($_GET["confirmation_success"])) { $message_class = 'login_success'; $message = Kohana::lang('ui_main.confirm_email_successful'); } // Is this a password reset request? We need to show the password reset form if it is if (isset($_GET["reset"])) { $this->template->token = $this->uri->segment(4); $this->template->changeid = $this->uri->segment(3); } // Regular Form Post for Signin // check, has the form been submitted, if so, setup validation if ($_POST and isset($_POST["action"]) and $_POST["action"] == "signin") { // START: Signin Process $post = Validation::factory($_POST); $post->pre_filter('trim'); $post->add_rules('username', 'required'); $post->add_rules('password', 'required'); if ($post->validate(FALSE)) { // Sanitize $_POST data removing all inputs without rules $postdata_array = $post->safe_array(); // Flip this flag to flase to skip the login $valid_login = TRUE; // Load the user $user = ORM::factory('user', $postdata_array['username']); $remember = isset($post->remember) ? TRUE : FALSE; // Allow a login with username or email address, but we need to figure out which is // which so we can pass the appropriate variable on login. Mostly used for RiverID $email = $postdata_array['username']; if (valid::email($email) == FALSE) { // Invalid Email, we need to grab it from the user account instead $email = $user->email; if (valid::email($email) == FALSE and kohana::config('riverid.enable') == TRUE) { // We don't have any valid email for this user. // Only skip login if we are authenticating with RiverID. $valid_login = FALSE; } } // Auth Login requires catching exceptions to properly show errors try { $login = $auth->login($user, $postdata_array['password'], $remember, $email); // Attempt a login if ($login and $valid_login) { // Action::user_login - User Logged In Event::run('ushahidi_action.user_login', $user); // Exists Redirect to Dashboard url::redirect($user->dashboard()); } else { // If user isn't confirmed, redirect to resend confirmation page if (Kohana::config('settings.require_email_confirmation') and ORM::factory('user', $user)->confirmed == 0) { url::redirect("login?new_confirm_email"); } // Generic Error if exception not passed $post->add_error('password', 'login error'); } } catch (Exception $e) { $error_message = $e->getMessage(); // We use a "custom" message because of RiverID. $post->add_error('password', $error_message); } // repopulate the form fields $form = arr::overwrite($form, $post->as_array()); // populate the error fields, if any // We need to already have created an error message file, for Kohana to use // Pass the error message file name to the errors() method $errors = arr::merge($errors, $post->errors('auth')); $form_error = TRUE; } else { // repopulate the form fields $form = arr::overwrite($form, $post->as_array()); // populate the error fields, if any // We need to already have created an error message file, for Kohana to use // Pass the error message file name to the errors() method $errors = arr::merge($errors, $post->errors('auth')); $form_error = TRUE; } // END: Signin Process } elseif ($_POST and isset($_POST["action"]) and $_POST["action"] == "new") { // START: New User Process $post = Validation::factory($_POST); // Add some filters $post->pre_filter('trim', TRUE); $post->add_rules('password', 'required', 'length[' . kohana::config('auth.password_length') . ']', 'alpha_dash'); $post->add_rules('name', 'required', 'length[3,100]'); $post->add_rules('email', 'required', 'email', 'length[4,64]'); $post->add_callbacks('username', array($this, 'username_exists_chk')); $post->add_callbacks('email', array($this, 'email_exists_chk')); // If Password field is not blank if (!empty($post->password)) { $post->add_rules('password', 'required', 'length[' . kohana::config('auth.password_length') . ']', 'alpha_dash', 'matches[password_again]'); } //pass the post object to any plugins that care to know. Event::run('ushahidi_action.users_add_login_form', $post); if ($post->validate()) { $riverid_id = false; if (kohana::config('riverid.enable') == true) { $riverid = new RiverID(); $riverid->email = $post->email; $riverid->password = $post->password; $riverid->register(); $riverid_id = $riverid->user_id; } $user = User_Model::create_user($post->email, $post->password, $riverid_id, $post->name); //pass the new user on to any plugins that care to know Event::run('ushahidi_action.user_edit', $user); // Send Confirmation email $email_sent = $this->_send_email_confirmation($user); if ($email_sent) { $message_class = 'login_success'; $message = Kohana::lang('ui_main.login_confirmation_sent'); } else { $message_class = 'login_success'; $message = Kohana::lang('ui_main.login_account_creation_successful'); } $success = TRUE; $action = ""; } else { // repopulate the form fields $form = arr::overwrite($form, $post->as_array()); // populate the error fields, if any $errors = arr::merge($errors, $post->errors('auth')); $form_error = TRUE; } // END: New User Process } elseif ($_POST and isset($_POST["action"]) and $_POST["action"] == "forgot") { // START: Forgot Password Process $post = Validation::factory($_POST); // Add some filters $post->pre_filter('trim', TRUE); $post->add_callbacks('resetemail', array($this, 'email_exists_chk')); if ($post->validate()) { $user = ORM::factory('user', $post->resetemail); // Existing User?? if ($user->loaded) { $email_sent = FALSE; // Determine which reset method to use. The options are to use the RiverID server // or to use the normal method which just resets the password locally. if (Kohana::config('riverid.enable') == TRUE and !empty($user->riverid)) { // Reset on RiverID Server $secret_link = url::site('login/index/' . $user->id . '/%token%?reset'); $message = $this->_email_resetlink_message($user->name, $secret_link); $riverid = new RiverID(); $riverid->email = $post->resetemail; $email_sent = $riverid->requestpassword($message); } else { // Reset locally $secret = $user->forgot_password_token(); $secret_link = url::site('login/index/' . $user->id . '/' . urlencode($secret) . '?reset'); $email_sent = $this->_email_resetlink($post->resetemail, $user->name, $secret_link); } if ($email_sent == TRUE) { $message_class = 'login_success'; $message = Kohana::lang('ui_main.login_confirmation_sent'); } else { $message_class = 'login_error'; $message = Kohana::lang('ui_main.unable_send_email'); } $success = TRUE; $action = ""; } } else { // repopulate the form fields $form = arr::overwrite($form, $post->as_array()); // populate the error fields, if any $errors = arr::merge($errors, $post->errors('auth')); $form_error = TRUE; } // END: Forgot Password Process } elseif ($_POST and isset($_POST["action"]) and $_POST["action"] == "changepass") { // START: Password Change Process $post = Validation::factory($_POST); // Add some filters $post->pre_filter('trim', TRUE); $post->add_rules('token', 'required'); $post->add_rules('changeid', 'required'); $post->add_rules('password', 'required', 'length[' . Kohana::config('auth.password_length') . ']', 'alpha_dash'); $post->add_rules('password', 'required', 'length[' . Kohana::config('auth.password_length') . ']', 'alpha_dash', 'matches[password_again]'); if ($post->validate()) { $success = $this->_new_password($post->changeid, $post->password, $post->token); if ($success == TRUE) { // We don't need to see this page anymore if we were successful. We want to go // to the login form and let the user know that they were successful at // changing their password url::redirect("login?change_pw_success"); exit; } $post->add_error('token', 'invalid'); // repopulate the form fields $form = arr::overwrite($form, $post->as_array()); // populate the error fields, if any $errors = arr::merge($errors, $post->errors('auth')); $form_error = TRUE; } else { // repopulate the form fields $form = arr::overwrite($form, $post->as_array()); // populate the error fields, if any $errors = arr::merge($errors, $post->errors('auth')); $form_error = TRUE; } // END: Password Change Process } elseif ($_POST and isset($_POST["action"]) and $_POST["action"] == "resend_confirmation") { // START: Confirmation Email Resend Process $post = Validation::factory($_POST); // Add some filters $post->pre_filter('trim', TRUE); $post->add_callbacks('confirmation_email', array($this, 'email_exists_chk')); if ($post->validate()) { $user = ORM::factory('user', $post->confirmation_email); if ($user->loaded) { // Send Confirmation email $email_sent = $this->_send_email_confirmation($user); if ($email_sent) { $message_class = 'login_success'; $message = Kohana::lang('ui_main.login_confirmation_sent'); $success = TRUE; } else { $message_class = 'login_error'; $message = Kohana::lang('ui_main.unable_send_email'); $success = FALSE; } } else { // ERROR: User doesn't exist $message_class = 'login_error'; $message = Kohana::lang('ui_main.login_email_doesnt_exist'); $success = FALSE; } } else { // repopulate the form fields $form = arr::overwrite($form, $post->as_array()); // populate the error fields, if any $errors = arr::merge($errors, $post->errors('auth')); $form_error = TRUE; } } // Only if we allow OpenID, should we even try this if (Kohana::config('config.allow_openid') == TRUE) { // START: OpenID Shenanigans // OpenID Post try { $openid = new OpenID(); // Retrieve the Name (if available) and Email $openid->required = array("namePerson", "contact/email"); if (!$openid->mode) { if (isset($_POST["openid_identifier"])) { $openid->identity = $_POST["openid_identifier"]; header("Location: " . $openid->authUrl()); } } elseif ($openid->mode == "cancel") { $openid_error = TRUE; $message_class = 'login_error'; $message = "You have canceled authentication!"; } else { if ($openid->validate()) { // Does User Exist? $openid_user = ORM::factory("openid")->where("openid", $openid->identity)->find(); if ($openid_user->loaded and $openid_user->user) { // First log all other sessions out $auth->logout(); // Initiate Ushahidi side login + AutoLogin $auth->force_login($openid_user->user->username); // Exists Redirect to Dashboard url::redirect($user->dashboard()); } else { // Does this openid have the required email?? $new_openid = $openid->getAttributes(); if (!isset($new_openid["contact/email"]) or empty($new_openid["contact/email"])) { $openid_error = TRUE; $message_class = 'login_error'; $message = $openid->identity . " has not been logged in. No Email Address Found."; } else { // Create new User and save OpenID $user = ORM::factory("user"); // But first... does this email address already exist // in the system? if ($user->email_exists($new_openid["contact/email"])) { $openid_error = TRUE; $message_class = 'login_error'; $message = $new_openid["contact/email"] . " is already registered in our system."; } else { $username = "******" . time(); // Random User Name from TimeStamp - can be changed later $password = text::random("alnum", 16); // Create Random Strong Password // Name Available? $user->name = (isset($new_openid["namePerson"]) and !empty($new_openid["namePerson"])) ? $new_openid["namePerson"] : $username; $user->username = $username; $user->password = $password; $user->email = $new_openid["contact/email"]; // Add New Roles $user->add(ORM::factory('role', 'login')); $user->add(ORM::factory('role', 'member')); $user->save(); // Save OpenID and Association $openid_user->user_id = $user->id; $openid_user->openid = $openid->identity; $openid_user->openid_email = $new_openid["contact/email"]; $openid_user->openid_server = $openid->server; $openid_user->openid_date = date("Y-m-d H:i:s"); $openid_user->save(); // Initiate Ushahidi side login + AutoLogin $auth->login($username, $password, TRUE); // Redirect to Dashboard url::redirect($user->dashboard()); } } } } else { $openid_error = TRUE; $message_class = 'login_error'; $message = $openid->identity . "has not been logged in."; } } } catch (ErrorException $e) { $openid_error = TRUE; $message_class = 'login_error'; $message = $e->getMessage(); } // END: OpenID Shenanigans } // Set the little badge under the form informing users that their logins are being managed // by an external service. $this->template->riverid_information = ''; if (kohana::config('riverid.enable') == TRUE) { $riverid = new RiverID(); $this->template->riverid_information = Kohana::lang('ui_main.riverid_information', $riverid->name); $this->template->riverid_url = $riverid->url; } $this->template->errors = $errors; $this->template->success = $success; $this->template->change_pw_success = $change_pw_success; $this->template->form = $form; $this->template->form_error = $form_error; $this->template->new_confirm_email_form = $new_confirm_email_form; // Message to user $this->template->message_class = $message_class; $this->template->message = $message; // This just means the user isn't a member or an admin, so they have nowhere to go, but they are logged in. $this->template->insufficient_role = $insufficient_role; $this->template->site_name = Kohana::config('settings.site_name'); $this->template->site_tagline = Kohana::config('settings.site_tagline'); // Javascript Header $this->template->js = new View('login/login_js'); $this->template->js->action = $action; // Header Nav $header_nav = new View('header_nav'); $this->template->header_nav = $header_nav; $this->template->header_nav->loggedin_user = FALSE; if (isset(Auth::instance()->get_user()->id)) { // Load User $this->template->header_nav->loggedin_role = Auth::instance()->get_user()->dashboard(); $this->template->header_nav->loggedin_user = Auth::instance()->get_user(); } $this->template->header_nav->site_name = Kohana::config('settings.site_name'); }
/** * Actually register the member. * @todo split this function in two functions: * - a function that handles action=register2, which needs no parameter; * - a function that processes the case of OpenID verification. * * @param bool $verifiedOpenID = false */ public function action_register2($verifiedOpenID = false) { global $txt, $modSettings, $context, $user_info; // Start collecting together any errors. $reg_errors = Error_Context::context('register', 0); // We can't validate the token and the session with OpenID enabled. if (!$verifiedOpenID) { checkSession(); if (!validateToken('register', 'post', true, false)) { $reg_errors->addError('token_verification'); } } // Did we save some open ID fields? if ($verifiedOpenID && !empty($context['openid_save_fields'])) { foreach ($context['openid_save_fields'] as $id => $value) { $_POST[$id] = $value; } } // You can't register if it's disabled. if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 3) { fatal_lang_error('registration_disabled', false); } // If we're using an agreement checkbox, did they check it? if (!empty($modSettings['checkboxAgreement']) && !empty($_POST['checkbox_agreement'])) { $_SESSION['registration_agreed'] = true; } // Things we don't do for people who have already confirmed their OpenID allegances via register. if (!$verifiedOpenID) { // Well, if you don't agree, you can't register. if (!empty($modSettings['requireAgreement']) && empty($_SESSION['registration_agreed'])) { redirectexit(); } // Make sure they came from *somewhere*, have a session. if (!isset($_SESSION['old_url'])) { redirectexit('action=register'); } // If we don't require an agreement, we need a extra check for coppa. if (empty($modSettings['requireAgreement']) && !empty($modSettings['coppaAge'])) { $_SESSION['skip_coppa'] = !empty($_POST['accept_agreement']); } // Are they under age, and under age users are banned? if (!empty($modSettings['coppaAge']) && empty($modSettings['coppaType']) && empty($_SESSION['skip_coppa'])) { loadLanguage('Login'); fatal_lang_error('under_age_registration_prohibited', false, array($modSettings['coppaAge'])); } // Check the time gate for miscreants. First make sure they came from somewhere that actually set it up. if (empty($_SESSION['register']['timenow']) || empty($_SESSION['register']['limit'])) { redirectexit('action=register'); } // Failing that, check the time limit for exessive speed. if (time() - $_SESSION['register']['timenow'] < $_SESSION['register']['limit']) { loadLanguage('Login'); $reg_errors->addError('too_quickly'); } // Check whether the visual verification code was entered correctly. if (!empty($modSettings['reg_verification'])) { require_once SUBSDIR . '/VerificationControls.class.php'; $verificationOptions = array('id' => 'register'); $context['visual_verification'] = create_control_verification($verificationOptions, true); if (is_array($context['visual_verification'])) { foreach ($context['visual_verification'] as $error) { $reg_errors->addError($error); } } } } foreach ($_POST as $key => $value) { if (!is_array($_POST[$key])) { $_POST[$key] = htmltrim__recursive(str_replace(array("\n", "\r"), '', $_POST[$key])); } } // Collect all extra registration fields someone might have filled in. $possible_strings = array('birthdate', 'time_format', 'buddy_list', 'pm_ignore_list', 'smiley_set', 'personal_text', 'avatar', 'lngfile', 'location', 'secret_question', 'secret_answer', 'website_url', 'website_title'); $possible_ints = array('pm_email_notify', 'notify_types', 'id_theme', 'gender'); $possible_floats = array('time_offset'); $possible_bools = array('notify_announcements', 'notify_regularity', 'notify_send_body', 'hide_email', 'show_online'); if (isset($_POST['secret_answer']) && $_POST['secret_answer'] != '') { $_POST['secret_answer'] = md5($_POST['secret_answer']); } // Needed for isReservedName() and registerMember(). require_once SUBSDIR . '/Members.subs.php'; // Validation... even if we're not a mall. if (isset($_POST['real_name']) && (!empty($modSettings['allow_editDisplayName']) || allowedTo('moderate_forum'))) { $_POST['real_name'] = trim(preg_replace('~[\\t\\n\\r \\x0B\\0\\x{A0}\\x{AD}\\x{2000}-\\x{200F}\\x{201F}\\x{202F}\\x{3000}\\x{FEFF}]+~u', ' ', $_POST['real_name'])); if (trim($_POST['real_name']) != '' && !isReservedName($_POST['real_name']) && Util::strlen($_POST['real_name']) < 60) { $possible_strings[] = 'real_name'; } } // Handle a string as a birthdate... if (isset($_POST['birthdate']) && $_POST['birthdate'] != '') { $_POST['birthdate'] = strftime('%Y-%m-%d', strtotime($_POST['birthdate'])); } elseif (!empty($_POST['bday1']) && !empty($_POST['bday2'])) { $_POST['birthdate'] = sprintf('%04d-%02d-%02d', empty($_POST['bday3']) ? 0 : (int) $_POST['bday3'], (int) $_POST['bday1'], (int) $_POST['bday2']); } // By default assume email is hidden, only show it if we tell it to. $_POST['hide_email'] = !empty($_POST['allow_email']) ? 0 : 1; // Validate the passed language file. if (isset($_POST['lngfile']) && !empty($modSettings['userLanguage'])) { // Do we have any languages? $context['languages'] = getLanguages(); // Did we find it? if (isset($context['languages'][$_POST['lngfile']])) { $_SESSION['language'] = $_POST['lngfile']; } else { unset($_POST['lngfile']); } } else { unset($_POST['lngfile']); } // Some of these fields we may not want. if (!empty($modSettings['registration_fields'])) { // But we might want some of them if the admin asks for them. $standard_fields = array('location', 'gender'); $reg_fields = explode(',', $modSettings['registration_fields']); $exclude_fields = array_diff($standard_fields, $reg_fields); // Website is a little different if (!in_array('website', $reg_fields)) { $exclude_fields = array_merge($exclude_fields, array('website_url', 'website_title')); } // We used to accept signature on registration but it's being abused by spammers these days, so no more. $exclude_fields[] = 'signature'; } else { $exclude_fields = array('signature', 'location', 'gender', 'website_url', 'website_title'); } $possible_strings = array_diff($possible_strings, $exclude_fields); $possible_ints = array_diff($possible_ints, $exclude_fields); $possible_floats = array_diff($possible_floats, $exclude_fields); $possible_bools = array_diff($possible_bools, $exclude_fields); // Set the options needed for registration. $regOptions = array('interface' => 'guest', 'username' => !empty($_POST['user']) ? $_POST['user'] : '', 'email' => !empty($_POST['email']) ? $_POST['email'] : '', 'password' => !empty($_POST['passwrd1']) ? $_POST['passwrd1'] : '', 'password_check' => !empty($_POST['passwrd2']) ? $_POST['passwrd2'] : '', 'openid' => !empty($_POST['openid_identifier']) ? $_POST['openid_identifier'] : '', 'auth_method' => !empty($_POST['authenticate']) ? $_POST['authenticate'] : '', 'check_reserved_name' => true, 'check_password_strength' => true, 'check_email_ban' => true, 'send_welcome_email' => !empty($modSettings['send_welcomeEmail']), 'require' => !empty($modSettings['coppaAge']) && !$verifiedOpenID && empty($_SESSION['skip_coppa']) ? 'coppa' : (empty($modSettings['registration_method']) ? 'nothing' : ($modSettings['registration_method'] == 1 ? 'activation' : 'approval')), 'extra_register_vars' => array(), 'theme_vars' => array()); // Include the additional options that might have been filled in. foreach ($possible_strings as $var) { if (isset($_POST[$var])) { $regOptions['extra_register_vars'][$var] = Util::htmlspecialchars($_POST[$var], ENT_QUOTES); } } foreach ($possible_ints as $var) { if (isset($_POST[$var])) { $regOptions['extra_register_vars'][$var] = (int) $_POST[$var]; } } foreach ($possible_floats as $var) { if (isset($_POST[$var])) { $regOptions['extra_register_vars'][$var] = (double) $_POST[$var]; } } foreach ($possible_bools as $var) { if (isset($_POST[$var])) { $regOptions['extra_register_vars'][$var] = empty($_POST[$var]) ? 0 : 1; } } // Registration options are always default options... if (isset($_POST['default_options'])) { $_POST['options'] = isset($_POST['options']) ? $_POST['options'] + $_POST['default_options'] : $_POST['default_options']; } $regOptions['theme_vars'] = isset($_POST['options']) && is_array($_POST['options']) ? $_POST['options'] : array(); // Make sure they are clean, dammit! $regOptions['theme_vars'] = htmlspecialchars__recursive($regOptions['theme_vars']); // Check whether we have fields that simply MUST be displayed? require_once SUBSDIR . '/Profile.subs.php'; loadCustomFields(0, 'register'); foreach ($context['custom_fields'] as $row) { // Don't allow overriding of the theme variables. if (isset($regOptions['theme_vars'][$row['colname']])) { unset($regOptions['theme_vars'][$row['colname']]); } // Prepare the value! $value = isset($_POST['customfield'][$row['colname']]) ? trim($_POST['customfield'][$row['colname']]) : ''; // We only care for text fields as the others are valid to be empty. if (!in_array($row['type'], array('check', 'select', 'radio'))) { // Is it too long? if ($row['field_length'] && $row['field_length'] < Util::strlen($value)) { $reg_errors->addError(array('custom_field_too_long', array($row['name'], $row['field_length']))); } // Any masks to apply? if ($row['type'] == 'text' && !empty($row['mask']) && $row['mask'] != 'none') { // @todo We never error on this - just ignore it at the moment... if ($row['mask'] == 'email' && !isValidEmail($value)) { $reg_errors->addError(array('custom_field_invalid_email', array($row['name']))); } elseif ($row['mask'] == 'number' && preg_match('~[^\\d]~', $value)) { $reg_errors->addError(array('custom_field_not_number', array($row['name']))); } elseif (substr($row['mask'], 0, 5) == 'regex' && trim($value) !== '' && preg_match(substr($row['mask'], 5), $value) === 0) { $reg_errors->addError(array('custom_field_inproper_format', array($row['name']))); } } } // Is this required but not there? if (trim($value) == '' && $row['show_reg'] > 1) { $reg_errors->addError(array('custom_field_empty', array($row['name']))); } } // Lets check for other errors before trying to register the member. if ($reg_errors->hasErrors()) { $_REQUEST['step'] = 2; // If they've filled in some details but made an error then they need less time to finish $_SESSION['register']['limit'] = 4; return $this->action_register(); } // If they're wanting to use OpenID we need to validate them first. if (empty($_SESSION['openid']['verified']) && !empty($_POST['authenticate']) && $_POST['authenticate'] == 'openid') { // What do we need to save? $save_variables = array(); foreach ($_POST as $k => $v) { if (!in_array($k, array('sc', 'sesc', $context['session_var'], 'passwrd1', 'passwrd2', 'regSubmit'))) { $save_variables[$k] = $v; } } require_once SUBSDIR . '/OpenID.subs.php'; $openID = new OpenID(); $openID->validate($_POST['openid_identifier'], false, $save_variables); } elseif ($verifiedOpenID || (!empty($_POST['openid_identifier']) || !empty($_SESSION['openid']['openid_uri'])) && $_POST['authenticate'] == 'openid') { $regOptions['username'] = !empty($_POST['user']) && trim($_POST['user']) != '' ? $_POST['user'] : $_SESSION['openid']['nickname']; $regOptions['email'] = !empty($_POST['email']) && trim($_POST['email']) != '' ? $_POST['email'] : $_SESSION['openid']['email']; $regOptions['auth_method'] = 'openid'; $regOptions['openid'] = !empty($_SESSION['openid']['openid_uri']) ? $_SESSION['openid']['openid_uri'] : (!empty($_POST['openid_identifier']) ? $_POST['openid_identifier'] : ''); } // Registration needs to know your IP $req = request(); $regOptions['ip'] = $user_info['ip']; $regOptions['ip2'] = $req->ban_ip(); $memberID = registerMember($regOptions, 'register'); // If there are "important" errors and you are not an admin: log the first error // Otherwise grab all of them and don't log anything if ($reg_errors->hasErrors(1) && !$user_info['is_admin']) { foreach ($reg_errors->prepareErrors(1) as $error) { fatal_error($error, 'general'); } } // Was there actually an error of some kind dear boy? if ($reg_errors->hasErrors()) { $_REQUEST['step'] = 2; return $this->action_register(); } // Do our spam protection now. spamProtection('register'); // We'll do custom fields after as then we get to use the helper function! if (!empty($_POST['customfield'])) { require_once SUBSDIR . '/Profile.subs.php'; makeCustomFieldChanges($memberID, 'register'); } // If COPPA has been selected then things get complicated, setup the template. if (!empty($modSettings['coppaAge']) && empty($_SESSION['skip_coppa'])) { redirectexit('action=coppa;member=' . $memberID); } elseif (!empty($modSettings['registration_method'])) { loadTemplate('Register'); $context += array('page_title' => $txt['register'], 'title' => $txt['registration_successful'], 'sub_template' => 'after', 'description' => $modSettings['registration_method'] == 2 ? $txt['approval_after_registration'] : $txt['activate_after_registration']); } else { call_integration_hook('integrate_activate', array($regOptions['username'])); setLoginCookie(60 * $modSettings['cookieTime'], $memberID, hash('sha256', Util::strtolower($regOptions['username']) . $regOptions['password'] . $regOptions['register_vars']['password_salt'])); redirectexit('action=auth;sa=check;member=' . $memberID, $context['server']['needs_login_fix']); } }
/** * 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(); }
public function index($user_id = 0) { $auth = Auth::instance(); // If already logged in redirect to user account page // Otherwise attempt to auto login if autologin cookie can be found // (Set when user previously logged in and ticked 'stay logged in') if ($auth->logged_in() or $auth->auto_login()) { if ($user = Session::instance()->get('auth_user', FALSE) and $auth->logged_in('member')) { url::redirect('members/dashboard'); } } // setup and initialize form field names $form = array('action' => '', 'username' => '', 'password' => '', 'password_again' => '', 'name' => '', 'email' => '', 'resetemail' => ''); // copy the form as errors, so the errors will be stored with keys corresponding to the form field names $errors = $form; $form_error = FALSE; $openid_error = FALSE; $success = FALSE; $action = isset($_POST["action"]) ? $_POST["action"] : ""; // Is this a password reset request? if (isset($_GET["reset"])) { $this->_new_password($user_id, $this->uri->segment(5)); $success = TRUE; } // Regular Form Post for Signin // check, has the form been submitted, if so, setup validation if ($_POST and isset($_POST["action"]) and $_POST["action"] == "signin") { $post = Validation::factory($_POST); $post->pre_filter('trim'); $post->add_rules('username', 'required'); $post->add_rules('password', 'required'); if ($post->validate()) { // Sanitize $_POST data removing all inputs without rules $postdata_array = $post->safe_array(); // Load the user $user = ORM::factory('user', $postdata_array['username']); // If no user with that username found if (!$user->id) { $post->add_error('username', 'login error'); } else { $remember = isset($post->remember) ? TRUE : FALSE; // Attempt a login if ($auth->login($user, $postdata_array['password'], $remember)) { // Exists Redirect to Dashboard url::redirect("members/dashboard"); } else { $post->add_error('password', 'login error'); } } // repopulate the form fields $form = arr::overwrite($form, $post->as_array()); // populate the error fields, if any // We need to already have created an error message file, for Kohana to use // Pass the error message file name to the errors() method $errors = arr::overwrite($errors, $post->errors('auth')); $form_error = TRUE; } else { // repopulate the form fields $form = arr::overwrite($form, $post->as_array()); // populate the error fields, if any // We need to already have created an error message file, for Kohana to use // Pass the error message file name to the errors() method $errors = arr::overwrite($errors, $post->errors('auth')); $form_error = TRUE; } } elseif ($_POST and isset($_POST["action"]) and $_POST["action"] == "new") { $post = Validation::factory($_POST); // Add some filters $post->pre_filter('trim', TRUE); $post->add_rules('username', 'required', 'length[3,16]', 'alpha_numeric'); $post->add_rules('password', 'required', 'length[5,30]', 'alpha_numeric'); $post->add_rules('name', 'required', 'length[3,100]'); $post->add_rules('email', 'required', 'email', 'length[4,64]'); $post->add_callbacks('username', array($this, 'username_exists_chk')); $post->add_callbacks('email', array($this, 'email_exists_chk')); // If Password field is not blank if (!empty($post->password)) { $post->add_rules('password', 'required', 'length[5,16]', 'alpha_numeric', 'matches[password_again]'); } if ($post->validate()) { $user = ORM::factory('user'); $user->name = $post->name; $user->email = $post->email; $user->username = $post->username; $user->password = $post->password; // Add New Roles $user->add(ORM::factory('role', 'login')); $user->add(ORM::factory('role', 'member')); $user->save(); // Send Confirmation email $this->_send_email_confirmation($user); $success = TRUE; $action = ""; } else { // repopulate the form fields $form = arr::overwrite($form, $post->as_array()); // populate the error fields, if any $errors = arr::overwrite($errors, $post->errors('auth')); $form_error = TRUE; } } elseif ($_POST and isset($_POST["action"]) and $_POST["action"] == "forgot") { $post = Validation::factory($_POST); // Add some filters $post->pre_filter('trim', TRUE); $post->add_callbacks('resetemail', array($this, 'email_exists_chk')); if ($post->validate()) { $user = ORM::factory('user', $post->resetemail); // Existing User?? if ($user->loaded == true) { // Secret consists of email and the last_login field. // So as soon as the user logs in again, // the reset link expires automatically. $secret = $auth->hash_password($user->email . $user->last_login); $secret_link = url::site('members/login/index/' . $user->id . '/' . $secret . "?reset"); $details_sent = $this->_email_resetlink($post->resetemail, $user->name, $secret_link); if ($details_sent) { $password_reset = TRUE; } $success = TRUE; $action = ""; } } else { // repopulate the form fields $form = arr::overwrite($form, $post->as_array()); // populate the error fields, if any $errors = arr::overwrite($errors, $post->errors('auth')); $form_error = TRUE; } } // OpenID Post try { $openid = new OpenID(); // Retrieve the Name (if available) and Email $openid->required = array("namePerson", "contact/email"); if (!$openid->mode) { if (isset($_POST["openid_identifier"])) { $openid->identity = $_POST["openid_identifier"]; header("Location: " . $openid->authUrl()); } } elseif ($openid->mode == "cancel") { $openid_error = "You have canceled authentication!"; } else { if ($openid->validate()) { // Does User Exist? $openid_user = ORM::factory("openid")->where("openid", $openid->identity)->find(); if ($openid_user->loaded and $openid_user->user) { // First log all other sessions out $auth->logout(); // Initiate Ushahidi side login + AutoLogin $auth->force_login($openid_user->user->username); // Exists Redirect to Dashboard url::redirect("members/dashboard"); } else { // Does this openid have the required email?? $new_openid = $openid->getAttributes(); if (!isset($new_openid["contact/email"]) or empty($new_openid["contact/email"])) { $openid_error = $openid->identity . " has not been logged in. No Email Address Found."; } else { // Create new User and save OpenID $user = ORM::factory("user"); // But first... does this email address already exist // in the system? if ($user->email_exists($new_openid["contact/email"])) { $openid_error = $new_openid["contact/email"] . " is already registered in our system."; } else { $username = "******" . time(); // Random User Name from TimeStamp - can be changed later $password = text::random("alnum", 16); // Create Random Strong Password // Name Available? $user->name = (isset($new_openid["namePerson"]) and !empty($new_openid["namePerson"])) ? $new_openid["namePerson"] : $username; $user->username = $username; $user->password = $password; $user->email = $new_openid["contact/email"]; // Add New Roles $user->add(ORM::factory('role', 'login')); $user->add(ORM::factory('role', 'member')); $user->save(); // Save OpenID and Association $openid_user->user_id = $user->id; $openid_user->openid = $openid->identity; $openid_user->openid_email = $new_openid["contact/email"]; $openid_user->openid_server = $openid->server; $openid_user->openid_date = date("Y-m-d H:i:s"); $openid_user->save(); // Initiate Ushahidi side login + AutoLogin $auth->login($username, $password, TRUE); // Redirect to Dashboard url::redirect("members/dashboard"); } } } } else { $openid_error = $openid->identity . "has not been logged in."; } } } catch (ErrorException $e) { $openid_error = $e->getMessage(); } $this->template->errors = $errors; $this->template->success = $success; $this->template->form = $form; $this->template->form_error = $form_error; $this->template->openid_error = $openid_error; $this->template->site_name = Kohana::config('settings.site_name'); $this->template->site_tagline = Kohana::config('settings.site_tagline'); // Javascript Header $this->template->js = new View('members/login_js'); $this->template->js->action = $action; }
/** * Changing authentication method? * Only appropriate for people using OpenID. * * @param bool $saving = false */ public function action_authentication($saving = false) { global $context, $cur_profile, $post_errors, $modSettings; $memID = currentMemberID(); loadLanguage('Login'); loadTemplate('ProfileOptions'); // We are saving? if ($saving) { // Moving to password passed authentication? if ($_POST['authenticate'] == 'passwd') { // Didn't enter anything? if ($_POST['passwrd1'] == '') { $post_errors[] = 'no_password'; } elseif (!isset($_POST['passwrd2']) || $_POST['passwrd1'] != $_POST['passwrd2']) { $post_errors[] = 'bad_new_password'; } else { require_once SUBSDIR . '/Auth.subs.php'; $passwordErrors = validatePassword($_POST['passwrd1'], $cur_profile['member_name'], array($cur_profile['real_name'], $cur_profile['email_address'])); // Were there errors? if ($passwordErrors != null) { $post_errors[] = 'password_' . $passwordErrors; } } if (empty($post_errors)) { // Integration? call_integration_hook('integrate_reset_pass', array($cur_profile['member_name'], $cur_profile['member_name'], $_POST['passwrd1'])); // Go then. require_once SUBSDIR . '/Auth.subs.php'; $new_pass = $_POST['passwrd1']; $passwd = validateLoginPassword($new_pass, '', $cur_profile['member_name'], true); // Do the important bits. updateMemberData($memID, array('openid_uri' => '', 'passwd' => $passwd)); if ($context['user']['is_owner']) { setLoginCookie(60 * $modSettings['cookieTime'], $memID, hash('sha256', $new_pass . $cur_profile['password_salt'])); redirectexit('action=profile;area=authentication;updated'); } else { redirectexit('action=profile;u=' . $memID); } } return true; } elseif ($_POST['authenticate'] == 'openid' && !empty($_POST['openid_identifier'])) { require_once SUBSDIR . '/OpenID.subs.php'; require_once SUBSDIR . '/Members.subs.php'; $openID = new OpenID(); $_POST['openid_identifier'] = $openID->canonize($_POST['openid_identifier']); if (memberExists($_POST['openid_identifier'])) { $post_errors[] = 'openid_in_use'; } elseif (empty($post_errors)) { // Authenticate using the new OpenID URI first to make sure they didn't make a mistake. if ($context['user']['is_owner']) { $_SESSION['new_openid_uri'] = $_POST['openid_identifier']; $openID->validate($_POST['openid_identifier'], false, null, 'change_uri'); } else { updateMemberData($memID, array('openid_uri' => $_POST['openid_identifier'])); } } } } // Some stuff. $context['member']['openid_uri'] = $cur_profile['openid_uri']; $context['auth_method'] = empty($cur_profile['openid_uri']) ? 'password' : 'openid'; $context['sub_template'] = 'authentication_method'; loadJavascriptFile('register.js'); }