Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
1 | <?php |
||
27 | */ |
||
28 | private $name = 'LDAP'; |
||
|
|||
29 | |||
30 | /** |
||
31 | * Set to 'yes' to indicate if this module should look up usernames in LDAP by matching the email addresses. |
||
32 | * |
||
33 | * CAVEAT #1: only set to 'yes' for systems that enforce email uniqueness. |
||
34 | * Otherwise only the first LDAP user with matching email will be accessible. |
||
35 | * |
||
36 | * CAVEAT #2: this is untested for systems that use LDAP with principal style usernames (i.e. [email protected]). |
||
37 | * The system will misunderstand emails for usernames with uncertain outcome. |
||
38 | * |
||
39 | * @var string 'no' or 'yes' |
||
40 | */ |
||
41 | private static $allow_email_login = 'no'; |
||
42 | |||
43 | /** |
||
44 | * Set to 'yes' to fallback login attempts to {@link $fallback_authenticator}. |
||
45 | * This will occur if LDAP fails to authenticate the user. |
||
46 | * |
||
47 | * @var string 'no' or 'yes' |
||
48 | */ |
||
49 | private static $fallback_authenticator = 'no'; |
||
50 | |||
51 | /** |
||
52 | * The class of {@link Authenticator} to use as the fallback authenticator. |
||
53 | * |
||
54 | * @var string |
||
55 | */ |
||
56 | private static $fallback_authenticator_class = MemberAuthenticator::class; |
||
57 | |||
58 | /** |
||
59 | * @return string |
||
60 | */ |
||
61 | public static function get_name() |
||
62 | { |
||
63 | return Config::inst()->get(self::class, 'name'); |
||
64 | } |
||
65 | |||
66 | /** |
||
67 | * @param Controller $controller |
||
68 | * @return LDAPLoginForm |
||
69 | */ |
||
70 | public static function get_login_form(Controller $controller) |
||
71 | { |
||
72 | return LDAPLoginForm::create($controller, LDAPAuthenticator::class, 'LoginForm'); |
||
73 | } |
||
74 | |||
75 | /** |
||
76 | * Performs the login, but will also create and sync the Member record on-the-fly, if not found. |
||
77 | * |
||
78 | * @param array $data |
||
79 | * @param HTTPRequest $request |
||
80 | * @param ValidationResult|null $result |
||
81 | * @return null|Member |
||
82 | */ |
||
83 | public function authenticate(array $data, HTTPRequest $request, ValidationResult &$result = null) |
||
84 | { |
||
85 | $result = $result ?: ValidationResult::create(); |
||
86 | /** @var LDAPService $service */ |
||
87 | $service = Injector::inst()->get(LDAPService::class); |
||
88 | $login = trim($data['Login']); |
||
89 | if (Email::is_valid_address($login)) { |
||
90 | if (Config::inst()->get(self::class, 'allow_email_login') != 'yes') { |
||
91 | $result->addError( |
||
92 | _t( |
||
93 | __CLASS__ . '.PLEASEUSEUSERNAME', |
||
94 | 'Please enter your username instead of your email to log in.' |
||
95 | ) |
||
96 | ); |
||
97 | return null; |
||
98 | } |
||
99 | $username = $service->getUsernameByEmail($login); |
||
100 | |||
101 | // No user found with this email. |
||
102 | if (!$username) { |
||
103 | if (Config::inst()->get(self::class, 'fallback_authenticator') === 'yes') { |
||
104 | if ($fallbackMember = $this->fallbackAuthenticate($data, $request)) { |
||
105 | { |
||
106 | return $fallbackMember; |
||
107 | } |
||
108 | } |
||
109 | } |
||
110 | |||
111 | $result->addError(_t(__CLASS__ . '.INVALIDCREDENTIALS', 'Invalid credentials')); |
||
112 | return null; |
||
113 | } |
||
114 | } else { |
||
115 | $username = $login; |
||
116 | } |
||
117 | |||
118 | $serviceAuthenticationResult = $service->authenticate($username, $data['Password']); |
||
119 | $success = $serviceAuthenticationResult['success'] === true; |
||
120 | |||
121 | if (!$success) { |
||
122 | /* |
||
123 | * Try the fallback method if admin or it failed for anything other than invalid credentials |
||
124 | * This is to avoid having an unhandled exception error thrown by PasswordEncryptor::create_for_algorithm() |
||
125 | */ |
||
126 | if (Config::inst()->get(self::class, 'fallback_authenticator') === 'yes') { |
||
127 | if (!in_array($serviceAuthenticationResult['code'], [Result::FAILURE_CREDENTIAL_INVALID]) |
||
128 | || $username === 'admin' |
||
129 | ) { |
||
130 | if ($fallbackMember = $this->fallbackAuthenticate($data, $request)) { |
||
131 | return $fallbackMember; |
||
132 | } |
||
133 | } |
||
134 | } |
||
135 | |||
136 | $result->addError($serviceAuthenticationResult['message']); |
||
137 | |||
138 | return null; |
||
139 | } |
||
140 | $data = $service->getUserByUsername($serviceAuthenticationResult['identity']); |
||
141 | if (!$data) { |
||
142 | $result->addError( |
||
143 | _t( |
||
144 | __CLASS__ . '.PROBLEMFINDINGDATA', |
||
145 | 'There was a problem retrieving your user data' |
||
146 | ) |
||
147 | ); |
||
148 | return null; |
||
149 | } |
||
150 | |||
151 | // LDAPMemberExtension::memberLoggedIn() will update any other AD attributes mapped to Member fields |
||
152 | $member = Member::get()->filter('GUID', $data['objectguid'])->limit(1)->first(); |
||
153 | View Code Duplication | if (!($member && $member->exists())) { |
|
154 | $member = new Member(); |
||
155 | $member->GUID = $data['objectguid']; |
||
156 | } |
||
157 | |||
158 | // Update the users from LDAP so we are sure that the email is correct. |
||
159 | // This will also write the Member record. |
||
160 | $service->updateMemberFromLDAP($member, $data); |
||
161 | |||
162 | $request->getSession()->clear('BackURL'); |
||
163 | |||
164 | return $member; |
||
165 | } |
||
166 | |||
167 | /** |
||
168 | * Try to authenticate using the fallback authenticator. |
||
169 | * |
||
170 | * @param array $data |
||
171 | * @param HTTPRequest $request |
||
172 | * @return null|Member |
||
173 | */ |
||
174 | protected function fallbackAuthenticate($data, HTTPRequest $request) |
||
175 | { |
||
176 | // Set Email from Login |
||
177 | if (array_key_exists('Login', $data) && !array_key_exists('Email', $data)) { |
||
178 | $data['Email'] = $data['Login']; |
||
179 | } |
||
180 | $authenticatorClass = Config::inst()->get(self::class, 'fallback_authenticator_class'); |
||
181 | if ($authenticator = Injector::inst()->get($authenticatorClass)) { |
||
182 | $result = call_user_func( |
||
183 | [ |
||
184 | $authenticator, |
||
185 | 'authenticate' |
||
186 | ], |
||
187 | $data, |
||
188 | $request |
||
189 | ); |
||
190 | return $result; |
||
191 | } |
||
192 | } |
||
193 | |||
194 | public function getLoginHandler($link) |
||
195 | { |
||
196 | return LDAPLoginHandler::create($link, $this); |
||
197 | } |
||
198 | |||
199 | public function supportedServices() |
||
200 | { |
||
201 | $result = Authenticator::LOGIN | Authenticator::LOGOUT | Authenticator::RESET_PASSWORD; |
||
202 | |||
203 | if ((bool)LDAPService::config()->get('allow_password_change')) { |
||
204 | $result |= Authenticator::CHANGE_PASSWORD; |
||
205 | } |
||
206 | return $result; |
||
207 | } |
||
208 | |||
209 | public function getLostPasswordHandler($link) |
||
210 | { |
||
211 | return LDAPLostPasswordHandler::create($link, $this); |
||
212 | } |
||
213 | |||
214 | /** |
||
215 | * @param string $link |
||
216 | * @return LDAPChangePasswordHandler |
||
217 | */ |
||
218 | public function getChangePasswordHandler($link) |
||
221 | } |
||
222 | } |
||
223 |
This check marks private properties in classes that are never used. Those properties can be removed.