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 | * This file is part of the LdapToolsBundle package. |
||
4 | * |
||
5 | * (c) Chad Sikorra <[email protected]> |
||
6 | * |
||
7 | * For the full copyright and license information, please view the LICENSE |
||
8 | * file that was distributed with this source code. |
||
9 | */ |
||
10 | |||
11 | namespace LdapTools\Bundle\LdapToolsBundle\Security; |
||
12 | |||
13 | use LdapTools\Bundle\LdapToolsBundle\Event\AuthenticationHandlerEvent; |
||
14 | use LdapTools\Bundle\LdapToolsBundle\Event\LdapLoginEvent; |
||
15 | use LdapTools\Bundle\LdapToolsBundle\Security\User\LdapUserChecker; |
||
16 | use LdapTools\Bundle\LdapToolsBundle\Security\User\LdapUserProvider; |
||
17 | use LdapTools\Exception\LdapConnectionException; |
||
18 | use LdapTools\Operation\AuthenticationOperation; |
||
19 | use LdapTools\LdapManager; |
||
20 | use Symfony\Component\EventDispatcher\EventDispatcherInterface; |
||
21 | use Symfony\Component\HttpFoundation\Request; |
||
22 | use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; |
||
23 | use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; |
||
24 | use Symfony\Component\Security\Core\Exception\AuthenticationException; |
||
25 | use Symfony\Component\Security\Core\Exception\BadCredentialsException; |
||
26 | use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException; |
||
27 | use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; |
||
28 | use Symfony\Component\Security\Core\Security; |
||
29 | use Symfony\Component\Security\Core\User\UserInterface; |
||
30 | use Symfony\Component\Security\Core\User\UserProviderInterface; |
||
31 | use Symfony\Component\Security\Guard\AbstractGuardAuthenticator; |
||
32 | use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; |
||
33 | use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; |
||
34 | use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; |
||
35 | use Symfony\Component\Security\Http\EntryPoint\BasicAuthenticationEntryPoint; |
||
36 | |||
37 | /** |
||
38 | * LDAP Guard Authenticator. |
||
39 | * |
||
40 | * @author Chad Sikorra <[email protected]> |
||
41 | */ |
||
42 | class LdapGuardAuthenticator extends AbstractGuardAuthenticator |
||
43 | { |
||
44 | use LdapAuthenticationTrait; |
||
45 | |||
46 | /** |
||
47 | * @var LdapUserChecker |
||
48 | */ |
||
49 | protected $userChecker; |
||
50 | |||
51 | /** |
||
52 | * @var string |
||
53 | */ |
||
54 | protected $domain; |
||
55 | |||
56 | /** |
||
57 | * @var EventDispatcherInterface |
||
58 | */ |
||
59 | protected $dispatcher; |
||
60 | |||
61 | /** |
||
62 | * @var AuthenticationSuccessHandlerInterface |
||
63 | */ |
||
64 | protected $successHandler; |
||
65 | |||
66 | /** |
||
67 | * @var AuthenticationFailureHandlerInterface |
||
68 | */ |
||
69 | protected $failureHandler; |
||
70 | |||
71 | /** |
||
72 | * @var AuthenticationEntryPointInterface |
||
73 | */ |
||
74 | protected $entryPoint; |
||
75 | |||
76 | /** |
||
77 | * @var array |
||
78 | */ |
||
79 | protected $options = [ |
||
80 | 'hide_user_not_found_exceptions' => true, |
||
81 | 'username_parameter' => '_username', |
||
82 | 'password_parameter' => '_password', |
||
83 | 'domain_parameter' => '_ldap_domain', |
||
84 | 'post_only' => false, |
||
85 | 'remember_me' => false, |
||
86 | 'login_query_attribute' => null, |
||
87 | 'http_basic' => false, |
||
88 | 'http_basic_realm' => null, |
||
89 | 'http_basic_domain' => null, |
||
90 | ]; |
||
91 | |||
92 | /** |
||
93 | * @param bool $hideUserNotFoundExceptions |
||
94 | * @param LdapUserChecker $userChecker |
||
95 | * @param LdapManager $ldap |
||
96 | * @param AuthenticationEntryPointInterface $entryPoint |
||
97 | * @param EventDispatcherInterface $dispatcher |
||
98 | * @param AuthenticationSuccessHandlerInterface $successHandler |
||
99 | * @param AuthenticationFailureHandlerInterface $failureHandler |
||
100 | * @param array $options |
||
101 | * @param LdapUserProvider $ldapUserProvider |
||
102 | */ |
||
103 | public function __construct($hideUserNotFoundExceptions = true, LdapUserChecker $userChecker, LdapManager $ldap, AuthenticationEntryPointInterface $entryPoint, EventDispatcherInterface $dispatcher, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options, LdapUserProvider $ldapUserProvider) |
||
104 | { |
||
105 | $this->userChecker = $userChecker; |
||
106 | $this->ldap = $ldap; |
||
107 | $this->entryPoint = $entryPoint; |
||
108 | $this->dispatcher = $dispatcher; |
||
109 | $this->successHandler = $successHandler; |
||
110 | $this->failureHandler = $failureHandler; |
||
111 | $this->options['hide_user_not_found_exceptions'] = $hideUserNotFoundExceptions; |
||
112 | $this->ldapUserProvider = $ldapUserProvider; |
||
113 | $this->options = array_merge($this->options, $options); |
||
114 | } |
||
115 | |||
116 | /** |
||
117 | * Allows to more easily extend the base LDAP guard service and set specific options. |
||
118 | * |
||
119 | * @param array $options |
||
120 | * @return $this |
||
121 | */ |
||
122 | public function setOptions(array $options) |
||
123 | { |
||
124 | $this->options = array_merge($this->options, $options); |
||
125 | |||
126 | return $this; |
||
127 | } |
||
128 | |||
129 | /** |
||
130 | * {@inheritdoc} |
||
131 | */ |
||
132 | public function supports(Request $request) |
||
133 | { |
||
134 | return !empty($this->getRequestUsername($request)); |
||
135 | } |
||
136 | |||
137 | /** |
||
138 | * {@inheritdoc} |
||
139 | */ |
||
140 | public function getCredentials(Request $request) |
||
141 | { |
||
142 | if (!$this->supports($request)) { |
||
143 | return null; |
||
144 | } |
||
145 | $credentials = [ |
||
146 | 'username' => $this->getRequestUsername($request), |
||
147 | 'password' => $this->getRequestPassword($request), |
||
148 | 'ldap_domain' => $this->getRequestDomain($request), |
||
149 | ]; |
||
150 | $request->getSession()->set(Security::LAST_USERNAME, $credentials['username']); |
||
151 | |||
152 | return $credentials; |
||
153 | } |
||
154 | |||
155 | /** |
||
156 | * {@inheritdoc} |
||
157 | */ |
||
158 | public function getUser($credentials, UserProviderInterface $userProvider) |
||
159 | { |
||
160 | $domain = $this->ldap->getDomainContext(); |
||
161 | |||
162 | try { |
||
163 | $credDomain = isset($credentials['ldap_domain']) ? $credentials['ldap_domain'] : ''; |
||
164 | $this->switchDomainIfNeeded($credDomain); |
||
165 | $this->setLdapCredentialsIfNeeded($credentials['username'], $credentials['password'], $userProvider); |
||
166 | $user = $userProvider->loadUserByUsername($credentials['username']); |
||
167 | $this->userChecker->checkPreAuth($user); |
||
168 | |||
169 | return $user; |
||
170 | } catch (UsernameNotFoundException $e) { |
||
171 | $this->hideOrThrow($e, $this->options['hide_user_not_found_exceptions']); |
||
172 | } catch (BadCredentialsException $e) { |
||
173 | $this->hideOrThrow($e, $this->options['hide_user_not_found_exceptions']); |
||
174 | } catch (LdapConnectionException $e) { |
||
175 | $this->hideOrThrow($e, $this->options['hide_user_not_found_exceptions']); |
||
176 | } catch (\Exception $e) { |
||
177 | $this->hideOrThrow($e, $this->options['hide_user_not_found_exceptions']); |
||
178 | } finally { |
||
179 | $this->switchDomainBackIfNeeded($domain); |
||
180 | } |
||
181 | } |
||
182 | |||
183 | /** |
||
184 | * {@inheritdoc} |
||
185 | */ |
||
186 | public function checkCredentials($credentials, UserInterface $user) |
||
187 | { |
||
188 | $domain = $this->ldap->getDomainContext(); |
||
189 | |||
190 | try { |
||
191 | $credDomain = isset($credentials['ldap_domain']) ? $credentials['ldap_domain'] : ''; |
||
192 | $this->switchDomainIfNeeded($credDomain); |
||
193 | /** @var \LdapTools\Operation\AuthenticationResponse $response */ |
||
194 | $response = $this->ldap->getConnection()->execute( |
||
195 | new AuthenticationOperation( |
||
196 | $this->getBindUsername($user, $this->options['login_query_attribute']), |
||
197 | $credentials['password'] |
||
198 | ) |
||
199 | ); |
||
200 | View Code Duplication | if (!$response->isAuthenticated()) { |
|
0 ignored issues
–
show
|
|||
201 | $this->userChecker->checkLdapErrorCode( |
||
202 | $user, |
||
203 | $response->getErrorCode(), |
||
204 | $this->ldap->getConnection()->getConfig()->getLdapType() |
||
205 | ); |
||
206 | throw new CustomUserMessageAuthenticationException( |
||
207 | $response->getErrorMessage(), [], $response->getErrorCode() |
||
208 | ); |
||
209 | } |
||
210 | // No way to get the token from the Guard, need to create one to pass... |
||
211 | $token = new UsernamePasswordToken($user, $credentials['password'], 'ldap-tools', $user->getRoles()); |
||
212 | $token->setAttribute('ldap_domain', $credDomain); |
||
213 | $this->dispatcher->dispatch( |
||
214 | LdapLoginEvent::SUCCESS, |
||
215 | new LdapLoginEvent($user, $token) |
||
216 | ); |
||
217 | } catch (\Exception $e) { |
||
218 | $this->hideOrThrow($e, $this->options['hide_user_not_found_exceptions']); |
||
219 | } finally { |
||
220 | $this->domain = $this->ldap->getDomainContext(); |
||
221 | $this->switchDomainBackIfNeeded($domain); |
||
222 | } |
||
223 | |||
224 | return true; |
||
225 | } |
||
226 | |||
227 | /** |
||
228 | * {@inheritdoc} |
||
229 | */ |
||
230 | View Code Duplication | public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
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. ![]() |
|||
231 | { |
||
232 | $event = new AuthenticationHandlerEvent( |
||
233 | $this->successHandler->onAuthenticationSuccess($request, $token), |
||
234 | $request, |
||
235 | null, |
||
236 | $token, |
||
237 | $providerKey |
||
238 | ); |
||
239 | $this->dispatcher->dispatch(AuthenticationHandlerEvent::SUCCESS, $event); |
||
240 | |||
241 | return $this->options['http_basic'] ? null : $event->getResponse(); |
||
242 | } |
||
243 | |||
244 | /** |
||
245 | * {@inheritdoc} |
||
246 | */ |
||
247 | public function onAuthenticationFailure(Request $request, AuthenticationException $exception) |
||
248 | { |
||
249 | $event = new AuthenticationHandlerEvent( |
||
250 | $this->failureHandler->onAuthenticationFailure($request, $exception), |
||
251 | $request, |
||
252 | $exception |
||
253 | ); |
||
254 | $this->dispatcher->dispatch(AuthenticationHandlerEvent::FAILURE, $event); |
||
255 | |||
256 | return $this->options['http_basic'] ? null : $event->getResponse(); |
||
257 | } |
||
258 | |||
259 | /** |
||
260 | * {@inheritdoc} |
||
261 | */ |
||
262 | View Code Duplication | public function start(Request $request, AuthenticationException $authException = null) |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
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. ![]() |
|||
263 | { |
||
264 | $entryPoint = $this->options['http_basic'] ? new BasicAuthenticationEntryPoint($this->getHttpBasicRealm()) : $this->entryPoint; |
||
265 | $event = new AuthenticationHandlerEvent( |
||
266 | $entryPoint->start($request, $authException), |
||
267 | $request, |
||
268 | $authException |
||
269 | ); |
||
270 | $this->dispatcher->dispatch(AuthenticationHandlerEvent::START, $event); |
||
271 | |||
272 | return $event->getResponse(); |
||
273 | } |
||
274 | |||
275 | /** |
||
276 | * {@inheritdoc} |
||
277 | */ |
||
278 | public function supportsRememberMe() |
||
279 | { |
||
280 | return $this->options['remember_me']; |
||
281 | } |
||
282 | |||
283 | /** |
||
284 | * {@inheritdoc} |
||
285 | */ |
||
286 | public function createAuthenticatedToken(UserInterface $user, $providerKey) |
||
287 | { |
||
288 | $token = parent::createAuthenticatedToken($user, $providerKey); |
||
289 | $token->setAttribute('ldap_domain', $this->domain); |
||
290 | |||
291 | return $token; |
||
292 | } |
||
293 | |||
294 | /** |
||
295 | * @param Request $request |
||
296 | * @return null|string |
||
297 | */ |
||
298 | protected function getRequestUsername(Request $request) |
||
299 | { |
||
300 | if ($this->options['http_basic']) { |
||
301 | return $request->server->get('PHP_AUTH_USER'); |
||
302 | } else{ |
||
303 | return $this->getRequestParameter($this->options['username_parameter'], $request); |
||
304 | } |
||
305 | } |
||
306 | |||
307 | /** |
||
308 | * @param Request $request |
||
309 | * @return null|string |
||
310 | */ |
||
311 | protected function getRequestPassword(Request $request) |
||
312 | { |
||
313 | if ($this->options['http_basic']) { |
||
314 | return $request->server->get('PHP_AUTH_PW'); |
||
315 | } else{ |
||
316 | return $this->getRequestParameter($this->options['password_parameter'], $request); |
||
317 | } |
||
318 | } |
||
319 | |||
320 | /** |
||
321 | * @param Request $request |
||
322 | * @return null|string |
||
323 | */ |
||
324 | protected function getRequestDomain(Request $request) |
||
325 | { |
||
326 | if ($this->options['http_basic']) { |
||
327 | return $this->options['http_basic_domain']; |
||
328 | } else{ |
||
329 | return $this->getRequestParameter($this->options['domain_parameter'], $request); |
||
330 | } |
||
331 | } |
||
332 | |||
333 | /** |
||
334 | * @param string $param |
||
335 | * @param Request $request |
||
336 | * @return string|null |
||
337 | */ |
||
338 | protected function getRequestParameter($param, Request $request) |
||
339 | { |
||
340 | if ($this->options['post_only']) { |
||
341 | $value = $request->request->get($param); |
||
342 | } else { |
||
343 | $value = $request->request->get($param) ?: $request->get($param); |
||
344 | } |
||
345 | |||
346 | return $value; |
||
347 | } |
||
348 | |||
349 | /** |
||
350 | * @return string |
||
351 | */ |
||
352 | protected function getHttpBasicRealm() |
||
353 | { |
||
354 | if ($this->options['http_basic_realm'] !== null) { |
||
355 | $realm = $this->options['http_basic_realm']; |
||
356 | } elseif ($this->options['http_basic_domain'] !== null) { |
||
357 | $realm = $this->options['http_basic_domain']; |
||
358 | } else { |
||
359 | $realm = $this->ldap->getDomainContext(); |
||
360 | } |
||
361 | |||
362 | return $realm; |
||
363 | } |
||
364 | } |
||
365 |
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.