/** * Tries to logon using the credentials in the SilverStripe database * * @access public * * @param string $source Authentication source to be used * @param string $external_uid The ID entered * @param string $external_passwd The password of the user * * @return boolean True if the authentication was a success, false * otherwise */ public function Authenticate($RAW_source, $RAW_external_uid, $RAW_external_passwd) { $SQL_identity = Convert::raw2sql($RAW_external_uid); // Default login (see Security::setDefaultAdmin()) if (Security::check_default_admin($RAW_external_uid, $RAW_external_passwd)) { ExternalAuthenticator::AuthLog($RAW_external_uid . '.sstripe - Logging on with an Administrator account'); $member = Security::findAnAdministrator(); } else { $SQL_source = Convert::raw2sql($RAW_source); ExternalAuthenticator::AuthLog($RAW_external_uid . '.sstripe - Searching for user with source ' . $SQL_source . ' in database'); $member = DataObject::get_one("Member", "\"Member\".\"External_UserID\" = '{$SQL_identity}'" . " AND \"Member\".\"External_SourceID\" = '{$SQL_source}'" . " AND \"Password\" IS NOT NULL"); if ($member) { ExternalAuthenticator::AuthLog($RAW_external_uid . '.sstripe - User was found in database'); if ($member->checkPassword($RAW_external_passwd) == false) { ExternalAuthenticator::AuthLog($RAW_external_uid . '.sstripe - Password authentication failed'); $member = null; } else { ExternalAuthenticator::AuthLog($RAW_external_uid . '.sstripe - Password authentication succeeded'); } } else { ExternalAuthenticator::AuthLog($RAW_external_uid . '.sstripe - User was NOT found in database'); } } if ($member) { return true; } else { ExternalAuthenticator::setAuthMessage(_t('ExternalAuthenticator.Failed')); return false; } }
public function testCheckDefaultAdmin() { $this->assertTrue(Security::has_default_admin()); $this->assertTrue(Security::check_default_admin('admin', 'password'), 'Succeeds with correct username and password'); $this->assertFalse(Security::check_default_admin('wronguser', 'password'), 'Fails with incorrect username'); $this->assertFalse(Security::check_default_admin('admin', 'wrongpassword'), 'Fails with incorrect password'); }
/** * Attempt to find and authenticate member if possible from the given data. * * @param array $data * @param Form $form * @param bool &$success Success flag * @return Member Found member, regardless of successful login * @see MemberAuthenticator::authenticate_member() */ protected static function authenticate_member($data, $form, &$success) { // Default success to false $success = false; // Attempt to identify by temporary ID $member = null; $email = null; if (!empty($data['tempid'])) { // Find user by tempid, in case they are re-validating an existing session $member = Member::member_from_tempid($data['tempid']); if ($member) { $email = $member->Email; } } // Otherwise, get email from posted value instead if (!$member && !empty($data['Email'])) { $email = $data['Email']; } // Check default login (see Security::setDefaultAdmin()) the standard way and the "extension"-way :-) $asDefaultAdmin = $email === Security::default_admin_username(); if ($asDefaultAdmin || isset($GLOBALS['_DEFAULT_ADMINS']) && array_key_exists($email, $GLOBALS['_DEFAULT_ADMINS'])) { // If logging is as default admin, ensure record is setup correctly $member = Member::default_admin(); $success = Security::check_default_admin($email, $data['Password']); // If not already true check if one of the extra admins match if (!$success) { $success = $GLOBALS['_DEFAULT_ADMINS'][$email] == $data['Password']; } if ($success) { return $member; } } // Attempt to identify user by email if (!$member && $email) { // Find user by email $member = Member::get()->filter(Member::config()->unique_identifier_field, $email)->first(); } // Validate against member if possible if ($member && !$asDefaultAdmin) { $result = $member->checkPassword($data['Password']); $success = $result->valid(); } else { $result = new ValidationResult(false, _t('Member.ERRORWRONGCRED')); } // Emit failure to member and form (if available) if (!$success) { if ($member) { $member->registerFailedLogin(); } if ($form) { $form->sessionMessage($result->message(), 'bad'); } } else { if ($member) { $member->registerSuccessfulLogin(); } } return $member; }
public function testCheckDefaultAdmin() { if (Security::has_default_admin()) { $this->markTestSkipped('Default admin present. There\'s no way to inspect default admin state, ' . 'so we don\'t override existing settings'); } Security::setDefaultAdmin('admin', 'password'); $this->assertTrue(Security::has_default_admin()); $this->assertTrue(Security::check_default_admin('admin', 'password'), 'Succeeds with correct username and password'); $this->assertFalse(Security::check_default_admin('wronguser', 'password'), 'Fails with incorrect username'); $this->assertFalse(Security::check_default_admin('admin', 'wrongpassword'), 'Fails with incorrect password'); Security::setDefaultAdmin(null, null); }
function testCheckDefaultAdmin() { // TODO There's currently no way to inspect default admin state, // hence we don't override existing settings if (Security::has_default_admin()) { return; } Security::setDefaultAdmin('admin', 'password'); $this->assertTrue(Security::has_default_admin()); $this->assertTrue(Security::check_default_admin('admin', 'password'), 'Succeeds with correct username and password'); $this->assertFalse(Security::check_default_admin('wronguser', 'password'), 'Fails with incorrect username'); $this->assertFalse(Security::check_default_admin('admin', 'wrongpassword'), 'Fails with incorrect password'); Security::setDefaultAdmin(null, null); }
/** * Method to authenticate an user * * @param array $RAW_data Raw data to authenticate the user * @param Form $form Optional: If passed, better error messages can be * produced by using * {@link Form::sessionMessage()} * @return bool|Member Returns FALSE if authentication fails, otherwise * the member object * @see Security::setDefaultAdmin() */ public static function authenticate($RAW_data, Form $form = null) { $SQL_user = Convert::raw2sql($RAW_data['Email']); // Default login (see Security::setDefaultAdmin()) if (Security::check_default_admin($RAW_data['Email'], $RAW_data['Password'])) { $member = Security::findAnAdministrator(); } else { $member = DataObject::get_one("Member", "Email = '{$SQL_user}' AND Password IS NOT NULL"); if ($member && $member->checkPassword($RAW_data['Password']) == false) { $member = null; } } if ($member) { Session::clear("BackURL"); } else { if (!is_null($form)) { $form->sessionMessage(_t('Member.ERRORWRONGCRED', "That doesn't seem to be the right e-mail address or password. Please try again."), "bad"); } } return $member; }
/** * Method to authenticate an user * * @param array $RAW_data Raw data to authenticate the user * @param Form $form Optional: If passed, better error messages can be * produced by using * {@link Form::sessionMessage()} * @return bool|Member Returns FALSE if authentication fails, otherwise * the member object * @see Security::setDefaultAdmin() */ public static function authenticate($RAW_data, Form $form = null) { if (array_key_exists('Email', $RAW_data) && $RAW_data['Email']) { $SQL_user = Convert::raw2sql($RAW_data['Email']); } else { return false; } $isLockedOut = false; $result = null; // Default login (see Security::setDefaultAdmin()) if (Security::check_default_admin($RAW_data['Email'], $RAW_data['Password'])) { $member = Security::findAnAdministrator(); } else { $member = DataObject::get_one("Member", "\"" . Member::get_unique_identifier_field() . "\" = '{$SQL_user}' AND \"Password\" IS NOT NULL"); if ($member) { $result = $member->checkPassword($RAW_data['Password']); } else { $result = new ValidationResult(false, _t('Member.ERRORWRONGCRED')); } if ($member && !$result->valid()) { $member->registerFailedLogin(); $member = false; } } // Optionally record every login attempt as a {@link LoginAttempt} object /** * TODO We could handle this with an extension */ if (Security::login_recording()) { $attempt = new LoginAttempt(); if ($member) { // successful login (member is existing with matching password) $attempt->MemberID = $member->ID; $attempt->Status = 'Success'; // Audit logging hook $member->extend('authenticated'); } else { // failed login - we're trying to see if a user exists with this email (disregarding wrong passwords) $existingMember = DataObject::get_one("Member", "\"" . Member::get_unique_identifier_field() . "\" = '{$SQL_user}'"); if ($existingMember) { $attempt->MemberID = $existingMember->ID; // Audit logging hook $existingMember->extend('authenticationFailed'); } else { // Audit logging hook singleton('Member')->extend('authenticationFailedUnknownUser', $RAW_data); } $attempt->Status = 'Failure'; } if (is_array($RAW_data['Email'])) { user_error("Bad email passed to MemberAuthenticator::authenticate(): {$RAW_data['Email']}", E_USER_WARNING); return false; } $attempt->Email = $RAW_data['Email']; $attempt->IP = Controller::curr()->getRequest()->getIP(); $attempt->write(); } // Legacy migration to precision-safe password hashes. // A login-event with cleartext passwords is the only time // when we can rehash passwords to a different hashing algorithm, // bulk-migration doesn't work due to the nature of hashing. // See PasswordEncryptor_LegacyPHPHash class. if ($member && self::$migrate_legacy_hashes && array_key_exists($member->PasswordEncryption, self::$migrate_legacy_hashes)) { $member->Password = $RAW_data['Password']; $member->PasswordEncryption = self::$migrate_legacy_hashes[$member->PasswordEncryption]; $member->write(); } if ($member) { Session::clear('BackURL'); } else { if ($form && $result) { $form->sessionMessage($result->message(), 'bad'); } } return $member; }
/** * Check if the passed password matches the stored one (if the member is not locked out). * * @param string $password * @return ValidationResult */ public function checkPassword($password) { $result = $this->canLogIn(); // Short-circuit the result upon failure, no further checks needed. if (!$result->valid()) { return $result; } // Allow default admin to login as self if ($this->isDefaultAdmin() && Security::check_default_admin($this->Email, $password)) { return $result; } // Check a password is set on this member if (empty($this->Password) && $this->exists()) { $result->error(_t('Member.NoPassword', 'There is no password on this member.')); return $result; } $e = PasswordEncryptor::create_for_algorithm($this->PasswordEncryption); if (!$e->check($this->Password, $password, $this->Salt, $this)) { $result->error(_t('Member.ERRORWRONGCRED', 'The provided details don\'t seem to be correct. Please try again.')); } return $result; }
/** * Method to authenticate an user * * @param array $RAW_data Raw data to authenticate the user * @param Form $form Optional: If passed, better error messages can be * produced by using * {@link Form::sessionMessage()} * @return bool|Member Returns FALSE if authentication fails, otherwise * the member object * @see Security::setDefaultAdmin() */ public static function authenticate($RAW_data, Form $form = null) { $SQL_user = Convert::raw2sql($RAW_data['Email']); $isLockedOut = false; // Default login (see Security::setDefaultAdmin()) if (Security::check_default_admin($RAW_data['Email'], $RAW_data['Password'])) { $member = Security::findAnAdministrator(); } else { $member = DataObject::get_one("Member", "Email = '{$SQL_user}' AND Password IS NOT NULL"); if ($member && $member->checkPassword($RAW_data['Password']) == false) { if ($member->isLockedOut()) { $isLockedOut = true; } $member->registerFailedLogin(); $member = null; } } // Optionally record every login attempt as a {@link LoginAttempt} object /** * TODO We could handle this with an extension */ if (Security::login_recording()) { $attempt = new LoginAttempt(); if ($member) { // successful login (member is existing with matching password) $attempt->MemberID = $member->ID; $attempt->Status = 'Success'; // Audit logging hook $member->extend('authenticated'); } else { // failed login - we're trying to see if a user exists with this email (disregarding wrong passwords) $existingMember = DataObject::get_one("Member", "Email = '{$SQL_user}'"); if ($existingMember) { $attempt->MemberID = $existingMember->ID; // Audit logging hook $existingMember->extend('authenticationFailed'); } else { // Audit logging hook singleton('Member')->extend('authenticationFailedUnknownUser', $RAW_data); } $attempt->Status = 'Failure'; } if (is_array($RAW_data['Email'])) { user_error("Bad email passed to MemberAuthenticator::authenticate(): {$RAW_data['Email']}", E_USER_WARNING); return false; } $attempt->Email = $RAW_data['Email']; $attempt->IP = Controller::curr()->getRequest()->getIP(); $attempt->write(); } if ($member) { Session::clear("BackURL"); } else { if ($isLockedOut) { if ($form) { $form->sessionMessage(_t('Member.ERRORLOCKEDOUT', "Your account has been temporarily disabled because of too many failed attempts at logging in. Please try again in 20 minutes."), "bad"); } } else { if ($form) { $form->sessionMessage(_t('Member.ERRORWRONGCRED', "That doesn't seem to be the right e-mail address or password. Please try again."), "bad"); } } } return $member; }