2007-09-14 05:12:21 +02:00
< ? php
/**
* Authenticator for the default " member " method
*
* @ author Markus Lanthaler < markus @ silverstripe . com >
2008-02-25 03:10:37 +01:00
* @ package sapphire
* @ subpackage security
2007-09-14 05:12:21 +02:00
*/
class MemberAuthenticator extends Authenticator {
2009-11-14 01:42:18 +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 ) {
2007-09-14 05:12:21 +02:00
$SQL_user = Convert :: raw2sql ( $RAW_data [ 'Email' ]);
2008-04-26 08:32:05 +02:00
$isLockedOut = false ;
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-14 01:42:18 +01:00
$member = DataObject :: get_one (
" Member " ,
" \" Email \" = ' $SQL_user ' AND \" Password \" IS NOT NULL "
);
2008-04-26 08:32:05 +02:00
if ( $member && ( $member -> checkPassword ( $RAW_data [ 'Password' ]) == false )) {
if ( $member -> isLockedOut ()) $isLockedOut = true ;
$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)
2008-11-24 10:31:14 +01:00
$existingMember = DataObject :: get_one ( " Member " , " \" Email \" = ' $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-14 01:42:18 +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
if ( $member ) {
2007-10-25 04:47:45 +02:00
Session :: clear ( " BackURL " );
2008-04-26 08:32:05 +02:00
} 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 (
2007-10-25 04:47:45 +02:00
_t ( 'Member.ERRORWRONGCRED' , " That doesn't seem to be the right e-mail address or password. Please try again. " ),
" bad "
);
2008-04-26 08:32:05 +02:00
}
2007-09-14 05:12:21 +02:00
return $member ;
}
/**
* 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
}
?>