Version: current

      1 <?php
      2 /**
      3  * Log-in form for the "member" authentication method
      4  * @package sapphire
      5  * @subpackage security
      6  */
      7 class MemberLoginForm extends LoginForm {
      8
      9     protected $authenticator_class = 'MemberAuthenticator';
     10
     11     /**
     12      * Constructor
     13      *
     14      * @param Controller $controller The parent controller, necessary to
     15      *                               create the appropriate form action tag.
     16      * @param string $name The method on the controller that will return this
     17      *                     form object.
     18      * @param FieldSet|FormField $fields All of the fields in the form - a
     19      *                                   {@link FieldSet} of {@link FormField}
     20      *                                   objects.
     21      * @param FieldSet|FormAction $actions All of the action buttons in the
     22      *                                     form - a {@link FieldSet} of
     23      *                                     {@link FormAction} objects
     24      * @param bool $checkCurrentUser If set to TRUE, it will be checked if a
     25      *                               the user is currently logged in, and if
     26      *                               so, only a logout button will be rendered
     27      * @param string $authenticatorClassName Name of the authenticator class that this form uses.
     28      */
     29     function __construct($controller, $name, $fields = null, $actions = null,
     30                                              $checkCurrentUser = true) {
     31
     32         // This is now set on the class directly to make it easier to create subclasses
     33         // $this->authenticator_class = $authenticatorClassName;
     34
     35         $customCSS = project() . '/css/member_login.css';
     36         if(Director::fileExists($customCSS)) {
     37             Requirements::css($customCSS);
     38         }
     39
     40         if(isset($_REQUEST['BackURL'])) {
     41             $backURL = $_REQUEST['BackURL'];
     42         } else {
     43             $backURL = Session::get('BackURL');
     44             Session::clear('BackURL');
     45         }
     46
     47         if($checkCurrentUser && Member::currentUser() && Member::logged_in_session_exists()) {
     48             $fields = new FieldSet(
     49                 new HiddenField("AuthenticationMethod", null, $this->authenticator_class, $this)
     50             );
     51             $actions = new FieldSet(
     52                 new FormAction("logout", _t('Member.BUTTONLOGINOTHER', "Log in as someone else"))
     53             );
     54         } else {
     55             if(!$fields) {
     56                 $label=singleton('Member')->fieldLabel(Member::get_unique_identifier_field());
     57                 $fields = new FieldSet(
     58                     new HiddenField("AuthenticationMethod", null, $this->authenticator_class, $this),
     59                     //Regardless of what the unique identifer field is (usually 'Email'), it will be held in the 'Email' value, below:
     60                     new TextField("Email", $label, Session::get('SessionForms.MemberLoginForm.Email'), null, $this),
     61                     new PasswordField("Password", _t('Member.PASSWORD', 'Password'))
     62                 );
     63                 if(Security::$autologin_enabled) {
     64                     $fields->push(new CheckboxField(
     65                         "Remember",
     66                         _t('Member.REMEMBERME', "Remember me next time?")
     67                     ));
     68                 }
     69             }
     70             if(!$actions) {
     71                 $actions = new FieldSet(
     72                     new FormAction('dologin', _t('Member.BUTTONLOGIN', "Log in")),
     73                     new LiteralField(
     74                         'forgotPassword',
     75                         '<p id="ForgotPassword"><a href="'.Security::Link('lostpassword').'">' . _t('Member.BUTTONLOSTPASSWORD', "I've lost my password") . '</a></p>'
     76                     )
     77                 );
     78             }
     79         }
     80
     81         if(isset($backURL)) {
     82             $fields->push(new HiddenField('BackURL', 'BackURL', $backURL));
     83         }
     84
     85         parent::__construct($controller, $name, $fields, $actions);
     86
     87         $this->extend('updateMemberLoginForm');
     88         // Focus on the email input when the page is loaded
     89         // Only include this if other form JS validation is enabled
     90         if($this->getValidator()->getJavascriptValidationHandler() != 'none') {
     91             Requirements::customScript(<<<JS
     92                 (function() {
     93                     var el = document.getElementById("MemberLoginForm_LoginForm_Email");
     94                     if(el && el.focus) el.focus();
     95                 })();
     96 JS
     97             );
     98         }
     99     }
    100
    101     /**
    102      * Get message from session
    103      */
    104     protected function getMessageFromSession() {
    105         parent::getMessageFromSession();
    106         if(($member = Member::currentUser()) &&
    107                 !Session::get('MemberLoginForm.force_message')) {
    108             $this->message = sprintf(_t('Member.LOGGEDINAS', "You're logged in as %s."), $member->FirstName);
    109         }
    110         Session::set('MemberLoginForm.force_message', false);
    111     }
    112
    113
    114     /**
    115      * Login form handler method
    116      *
    117      * This method is called when the user clicks on "Log in"
    118      *
    119      * @param array $data Submitted data
    120      */
    121     public function dologin($data) {
    122         if($this->performLogin($data)) {
    123             Session::clear('SessionForms.MemberLoginForm.Email');
    124             Session::clear('SessionForms.MemberLoginForm.Remember');
    125             if(Member::currentUser()->isPasswordExpired()) {
    126                 if(isset($_REQUEST['BackURL']) && $backURL = $_REQUEST['BackURL']) {
    127                     Session::set('BackURL', $backURL);
    128                 }
    129
    130                 $cp = new ChangePasswordForm($this->controller, 'ChangePasswordForm');
    131                 $cp->sessionMessage('Your password has expired.  Please choose a new one.', 'good');
    132
    133                 Director::redirect('Security/changepassword');
    134             } elseif(
    135                 isset($_REQUEST['BackURL'])
    136                 && $_REQUEST['BackURL']
    137                 // absolute redirection URLs may cause spoofing
    138                 && Director::is_site_url($_REQUEST['BackURL'])
    139             ) {
    140                 Director::redirect($_REQUEST['BackURL']);
    141             } elseif (Security::default_login_dest()) {
    142                 Director::redirect(Director::absoluteBaseURL() . Security::default_login_dest());
    143             } else {
    144                 $member = Member::currentUser();
    145                 if($member) {
    146                     $firstname = Convert::raw2xml($member->FirstName);
    147
    148                     if(!empty($data['Remember'])) {
    149                         Session::set('SessionForms.MemberLoginForm.Remember', '1');
    150                         $member->logIn(true);
    151                     } else {
    152                         $member->logIn();
    153                     }
    154
    155                     Session::set('Security.Message.message',
    156                         sprintf(_t('Member.WELCOMEBACK', "Welcome Back, %s"), $firstname)
    157                     );
    158                     Session::set("Security.Message.type", "good");
    159                 }
    160                 Director::redirectBack();
    161             }
    162         } else {
    163             Session::set('SessionForms.MemberLoginForm.Email', $data['Email']);
    164             Session::set('SessionForms.MemberLoginForm.Remember', isset($data['Remember']));
    165
    166             if(isset($_REQUEST['BackURL'])) $backURL = $_REQUEST['BackURL'];
    167             else $backURL = null;
    168
    169             if($backURL) Session::set('BackURL', $backURL);
    170
    171             if($badLoginURL = Session::get("BadLoginURL")) {
    172                 Director::redirect($badLoginURL);
    173             } else {
    174                 // Show the right tab on failed login
    175                 $loginLink = Director::absoluteURL(Security::Link("login"));
    176                 if($backURL) $loginLink .= '?BackURL=' . urlencode($backURL);
    177                 Director::redirect($loginLink . '#' . $this->FormName() .'_tab');
    178             }
    179         }
    180     }
    181
    182
    183     /**
    184      * Log out form handler method
    185      *
    186      * This method is called when the user clicks on "logout" on the form
    187      * created when the parameter <i>$checkCurrentUser</i> of the
    188      * {@link __construct constructor} was set to TRUE and the user was
    189      * currently logged in.
    190      */
    191     public function logout() {
    192         $s = new Security();
    193         $s->logout();
    194     }
    195
    196
    197   /**
    198    * Try to authenticate the user
    199    *
    200    * @param array Submitted data
    201    * @return Member Returns the member object on successful authentication
    202    *                or NULL on failure.
    203    */
    204     public function performLogin($data) {
    205         $member = call_user_func_array(array($this->authenticator_class, 'authenticate'), array($data, $this));
    206         if($member) {
    207             $member->LogIn(isset($data['Remember']));
    208             return $member;
    209         } else {
    210             $this->extend('authenticationFailed', $data);
    211             return null;
    212         }
    213     }
    214
    215
    216     /**
    217      * Forgot password form handler method
    218      *
    219      * This method is called when the user clicks on "I've lost my password"
    220      *
    221      * @param array $data Submitted data
    222      */
    223     function forgotPassword($data) {
    224         $SQL_data = Convert::raw2sql($data);
    225         $SQL_email = $SQL_data['Email'];
    226         $member = DataObject::get_one('Member', "\"Email\" = '{$SQL_email}'");
    227
    228         if($member) {
    229             $member->generateAutologinHash();
    230
    231             $member->sendInfo(
    232                 'forgotPassword',
    233                 array(
    234                     'PasswordResetLink' => Security::getPasswordResetLink($member->AutoLoginHash)
    235                 )
    236             );
    237
    238             Director::redirect('Security/passwordsent/' . urlencode($data['Email']));
    239         } elseif($data['Email']) {
    240             // Avoid information disclosure by displaying the same status,
    241             // regardless wether the email address actually exists
    242             Director::redirect('Security/passwordsent/' . urlencode($data['Email']));
    243         } else {
    244             $this->sessionMessage(
    245                 _t('Member.ENTEREMAIL', 'Please enter an email address to get a password reset link.'),
    246                 'bad'
    247             );
    248
    249             Director::redirect('Security/lostpassword');
    250         }
    251     }
    252
    253 }
    254 ?>

[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -