2017-03-02 03:24:38 +01:00
|
|
|
<?php
|
|
|
|
|
2017-04-22 06:30:10 +02:00
|
|
|
namespace SilverStripe\Security\MemberAuthenticator;
|
2017-03-02 03:24:38 +01:00
|
|
|
|
|
|
|
use SilverStripe\Control\Controller;
|
2017-05-20 06:32:25 +02:00
|
|
|
use SilverStripe\Control\HTTPRequest;
|
2017-03-02 03:24:38 +01:00
|
|
|
use SilverStripe\Control\HTTPResponse;
|
|
|
|
use SilverStripe\Control\Session;
|
2017-04-22 06:30:10 +02:00
|
|
|
use SilverStripe\Control\RequestHandler;
|
2017-03-02 03:24:38 +01:00
|
|
|
use SilverStripe\ORM\ValidationResult;
|
2017-05-30 09:42:00 +02:00
|
|
|
use SilverStripe\Security\Authenticator;
|
2017-04-22 06:30:10 +02:00
|
|
|
use SilverStripe\Security\Security;
|
|
|
|
use SilverStripe\Security\Member;
|
2017-05-07 21:11:00 +02:00
|
|
|
use SilverStripe\Core\Injector\Injector;
|
|
|
|
use SilverStripe\Security\IdentityStore;
|
2017-03-02 03:24:38 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle login requests from MemberLoginForm
|
|
|
|
*/
|
2017-04-22 06:30:10 +02:00
|
|
|
class LoginHandler extends RequestHandler
|
2017-03-02 03:24:38 +01:00
|
|
|
{
|
2017-05-20 06:32:25 +02:00
|
|
|
/**
|
|
|
|
* @var Authenticator
|
|
|
|
*/
|
2017-04-22 06:30:10 +02:00
|
|
|
protected $authenticator;
|
|
|
|
|
2017-05-30 09:42:00 +02:00
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
2017-04-22 06:30:10 +02:00
|
|
|
private static $url_handlers = [
|
|
|
|
'' => 'login',
|
|
|
|
];
|
2017-03-02 03:24:38 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
* @config
|
|
|
|
*/
|
|
|
|
private static $allowed_actions = [
|
2017-04-22 06:30:10 +02:00
|
|
|
'login',
|
|
|
|
'LoginForm',
|
2017-03-02 03:24:38 +01:00
|
|
|
'logout',
|
|
|
|
];
|
|
|
|
|
2017-05-30 09:42:00 +02:00
|
|
|
/**
|
|
|
|
* @var string Called link on this handler
|
|
|
|
*/
|
2017-05-20 06:32:25 +02:00
|
|
|
private $link;
|
2017-04-22 06:30:10 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $link The URL to recreate this request handler
|
2017-05-30 09:42:00 +02:00
|
|
|
* @param MemberAuthenticator $authenticator The authenticator to use
|
2017-04-22 06:30:10 +02:00
|
|
|
*/
|
2017-05-30 09:42:00 +02:00
|
|
|
public function __construct($link, MemberAuthenticator $authenticator)
|
2017-04-22 06:30:10 +02:00
|
|
|
{
|
|
|
|
$this->link = $link;
|
|
|
|
$this->authenticator = $authenticator;
|
2017-05-30 09:42:00 +02:00
|
|
|
parent::__construct();
|
2017-04-22 06:30:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a link to this request handler.
|
|
|
|
* The link returned is supplied in the constructor
|
2017-05-30 09:42:00 +02:00
|
|
|
* @param null|string $action
|
2017-04-22 06:30:10 +02:00
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function link($action = null)
|
|
|
|
{
|
|
|
|
if ($action) {
|
|
|
|
return Controller::join_links($this->link, $action);
|
|
|
|
}
|
2017-05-20 06:32:25 +02:00
|
|
|
|
|
|
|
return $this->link;
|
2017-04-22 06:30:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* URL handler for the log-in screen
|
2017-05-30 09:42:00 +02:00
|
|
|
*
|
|
|
|
* @return array
|
2017-04-22 06:30:10 +02:00
|
|
|
*/
|
|
|
|
public function login()
|
|
|
|
{
|
|
|
|
return [
|
|
|
|
'Form' => $this->loginForm(),
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the MemberLoginForm form
|
2017-05-30 09:42:00 +02:00
|
|
|
*
|
|
|
|
* @return MemberLoginForm
|
2017-04-22 06:30:10 +02:00
|
|
|
*/
|
|
|
|
public function loginForm()
|
|
|
|
{
|
2017-05-30 09:42:00 +02:00
|
|
|
return MemberLoginForm::create(
|
2017-04-22 06:30:10 +02:00
|
|
|
$this,
|
|
|
|
get_class($this->authenticator),
|
|
|
|
'LoginForm'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-03-02 03:24:38 +01:00
|
|
|
/**
|
|
|
|
* Login form handler method
|
|
|
|
*
|
2017-05-20 06:32:25 +02:00
|
|
|
* This method is called when the user finishes the login flow
|
2017-03-02 03:24:38 +01:00
|
|
|
*
|
|
|
|
* @param array $data Submitted data
|
2017-05-30 09:42:00 +02:00
|
|
|
* @param MemberLoginForm $form
|
2017-03-02 03:24:38 +01:00
|
|
|
* @return HTTPResponse
|
|
|
|
*/
|
2017-04-23 05:30:33 +02:00
|
|
|
public function doLogin($data, $form)
|
2017-03-02 03:24:38 +01:00
|
|
|
{
|
2017-04-23 05:30:33 +02:00
|
|
|
$failureMessage = null;
|
|
|
|
|
2017-05-30 09:42:00 +02:00
|
|
|
$this->extend('beforeLogin');
|
2017-04-23 05:30:33 +02:00
|
|
|
// Successful login
|
2017-05-30 09:42:00 +02:00
|
|
|
if ($member = $this->checkLogin($data, $result)) {
|
2017-05-07 21:11:00 +02:00
|
|
|
$this->performLogin($member, $data, $form->getRequestHandler()->getRequest());
|
2017-05-30 09:42:00 +02:00
|
|
|
// Allow operations on the member after successful login
|
|
|
|
$this->extend('afterLogin', $member);
|
2017-05-20 06:32:25 +02:00
|
|
|
|
2017-04-23 05:30:33 +02:00
|
|
|
return $this->redirectAfterSuccessfulLogin();
|
2017-03-02 03:24:38 +01:00
|
|
|
}
|
|
|
|
|
2017-05-30 09:42:00 +02:00
|
|
|
$this->extend('failedLogin');
|
|
|
|
|
|
|
|
$message = implode("; ", array_map(
|
|
|
|
function ($message) {
|
|
|
|
return $message['message'];
|
|
|
|
},
|
|
|
|
$result->getMessages()
|
|
|
|
));
|
|
|
|
|
|
|
|
$form->sessionMessage($message, 'bad');
|
2017-04-23 05:30:33 +02:00
|
|
|
|
|
|
|
// Failed login
|
|
|
|
|
2017-03-02 03:24:38 +01:00
|
|
|
/** @skipUpgrade */
|
|
|
|
if (array_key_exists('Email', $data)) {
|
2017-05-30 09:42:00 +02:00
|
|
|
$rememberMe = (isset($data['Remember']) && Security::config()->get('autologin_enabled') === true);
|
2017-03-02 03:24:38 +01:00
|
|
|
Session::set('SessionForms.MemberLoginForm.Email', $data['Email']);
|
2017-05-30 09:42:00 +02:00
|
|
|
Session::set('SessionForms.MemberLoginForm.Remember', $rememberMe);
|
2017-03-02 03:24:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fail to login redirects back to form
|
2017-04-23 05:30:33 +02:00
|
|
|
return $form->getRequestHandler()->redirectBackToForm();
|
2017-03-02 03:24:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function getReturnReferer()
|
|
|
|
{
|
2017-04-22 06:30:10 +02:00
|
|
|
return $this->link();
|
2017-03-02 03:24:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Login in the user and figure out where to redirect the browser.
|
|
|
|
*
|
|
|
|
* The $data has this format
|
|
|
|
* array(
|
|
|
|
* 'AuthenticationMethod' => 'MemberAuthenticator',
|
|
|
|
* 'Email' => 'sam@silverstripe.com',
|
|
|
|
* 'Password' => '1nitialPassword',
|
|
|
|
* 'BackURL' => 'test/link',
|
|
|
|
* [Optional: 'Remember' => 1 ]
|
|
|
|
* )
|
|
|
|
*
|
|
|
|
* @return HTTPResponse
|
|
|
|
*/
|
2017-04-23 05:30:33 +02:00
|
|
|
protected function redirectAfterSuccessfulLogin()
|
2017-03-02 03:24:38 +01:00
|
|
|
{
|
|
|
|
Session::clear('SessionForms.MemberLoginForm.Email');
|
|
|
|
Session::clear('SessionForms.MemberLoginForm.Remember');
|
|
|
|
|
2017-05-20 06:32:25 +02:00
|
|
|
$member = Security::getCurrentUser();
|
2017-03-02 03:24:38 +01:00
|
|
|
if ($member->isPasswordExpired()) {
|
|
|
|
return $this->redirectToChangePassword();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Absolute redirection URLs may cause spoofing
|
|
|
|
$backURL = $this->getBackURL();
|
|
|
|
if ($backURL) {
|
|
|
|
return $this->redirect($backURL);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If a default login dest has been set, redirect to that.
|
|
|
|
$defaultLoginDest = Security::config()->get('default_login_dest');
|
|
|
|
if ($defaultLoginDest) {
|
|
|
|
return $this->redirect($defaultLoginDest);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Redirect the user to the page where they came from
|
|
|
|
if ($member) {
|
|
|
|
// Welcome message
|
|
|
|
$message = _t(
|
2017-04-20 03:15:24 +02:00
|
|
|
'SilverStripe\\Security\\Member.WELCOMEBACK',
|
2017-05-20 06:32:25 +02:00
|
|
|
'Welcome Back, {firstname}',
|
2017-03-02 03:24:38 +01:00
|
|
|
['firstname' => $member->FirstName]
|
|
|
|
);
|
2017-05-30 09:42:00 +02:00
|
|
|
Security::singleton()->setLoginMessage($message, ValidationResult::TYPE_GOOD);
|
2017-03-02 03:24:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Redirect back
|
|
|
|
return $this->redirectBack();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Try to authenticate the user
|
|
|
|
*
|
|
|
|
* @param array $data Submitted data
|
2017-05-30 09:42:00 +02:00
|
|
|
* @param ValidationResult $result
|
2017-03-02 03:24:38 +01:00
|
|
|
* @return Member Returns the member object on successful authentication
|
|
|
|
* or NULL on failure.
|
|
|
|
*/
|
2017-05-30 09:42:00 +02:00
|
|
|
public function checkLogin($data, &$result)
|
2017-03-02 03:24:38 +01:00
|
|
|
{
|
2017-05-30 09:42:00 +02:00
|
|
|
$member = $this->authenticator->authenticate($data, $result);
|
|
|
|
if ($member instanceof Member) {
|
2017-03-02 03:24:38 +01:00
|
|
|
return $member;
|
2017-04-23 05:30:33 +02:00
|
|
|
}
|
2017-05-20 06:32:25 +02:00
|
|
|
|
|
|
|
return null;
|
2017-03-02 03:24:38 +01:00
|
|
|
}
|
|
|
|
|
2017-04-23 05:30:33 +02:00
|
|
|
/**
|
|
|
|
* Try to authenticate the user
|
|
|
|
*
|
2017-05-20 06:32:25 +02:00
|
|
|
* @param Member $member
|
2017-04-23 05:30:33 +02:00
|
|
|
* @param array $data Submitted data
|
2017-05-20 06:32:25 +02:00
|
|
|
* @param HTTPRequest $request
|
2017-04-23 05:30:33 +02:00
|
|
|
* @return Member Returns the member object on successful authentication
|
|
|
|
* or NULL on failure.
|
|
|
|
*/
|
2017-05-07 21:11:00 +02:00
|
|
|
public function performLogin($member, $data, $request)
|
2017-04-23 05:30:33 +02:00
|
|
|
{
|
2017-05-30 09:42:00 +02:00
|
|
|
/** IdentityStore */
|
|
|
|
$rememberMe = (isset($data['Remember']) && Security::config()->get('autologin_enabled'));
|
|
|
|
Injector::inst()->get(IdentityStore::class)->logIn($member, $rememberMe, $request);
|
2017-05-20 06:32:25 +02:00
|
|
|
|
2017-04-23 05:30:33 +02:00
|
|
|
return $member;
|
|
|
|
}
|
2017-05-20 06:32:25 +02:00
|
|
|
|
2017-03-02 03:24:38 +01:00
|
|
|
/**
|
|
|
|
* Invoked if password is expired and must be changed
|
|
|
|
*
|
|
|
|
* @skipUpgrade
|
|
|
|
* @return HTTPResponse
|
|
|
|
*/
|
|
|
|
protected function redirectToChangePassword()
|
|
|
|
{
|
2017-04-22 06:30:10 +02:00
|
|
|
$cp = ChangePasswordForm::create($this, 'ChangePasswordForm');
|
2017-03-02 03:24:38 +01:00
|
|
|
$cp->sessionMessage(
|
2017-05-08 13:34:39 +02:00
|
|
|
_t('SilverStripe\\Security\\Member.PASSWORDEXPIRED', 'Your password has expired. Please choose a new one.'),
|
2017-03-02 03:24:38 +01:00
|
|
|
'good'
|
|
|
|
);
|
|
|
|
$changedPasswordLink = Security::singleton()->Link('changepassword');
|
2017-05-20 06:32:25 +02:00
|
|
|
|
2017-03-02 03:24:38 +01:00
|
|
|
return $this->redirect($this->addBackURLParam($changedPasswordLink));
|
|
|
|
}
|
|
|
|
}
|