Source of file LDAPLoginForm.php
Size: 9,001 Bytes - Last Modified: 2021-12-23T10:27:14+00:00
/var/www/docs.ssmods.com/process/src/code/authenticators/LDAPLoginForm.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 | <?php /** * Class LDAPLoginForm * * This not very interesting in itself. It's pretty much boiler-plate code to access the authenticator. */ class LDAPLoginForm extends MemberLoginForm { /** * This field is used in the "You are logged in as %s" message * @var string */ public $loggedInAsField = 'FirstName'; /** * @var string */ protected $authenticator_class = 'LDAPAuthenticator'; /** * @var LDAPSecurityController */ protected $ldapSecController = null; /** * Time in seconds that we use to ensure consistent repsonse times * * @var int */ const RESPONSE_TIME = 2; /** * Enables consistent handling times of password resets * @config */ private static $consistent_password_times = false; /** * Constructor. * * @param Controller $controller * @param string $name method on the $controller * @param FieldList $fields * @param FieldList $actions * @param bool $checkCurrentUser - show logout button if logged in */ public function __construct($controller, $name, $fields = null, $actions = null, $checkCurrentUser = true) { parent::__construct($controller, $name, $fields, $actions, $checkCurrentUser); // will be used to get correct Link() $this->ldapSecController = Injector::inst()->create('LDAPSecurityController'); if (Config::inst()->get('LDAPAuthenticator', 'allow_email_login')==='yes') { $loginField = new TextField('Login', _t('LDAPLoginForm.USERNAMEOREMAIL', 'Username or email'), null, null, $this); } else { $loginField = new TextField('Login', _t('LDAPLoginForm.USERNAME', 'Username'), null, null, $this); } $this->Fields()->replaceField('Email', $loginField); $this->setValidator(new RequiredFields('Login', 'Password')); if (Security::config()->remember_username) { $loginField->setValue(Session::get('SessionForms.MemberLoginForm.Email')); } else { // Some browsers won't respect this attribute unless it's added to the form $this->setAttribute('autocomplete', 'off'); $loginField->setAttribute('autocomplete', 'off'); } // Users can't change passwords unless appropriate a LDAP user with write permissions is // configured the LDAP connection binding $this->Actions()->remove($this->Actions()->fieldByName('forgotPassword')); $allowPasswordChange = Config::inst()->get('LDAPService', 'allow_password_change'); if ($allowPasswordChange && $name != 'LostPasswordForm' && !Member::currentUser()) { $forgotPasswordLink = sprintf('<p id="ForgotPassword"><a href="%s">%s</a></p>', $this->ldapSecController->Link('lostpassword'), _t('Member.BUTTONLOSTPASSWORD', "I've lost my password") ); $forgotPassword = new LiteralField('forgotPassword', $forgotPasswordLink); $this->Actions()->add($forgotPassword); } // Focus on the Username field when the page is loaded Requirements::block('MemberLoginFormFieldFocus'); $js = <<<JS (function() { var el = document.getElementById("Login"); if(el && el.focus && (typeof jQuery == 'undefined' || jQuery(el).is(':visible'))) el.focus(); })(); JS; Requirements::customScript($js, 'LDAPLoginFormFieldFocus'); } /** * Forgot password form handler method. * * Called when the user clicks on "I've lost my password". * * Extensions can use the 'forgotPassword' method to veto executing * the logic, by returning FALSE. In this case, the user will be redirected back * to the form without further action. It is recommended to set a message * in the form detailing why the action was denied. * * Overridden because we need to generate a link to the LDAPSecurityController * instead of the SecurityController * * @param array $data Submitted data * @return SS_HTTPResponse */ public function forgotPassword($data) { // Passing true returns a float rather than a string $startTime = microtime(true); // No need to protect against injections, LDAPService will ensure that this is safe $login = trim($data['Login']); $service = Injector::inst()->get('LDAPService'); if (Email::validEmailAddress($login)) { if (Config::inst()->get('LDAPAuthenticator', 'allow_email_login')!='yes') { $this->sessionMessage( _t( 'LDAPLoginForm.USERNAMEINSTEADOFEMAIL', 'Please enter your username instead of your email to get a password reset link.' ), 'bad' ); $this->consistentResponseTime($startTime); $this->controller->redirect($this->controller->Link('lostpassword')); return; } $userData = $service->getUserByEmail($login); } else { $userData = $service->getUserByUsername($login); } // Avoid information disclosure by displaying the same status, // regardless whether the email address actually exists if (!isset($userData['objectguid'])) { $this->consistentResponseTime($startTime); return $this->controller->redirect($this->controller->Link('passwordsent/') . urlencode($data['Login'])); } $member = Member::get()->filter('GUID', $userData['objectguid'])->limit(1)->first(); // User haven't been imported yet so do that now if (!($member && $member->exists())) { $member = new Member(); $member->GUID = $userData['objectguid']; } // Update the users from LDAP so we are sure that the email is correct. // This will also write the Member record. $service->updateMemberFromLDAP($member); // Allow vetoing forgot password requests $results = $this->extend('forgotPassword', $member); if ($results && is_array($results) && in_array(false, $results, true)) { $this->consistentResponseTime($startTime); return $this->controller->redirect($this->ldapSecController->Link('lostpassword')); } if ($member) { $token = $member->generateAutologinTokenAndStoreHash(); $e = Member_ForgotPasswordEmail::create(); $e->populateTemplate($member); $e->populateTemplate([ 'PasswordResetLink' => LDAPSecurityController::getPasswordResetLink($member, $token) ]); $e->setTo($member->Email); $e->send(); $this->consistentResponseTime($startTime); $this->controller->redirect($this->controller->Link('passwordsent/') . urlencode($data['Login'])); } elseif ($data['Login']) { // Avoid information disclosure by displaying the same status, // regardless whether the email address actually exists $this->consistentResponseTime($startTime); $this->controller->redirect($this->controller->Link('passwordsent/') . urlencode($data['Login'])); } else { if (Config::inst()->get('LDAPAuthenticator', 'allow_email_login')==='yes') { $this->sessionMessage( _t( 'LDAPLoginForm.ENTERUSERNAMEOREMAIL', 'Please enter your username or your email address to get a password reset link.' ), 'bad' ); } else { $this->sessionMessage( _t( 'LDAPLoginForm.ENTERUSERNAME', 'Please enter your username to get a password reset link.' ), 'bad' ); } $this->consistentResponseTime($startTime); $this->controller->redirect($this->controller->Link('lostpassword')); } } /** * Ensures response times are the same across all scenarios i.e. email exists or doesn't * this helps to avoid issues where malicious users could find if an email is legitimate based on response time * * @param float $startTime */ protected function consistentResponseTime($startTime) { if (!Config::inst()->get('LDAPLoginForm', 'consistent_password_times')) { return; } $timeTaken = microtime(true) - $startTime; if ($timeTaken < self::RESPONSE_TIME) { $sleepTime = self::RESPONSE_TIME - $timeTaken; // usleep takes microseconds, so we times our sleep period by 1mil (1mil ms = 1s) usleep($sleepTime * 1000000); } } } |