-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
feat(user_ldap): add function to find a user in ldap #56721
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
feat(user_ldap): add function to find a user in ldap #56721
Conversation
|
Hello there, We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process. Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6 Thank you for contributing to Nextcloud and we hope to hear from you soon! (If you believe you should not receive this message, you can add yourself to the blocklist.) |
blizzz
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the draft and the work on it @thpiron! I have a few remarks, the foundation is good!
| * | ||
| * @return IUser|null Returns a IUser if found in ldap using the configured ldap filter | ||
| * @throws \Exception if multiple users has been found (search query should not allow this) | ||
| */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the API, we note down @since annotations
| */ | |
| * @since 33.0.0 | |
| */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lib/public/LDAP/ILDAPProvider.php
Outdated
| * Search for a single user in ldap | ||
| * | ||
| * @return IUser|null Returns a IUser if found in ldap using the configured ldap filter | ||
| * @throws \Exception if multiple users has been found (search query should not allow this) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't throw the general \Exception but create a specific one, e.g. MultipleUsersReturnedException in the same namespace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
apps/user_ldap/lib/LDAPProvider.php
Outdated
| /** | ||
| * Search for a single user in ldap | ||
| * | ||
| * @return IUser|null Returns a IUser if found in ldap using the configured ldap filter | ||
| * @throws \Exception if multiple users has been found (search query should not allow this) | ||
| */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this docblock can be left out as it is provided by the interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * @return IUser |null Returns an IUser if found in LDAP using the configured LDAP filter, or null if no user is found. | ||
| */ | ||
| public function getUserFromCustomAttribute(string $filter, string $attribute, string $searchTerm): ?IUser { | ||
| if ($filter === null || $filter === '') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$filter cannot be null, as the signature demands a string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noted, I'll change this when reworking the interface function(s), keeping this as unresolved for now.
| public function getUserFromCustomAttribute(string $filter, string $attribute, string $searchTerm): ?IUser { | ||
| if ($filter === null || $filter === '') { | ||
| $searchTerm = $this->access->escapeFilterPart($searchTerm); | ||
| $filter = "($attribute=$searchTerm)"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The filter should always be an and-combination of the user list filter, otherwise it might pull in users without access.
(Technically the login filter would be more correct semantically, but it might not resolve on such setups by configuration to avoid direct login.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noted, I'll change this when reworking the interface function(s), keeping this as unresolved for now.
apps/user_ldap/lib/User_Proxy.php
Outdated
| foreach ($this->backends as $backend) { | ||
| if (method_exists($backend, 'getUserFromCustomAttribute')) { | ||
| $user = $backend->getUserFromCustomAttribute($filter, $attribute, $searchTerm); | ||
| return $user; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only the first LDAP configuration would be considered, as there is an immediate return statement. Also, the method_exists should not be necessary?
This can be solved in two ways:
- return the first result, that is not null. This might be faster, especially when there is not hit. But it might ignore users from other LDAP configurations, that then will not result in the exception.
- Run through all backends, and return that one user, if found, and throw the
MultipleUsersReturnedExceptionas soon as there are two results.
The broad search operations goes against all configurations as well, so going with #2 should be fine and not impacting the performance compared to the status quo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 is safer indeed, I only throw an exception if the the user are different, but I'm not sure if this makes sense, Maybe I should always throw the exception if two users found even if it's the same on nextcloud? I don't know if there is a safeguard somewhere to make this case impossible.
| * @return IUser|null Returns a IUser if found in ldap using the configured ldap filter | ||
| * @throws \Exception if multiple users has been found (search query should not allow this) | ||
| */ | ||
| public function findOneUser(string $filter, string $attribute, string $searchTerm): ?IUser; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The signature requires all parameters be set, contrary to the spec (it could have been written more precise, i take that) and I think contrary to your suggestion.
Two ways how to solve it:
- Use nullable and optional parameters:
?string $filter = null, ?string $attribute = null, ?string $searchTerm = null. The downside is that the usage does not become clear by the parameters and it is easy to use the methods wrongly. - Split it into two methods:
findOneUserByLdapFilter(string $filter): ?IUserandfindOneUserByAttributeValue(string $attribute, string $searchTerm): ?IUser.
I prefer the latter.
We can also go a step back and agree on one solution, either the filter (which actually is a filter part, could pronounce this as well and clarify that this is and-connected to the user list filter, as per my comment further above), or the attribute-value pair.
Due to
Other login backends that may rely on LDAP, like the SAML/SSO or OIDC backend, will get an additional configuration option to specify an attribute to which the received user id is being compared.
leaving out the filter (I am also a bit nervous about that: to easy to make a mistake) and only accepting the attribute name and the search value. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not happy with this function signature either, splitting it in to function is indeed better I think.
For most cases I think that only the attribute/searchTerm part would be enough, but maybe an having an "expert" config with the filter could be useful in complex configurations.
This would also be consistent with the way user_ldap config works, where it is almost always possible to edit the filter manually.
Maybe adding in the findOneUserByLdapFilter docstring that it should be used carefully by the other apps (as an advanced setting)?
Signed-off-by: Thibault Piron <[email protected]>
Signed-off-by: Thibault Piron <[email protected]>
Signed-off-by: Thibault Piron <[email protected]>
Signed-off-by: Thibault Piron <[email protected]>
Signed-off-by: Thibault Piron <[email protected]>
Signed-off-by: Thibault Piron <[email protected]>
084e1ab to
b430068
Compare
Summary
Add a findOneUser function to LDAPProvider
Checklist
3. to review, feature component)stable32)