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\User; |
||
12 | |||
13 | use LdapTools\BatchModify\BatchCollection; |
||
14 | use LdapTools\Bundle\LdapToolsBundle\Event\LoadUserEvent; |
||
15 | use LdapTools\Exception\EmptyResultException; |
||
16 | use LdapTools\Exception\MultiResultException; |
||
17 | use LdapTools\LdapManager; |
||
18 | use LdapTools\Object\LdapObject; |
||
19 | use Symfony\Component\EventDispatcher\EventDispatcherInterface; |
||
20 | use Symfony\Component\Security\Core\Exception\UnsupportedUserException; |
||
21 | use Symfony\Component\Security\Core\User\UserInterface; |
||
22 | use Symfony\Component\Security\Core\User\UserProviderInterface; |
||
23 | use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; |
||
24 | |||
25 | /** |
||
26 | * Loads a user from LDAP. |
||
27 | * |
||
28 | * @author Chad Sikorra <[email protected]> |
||
29 | */ |
||
30 | class LdapUserProvider implements UserProviderInterface |
||
31 | { |
||
32 | /** |
||
33 | * @var LdapManager |
||
34 | */ |
||
35 | protected $ldap; |
||
36 | |||
37 | /** |
||
38 | * @var EventDispatcherInterface |
||
39 | */ |
||
40 | protected $dispatcher; |
||
41 | |||
42 | /** |
||
43 | * @var LdapRoleMapper |
||
44 | */ |
||
45 | protected $roleMapper; |
||
46 | |||
47 | /** |
||
48 | * @var array Default attributes selected for the Advanced User Interface. |
||
49 | */ |
||
50 | protected $defaultAttributes = [ |
||
51 | 'username', |
||
52 | 'guid', |
||
53 | 'accountExpirationDate', |
||
54 | 'enabled', |
||
55 | 'groups', |
||
56 | 'locked', |
||
57 | 'passwordMustChange', |
||
58 | ]; |
||
59 | |||
60 | /** |
||
61 | * @var array |
||
62 | */ |
||
63 | protected $options = [ |
||
64 | 'refresh_user_roles' => false, |
||
65 | 'refresh_user_attributes' => false, |
||
66 | 'search_base' => null, |
||
67 | 'ldap_object_type' => 'user', |
||
68 | 'user' => LdapUser::class, |
||
69 | 'additional_attributes' => [], |
||
70 | ]; |
||
71 | |||
72 | /** |
||
73 | * @param LdapManager $ldap |
||
74 | * @param EventDispatcherInterface $dispatcher |
||
75 | * @param LdapRoleMapper $roleMapper |
||
76 | * @param array $options |
||
77 | */ |
||
78 | public function __construct(LdapManager $ldap, EventDispatcherInterface $dispatcher, LdapRoleMapper $roleMapper, array $options) |
||
79 | { |
||
80 | $this->ldap = $ldap; |
||
81 | $this->dispatcher = $dispatcher; |
||
82 | $this->roleMapper = $roleMapper; |
||
83 | $this->options = array_merge($this->options, $options); |
||
84 | } |
||
85 | |||
86 | /** |
||
87 | * {@inheritdoc} |
||
88 | */ |
||
89 | public function loadUserByUsername($username) |
||
90 | { |
||
91 | $this->dispatcher->dispatch(LoadUserEvent::BEFORE, new LoadUserEvent($username, $this->ldap->getDomainContext())); |
||
92 | $ldapUser = $this->getLdapUser('username', $username); |
||
93 | $user = $this->constructUserClass($ldapUser); |
||
94 | $this->roleMapper->setRoles($user); |
||
95 | $this->dispatcher->dispatch(LoadUserEvent::AFTER, new LoadUserEvent($username, $this->ldap->getDomainContext(), $user, $ldapUser)); |
||
0 ignored issues
–
show
|
|||
96 | |||
97 | return $user; |
||
0 ignored issues
–
show
The return type of
return $user; (LdapTools\Bundle\LdapToo...\User\LdapUserInterface ) is incompatible with the return type declared by the interface Symfony\Component\Securi...ace::loadUserByUsername of type Symfony\Component\Security\Core\User\UserInterface .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function ![]() |
|||
98 | } |
||
99 | |||
100 | /** |
||
101 | * {@inheritdoc} |
||
102 | */ |
||
103 | public function refreshUser(UserInterface $user) |
||
104 | { |
||
105 | if (!$user instanceof LdapUserInterface) { |
||
106 | throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user))); |
||
107 | } |
||
108 | $roles = $user->getRoles(); |
||
109 | |||
110 | if ($this->options['refresh_user_attributes']) { |
||
111 | $user = $this->constructUserClass($this->getLdapUser('guid', $user->getLdapGuid())); |
||
112 | } |
||
113 | if ($this->options['refresh_user_roles']) { |
||
114 | $this->roleMapper->setRoles($user); |
||
115 | } else { |
||
116 | $user->setRoles($roles); |
||
117 | } |
||
118 | |||
119 | return $user; |
||
0 ignored issues
–
show
The return type of
return $user; (LdapTools\Bundle\LdapToo...\User\LdapUserInterface ) is incompatible with the return type declared by the interface Symfony\Component\Securi...rInterface::refreshUser of type Symfony\Component\Security\Core\User\UserInterface .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function ![]() |
|||
120 | } |
||
121 | |||
122 | /** |
||
123 | * {@inheritdoc} |
||
124 | */ |
||
125 | public function supportsClass($class) |
||
126 | { |
||
127 | return is_subclass_of($class, LdapUserInterface::class); |
||
0 ignored issues
–
show
|
|||
128 | } |
||
129 | |||
130 | /** |
||
131 | * Search for, and return, the LDAP user by a specific attribute. |
||
132 | * |
||
133 | * @param string $attribute |
||
134 | * @param string $value |
||
135 | * @return LdapObject |
||
136 | */ |
||
137 | public function getLdapUser($attribute, $value) |
||
138 | { |
||
139 | try { |
||
140 | $query = $this->ldap->buildLdapQuery() |
||
141 | ->select($this->getAttributesToSelect()) |
||
142 | ->from($this->options['ldap_object_type']) |
||
143 | ->where([$attribute => $value]); |
||
144 | if (!is_null($this->options['search_base'])) { |
||
145 | $query->setBaseDn($this->options['search_base']); |
||
146 | } |
||
147 | return $query->getLdapQuery()->getSingleResult(); |
||
0 ignored issues
–
show
The expression
$query->getLdapQuery()->getSingleResult(); of type array|LdapTools\Object\LdapObject adds the type array to the return on line 147 which is incompatible with the return type documented by LdapTools\Bundle\LdapToo...erProvider::getLdapUser of type LdapTools\Object\LdapObject .
![]() |
|||
148 | } catch (EmptyResultException $e) { |
||
149 | throw new UsernameNotFoundException(sprintf('Username "%s" was not found.', $value)); |
||
150 | } catch (MultiResultException $e) { |
||
151 | throw new UsernameNotFoundException(sprintf('Multiple results for "%s" were found.', $value)); |
||
152 | } |
||
153 | } |
||
154 | |||
155 | /** |
||
156 | * Get all the attributes that should be selected for when querying LDAP. |
||
157 | * |
||
158 | * @return array |
||
159 | */ |
||
160 | protected function getAttributesToSelect() |
||
161 | { |
||
162 | return array_values(array_unique(array_filter(array_merge( |
||
163 | $this->defaultAttributes, |
||
164 | $this->options['additional_attributes'] |
||
165 | )))); |
||
166 | } |
||
167 | |||
168 | /** |
||
169 | * @param LdapObject $ldapObject |
||
170 | * @return LdapUserInterface |
||
171 | */ |
||
172 | protected function constructUserClass(LdapObject $ldapObject) |
||
173 | { |
||
174 | if (!$this->supportsClass($this->options['user'])) { |
||
175 | throw new UnsupportedUserException(sprintf( |
||
176 | 'The LDAP user provider class "%s" must implement "%s".', |
||
177 | $this->options['user'], |
||
178 | LdapUserInterface::class |
||
179 | )); |
||
180 | } |
||
181 | |||
182 | $errorMessage = 'Unable to instantiate user class "%s". Error was: %s'; |
||
183 | try { |
||
184 | /** @var LdapUserInterface $user */ |
||
185 | $user = new $this->options['user'](); |
||
186 | $user->setUsername($ldapObject->get('username')); |
||
187 | $user->setLdapGuid($ldapObject->get('guid')); |
||
188 | } catch (\Throwable $e) { |
||
0 ignored issues
–
show
The class
Throwable does not exist. Did you forget a USE statement, or did you not list all dependencies?
Scrutinizer analyzes your It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis. ![]() |
|||
189 | throw new UnsupportedUserException(sprintf($errorMessage, $this->options['user'], $e->getMessage())); |
||
190 | // Unlikely to help much in PHP 5.6, but oh well... |
||
191 | } catch (\Exception $e) { |
||
192 | throw new UnsupportedUserException(sprintf($errorMessage, $this->options['user'], $e->getMessage())); |
||
193 | } |
||
194 | // If the class also happens to extend the LdapTools LdapObject class, then set the attributes and type... |
||
195 | if ($user instanceof LdapObject) { |
||
196 | $this->hydrateLdapObjectUser($ldapObject, $user); |
||
197 | } |
||
198 | |||
199 | return $user; |
||
200 | } |
||
201 | |||
202 | /** |
||
203 | * @param LdapObject $ldapObject |
||
204 | * @param $user |
||
205 | */ |
||
206 | protected function hydrateLdapObjectUser(LdapObject $ldapObject, LdapObject $user) |
||
207 | { |
||
208 | $user->setBatchCollection(new BatchCollection($ldapObject->get('dn'))); |
||
209 | $user->refresh($ldapObject->toArray()); |
||
210 | |||
211 | // This is to avoid the constructor |
||
212 | $refObject = new \ReflectionObject($user); |
||
213 | $refProperty = $refObject->getProperty('type'); |
||
214 | $refProperty->setAccessible(true); |
||
215 | $refProperty->setValue($user, $this->options['ldap_object_type']); |
||
216 | } |
||
217 | } |
||
218 |
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: