This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Class LDAPLoginForm |
||
4 | * |
||
5 | * This not very interesting in itself. It's pretty much boiler-plate code to access the authenticator. |
||
6 | */ |
||
7 | class LDAPLoginForm extends MemberLoginForm |
||
8 | { |
||
9 | /** |
||
10 | * This field is used in the "You are logged in as %s" message |
||
11 | * @var string |
||
12 | */ |
||
13 | public $loggedInAsField = 'FirstName'; |
||
14 | |||
15 | /** |
||
16 | * @var string |
||
17 | */ |
||
18 | protected $authenticator_class = 'LDAPAuthenticator'; |
||
19 | |||
20 | /** |
||
21 | * @var LDAPSecurityController |
||
22 | */ |
||
23 | protected $ldapSecController = null; |
||
24 | |||
25 | /** |
||
26 | * Time in seconds that we use to ensure consistent repsonse times |
||
27 | * |
||
28 | * @var int |
||
29 | */ |
||
30 | const RESPONSE_TIME = 2; |
||
31 | |||
32 | /** |
||
33 | * Enables consistent handling times of password resets |
||
34 | * @config |
||
35 | */ |
||
36 | private static $consistent_password_times = false; |
||
37 | |||
38 | |||
39 | /** |
||
40 | * Constructor. |
||
41 | * |
||
42 | * @param Controller $controller |
||
43 | * @param string $name method on the $controller |
||
44 | * @param FieldList $fields |
||
45 | * @param FieldList $actions |
||
46 | * @param bool $checkCurrentUser - show logout button if logged in |
||
47 | */ |
||
48 | public function __construct($controller, $name, $fields = null, $actions = null, $checkCurrentUser = true) |
||
49 | { |
||
50 | parent::__construct($controller, $name, $fields, $actions, $checkCurrentUser); |
||
51 | |||
52 | // will be used to get correct Link() |
||
53 | $this->ldapSecController = Injector::inst()->create('LDAPSecurityController'); |
||
54 | |||
55 | if (Config::inst()->get('LDAPAuthenticator', 'allow_email_login')==='yes') { |
||
56 | $loginField = new TextField('Login', _t('LDAPLoginForm.USERNAMEOREMAIL', 'Username or email'), null, null, $this); |
||
57 | } else { |
||
58 | $loginField = new TextField('Login', _t('LDAPLoginForm.USERNAME', 'Username'), null, null, $this); |
||
59 | } |
||
60 | |||
61 | $this->Fields()->replaceField('Email', $loginField); |
||
62 | $this->setValidator(new RequiredFields('Login', 'Password')); |
||
63 | if (Security::config()->remember_username) { |
||
64 | $loginField->setValue(Session::get('SessionForms.MemberLoginForm.Email')); |
||
65 | } else { |
||
66 | // Some browsers won't respect this attribute unless it's added to the form |
||
67 | $this->setAttribute('autocomplete', 'off'); |
||
68 | $loginField->setAttribute('autocomplete', 'off'); |
||
69 | } |
||
70 | |||
71 | // Users can't change passwords unless appropriate a LDAP user with write permissions is |
||
72 | // configured the LDAP connection binding |
||
73 | $this->Actions()->remove($this->Actions()->fieldByName('forgotPassword')); |
||
74 | $allowPasswordChange = Config::inst()->get('LDAPService', 'allow_password_change'); |
||
75 | if ($allowPasswordChange && $name != 'LostPasswordForm' && !Member::currentUser()) { |
||
76 | $forgotPasswordLink = sprintf('<p id="ForgotPassword"><a href="%s">%s</a></p>', |
||
77 | $this->ldapSecController->Link('lostpassword'), |
||
78 | _t('Member.BUTTONLOSTPASSWORD', "I've lost my password") |
||
79 | ); |
||
80 | $forgotPassword = new LiteralField('forgotPassword', $forgotPasswordLink); |
||
81 | $this->Actions()->add($forgotPassword); |
||
82 | } |
||
83 | |||
84 | // Focus on the Username field when the page is loaded |
||
85 | Requirements::block('MemberLoginFormFieldFocus'); |
||
86 | $js = <<<JS |
||
87 | (function() { |
||
88 | var el = document.getElementById("Login"); |
||
89 | if(el && el.focus && (typeof jQuery == 'undefined' || jQuery(el).is(':visible'))) el.focus(); |
||
90 | })(); |
||
91 | JS; |
||
92 | Requirements::customScript($js, 'LDAPLoginFormFieldFocus'); |
||
93 | } |
||
94 | |||
95 | /** |
||
96 | * Forgot password form handler method. |
||
97 | * |
||
98 | * Called when the user clicks on "I've lost my password". |
||
99 | * |
||
100 | * Extensions can use the 'forgotPassword' method to veto executing |
||
101 | * the logic, by returning FALSE. In this case, the user will be redirected back |
||
102 | * to the form without further action. It is recommended to set a message |
||
103 | * in the form detailing why the action was denied. |
||
104 | * |
||
105 | * Overridden because we need to generate a link to the LDAPSecurityController |
||
106 | * instead of the SecurityController |
||
107 | * |
||
108 | * @param array $data Submitted data |
||
109 | * @return SS_HTTPResponse |
||
110 | */ |
||
111 | public function forgotPassword($data) |
||
112 | { |
||
113 | // Passing true returns a float rather than a string |
||
114 | $startTime = microtime(true); |
||
115 | // No need to protect against injections, LDAPService will ensure that this is safe |
||
116 | $login = trim($data['Login']); |
||
117 | |||
118 | $service = Injector::inst()->get('LDAPService'); |
||
119 | if (Email::validEmailAddress($login)) { |
||
120 | if (Config::inst()->get('LDAPAuthenticator', 'allow_email_login')!='yes') { |
||
121 | $this->sessionMessage( |
||
122 | _t( |
||
123 | 'LDAPLoginForm.USERNAMEINSTEADOFEMAIL', |
||
124 | 'Please enter your username instead of your email to get a password reset link.' |
||
125 | ), |
||
126 | 'bad' |
||
127 | ); |
||
128 | $this->consistentResponseTime($startTime); |
||
129 | $this->controller->redirect($this->controller->Link('lostpassword')); |
||
130 | return; |
||
131 | } |
||
132 | $userData = $service->getUserByEmail($login); |
||
133 | } else { |
||
134 | $userData = $service->getUserByUsername($login); |
||
135 | } |
||
136 | |||
137 | // Avoid information disclosure by displaying the same status, |
||
138 | // regardless whether the email address actually exists |
||
139 | if (!isset($userData['objectguid'])) { |
||
140 | $this->consistentResponseTime($startTime); |
||
141 | return $this->controller->redirect($this->controller->Link('passwordsent/') |
||
142 | . urlencode($data['Login'])); |
||
143 | } |
||
144 | |||
145 | $member = Member::get()->filter('GUID', $userData['objectguid'])->limit(1)->first(); |
||
146 | // User haven't been imported yet so do that now |
||
147 | View Code Duplication | if (!($member && $member->exists())) { |
|
0 ignored issues
–
show
|
|||
148 | $member = new Member(); |
||
149 | $member->GUID = $userData['objectguid']; |
||
150 | } |
||
151 | |||
152 | // Update the users from LDAP so we are sure that the email is correct. |
||
153 | // This will also write the Member record. |
||
154 | $service->updateMemberFromLDAP($member); |
||
155 | |||
156 | // Allow vetoing forgot password requests |
||
157 | $results = $this->extend('forgotPassword', $member); |
||
158 | if ($results && is_array($results) && in_array(false, $results, true)) { |
||
159 | $this->consistentResponseTime($startTime); |
||
160 | return $this->controller->redirect($this->ldapSecController->Link('lostpassword')); |
||
161 | } |
||
162 | |||
163 | if ($member) { |
||
164 | $token = $member->generateAutologinTokenAndStoreHash(); |
||
165 | $e = Member_ForgotPasswordEmail::create(); |
||
166 | $e->populateTemplate($member); |
||
167 | $e->populateTemplate([ |
||
168 | 'PasswordResetLink' => LDAPSecurityController::getPasswordResetLink($member, $token) |
||
169 | ]); |
||
170 | $e->setTo($member->Email); |
||
171 | $e->send(); |
||
172 | $this->consistentResponseTime($startTime); |
||
173 | $this->controller->redirect($this->controller->Link('passwordsent/') . urlencode($data['Login'])); |
||
174 | } elseif ($data['Login']) { |
||
175 | // Avoid information disclosure by displaying the same status, |
||
176 | // regardless whether the email address actually exists |
||
177 | $this->consistentResponseTime($startTime); |
||
178 | $this->controller->redirect($this->controller->Link('passwordsent/') . urlencode($data['Login'])); |
||
179 | } else { |
||
180 | if (Config::inst()->get('LDAPAuthenticator', 'allow_email_login')==='yes') { |
||
181 | $this->sessionMessage( |
||
182 | _t( |
||
183 | 'LDAPLoginForm.ENTERUSERNAMEOREMAIL', |
||
184 | 'Please enter your username or your email address to get a password reset link.' |
||
185 | ), |
||
186 | 'bad' |
||
187 | ); |
||
188 | } else { |
||
189 | $this->sessionMessage( |
||
190 | _t( |
||
191 | 'LDAPLoginForm.ENTERUSERNAME', |
||
192 | 'Please enter your username to get a password reset link.' |
||
193 | ), |
||
194 | 'bad' |
||
195 | ); |
||
196 | } |
||
197 | $this->consistentResponseTime($startTime); |
||
198 | $this->controller->redirect($this->controller->Link('lostpassword')); |
||
199 | } |
||
200 | } |
||
201 | |||
202 | /** |
||
203 | * Ensures response times are the same across all scenarios i.e. email exists or doesn't |
||
204 | * this helps to avoid issues where malicious users could find if an email is legitimate based on response time |
||
205 | * |
||
206 | * @param float $startTime |
||
207 | */ |
||
208 | protected function consistentResponseTime($startTime) |
||
209 | { |
||
210 | if (!Config::inst()->get('LDAPLoginForm', 'consistent_password_times')) { |
||
211 | return; |
||
212 | } |
||
213 | |||
214 | $timeTaken = microtime(true) - $startTime; |
||
215 | if ($timeTaken < self::RESPONSE_TIME) { |
||
216 | $sleepTime = self::RESPONSE_TIME - $timeTaken; |
||
217 | // usleep takes microseconds, so we times our sleep period by 1mil (1mil ms = 1s) |
||
218 | usleep($sleepTime * 1000000); |
||
219 | } |
||
220 | |||
221 | } |
||
222 | } |
||
223 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.