2007-09-14 05:12:21 +02:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Authenticator for the default "member" method
|
|
|
|
*
|
|
|
|
* @author Markus Lanthaler <markus@silverstripe.com>
|
2012-04-12 08:02:46 +02:00
|
|
|
* @package framework
|
2008-02-25 03:10:37 +01:00
|
|
|
* @subpackage security
|
2007-09-14 05:12:21 +02:00
|
|
|
*/
|
|
|
|
class MemberAuthenticator extends Authenticator {
|
|
|
|
|
2009-11-06 03:23:30 +01:00
|
|
|
/**
|
|
|
|
* @var Array Contains encryption algorithm identifiers.
|
|
|
|
* If set, will migrate to new precision-safe password hashing
|
|
|
|
* upon login. See http://open.silverstripe.org/ticket/3004.
|
|
|
|
*/
|
|
|
|
static $migrate_legacy_hashes = array(
|
|
|
|
'md5' => 'md5_v2.4',
|
|
|
|
'sha1' => 'sha1_v2.4'
|
|
|
|
);
|
|
|
|
|
2007-09-14 05:12:21 +02:00
|
|
|
/**
|
|
|
|
* Method to authenticate an user
|
|
|
|
*
|
|
|
|
* @param array $RAW_data Raw data to authenticate the user
|
2007-09-14 21:10:18 +02:00
|
|
|
* @param Form $form Optional: If passed, better error messages can be
|
|
|
|
* produced by using
|
|
|
|
* {@link Form::sessionMessage()}
|
2007-09-14 05:12:21 +02:00
|
|
|
* @return bool|Member Returns FALSE if authentication fails, otherwise
|
|
|
|
* the member object
|
2007-10-03 00:18:45 +02:00
|
|
|
* @see Security::setDefaultAdmin()
|
2007-09-14 05:12:21 +02:00
|
|
|
*/
|
2008-04-26 08:51:52 +02:00
|
|
|
public static function authenticate($RAW_data, Form $form = null) {
|
2011-10-27 22:38:11 +02:00
|
|
|
if(array_key_exists('Email', $RAW_data) && $RAW_data['Email']){
|
|
|
|
$SQL_user = Convert::raw2sql($RAW_data['Email']);
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-04-26 08:32:05 +02:00
|
|
|
$isLockedOut = false;
|
2010-02-05 01:36:25 +01:00
|
|
|
$result = null;
|
2007-09-14 05:12:21 +02:00
|
|
|
|
2007-10-03 00:18:45 +02:00
|
|
|
// Default login (see Security::setDefaultAdmin())
|
2007-09-27 23:13:59 +02:00
|
|
|
if(Security::check_default_admin($RAW_data['Email'], $RAW_data['Password'])) {
|
2007-09-16 19:39:41 +02:00
|
|
|
$member = Security::findAnAdministrator();
|
|
|
|
} else {
|
2009-11-06 03:23:30 +01:00
|
|
|
$member = DataObject::get_one(
|
|
|
|
"Member",
|
2010-04-12 07:00:05 +02:00
|
|
|
"\"" . Member::get_unique_identifier_field() . "\" = '$SQL_user' AND \"Password\" IS NOT NULL"
|
2009-11-06 03:23:30 +01:00
|
|
|
);
|
2010-10-13 03:35:19 +02:00
|
|
|
|
|
|
|
if($member) {
|
|
|
|
$result = $member->checkPassword($RAW_data['Password']);
|
|
|
|
} else {
|
|
|
|
$result = new ValidationResult(false, _t('Member.ERRORWRONGCRED'));
|
|
|
|
}
|
2010-02-05 01:36:25 +01:00
|
|
|
|
|
|
|
if($member && !$result->valid()) {
|
2008-04-26 08:32:05 +02:00
|
|
|
$member->registerFailedLogin();
|
2009-06-28 04:48:33 +02:00
|
|
|
$member = false;
|
2007-10-03 00:18:45 +02:00
|
|
|
}
|
2007-09-16 19:39:41 +02:00
|
|
|
}
|
2008-08-11 02:14:48 +02:00
|
|
|
|
|
|
|
// Optionally record every login attempt as a {@link LoginAttempt} object
|
2008-08-12 22:59:32 +02:00
|
|
|
/**
|
|
|
|
* TODO We could handle this with an extension
|
|
|
|
*/
|
2008-08-11 02:14:48 +02:00
|
|
|
if(Security::login_recording()) {
|
|
|
|
$attempt = new LoginAttempt();
|
|
|
|
if($member) {
|
|
|
|
// successful login (member is existing with matching password)
|
|
|
|
$attempt->MemberID = $member->ID;
|
|
|
|
$attempt->Status = 'Success';
|
2008-08-12 22:59:32 +02:00
|
|
|
|
|
|
|
// Audit logging hook
|
|
|
|
$member->extend('authenticated');
|
2008-08-11 02:14:48 +02:00
|
|
|
} else {
|
|
|
|
// failed login - we're trying to see if a user exists with this email (disregarding wrong passwords)
|
2012-09-26 23:34:00 +02:00
|
|
|
$existingMember = DataObject::get_one(
|
|
|
|
"Member",
|
|
|
|
"\"" . Member::get_unique_identifier_field() . "\" = '$SQL_user'"
|
|
|
|
);
|
2008-08-12 22:59:32 +02:00
|
|
|
if($existingMember) {
|
|
|
|
$attempt->MemberID = $existingMember->ID;
|
|
|
|
|
|
|
|
// Audit logging hook
|
|
|
|
$existingMember->extend('authenticationFailed');
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// Audit logging hook
|
2008-08-13 03:48:54 +02:00
|
|
|
singleton('Member')->extend('authenticationFailedUnknownUser', $RAW_data);
|
2008-08-12 22:59:32 +02:00
|
|
|
}
|
2008-08-11 02:14:48 +02:00
|
|
|
$attempt->Status = 'Failure';
|
|
|
|
}
|
2008-08-11 05:39:14 +02:00
|
|
|
if(is_array($RAW_data['Email'])) {
|
|
|
|
user_error("Bad email passed to MemberAuthenticator::authenticate(): $RAW_data[Email]", E_USER_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-08-11 02:14:48 +02:00
|
|
|
$attempt->Email = $RAW_data['Email'];
|
2008-08-11 02:21:44 +02:00
|
|
|
$attempt->IP = Controller::curr()->getRequest()->getIP();
|
2008-08-11 02:14:48 +02:00
|
|
|
$attempt->write();
|
|
|
|
}
|
2009-11-06 03:23:30 +01:00
|
|
|
|
|
|
|
// 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 // only migrate after successful login
|
|
|
|
&& 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();
|
|
|
|
}
|
2007-09-14 05:12:21 +02:00
|
|
|
|
2010-02-05 01:36:25 +01:00
|
|
|
if($member) {
|
|
|
|
Session::clear('BackURL');
|
|
|
|
} else {
|
|
|
|
if($form && $result) $form->sessionMessage($result->message(), 'bad');
|
|
|
|
}
|
2007-09-14 05:12:21 +02:00
|
|
|
|
2010-02-05 01:36:25 +01:00
|
|
|
return $member;
|
|
|
|
}
|
2007-09-14 05:12:21 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Method that creates the login form for this authentication method
|
|
|
|
*
|
2007-09-14 21:10:18 +02:00
|
|
|
* @param Controller The parent controller, necessary to create the
|
|
|
|
* appropriate form action tag
|
2007-09-14 05:12:21 +02:00
|
|
|
* @return Form Returns the login form to use with this authentication
|
|
|
|
* method
|
|
|
|
*/
|
2007-09-16 02:44:30 +02:00
|
|
|
public static function get_login_form(Controller $controller) {
|
2007-09-14 21:10:18 +02:00
|
|
|
return Object::create("MemberLoginForm", $controller, "LoginForm");
|
2007-09-14 05:12:21 +02:00
|
|
|
}
|
2007-09-14 21:13:12 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the name of the authentication method
|
|
|
|
*
|
|
|
|
* @return string Returns the name of the authentication method.
|
|
|
|
*/
|
2007-09-16 02:44:30 +02:00
|
|
|
public static function get_name() {
|
2007-10-25 04:47:45 +02:00
|
|
|
return _t('MemberAuthenticator.TITLE', "E-mail & Password");
|
2007-09-14 21:13:12 +02:00
|
|
|
}
|
2007-09-14 05:12:21 +02:00
|
|
|
}
|
|
|
|
|