-
-
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?
Changes from all commits
2f25d0b
c2d6df2
bdeb14b
fe25e82
375a69d
b430068
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,7 +14,10 @@ | |
| use OCA\User_LDAP\User\DeletedUsersIndex; | ||
| use OCA\User_LDAP\User\OfflineUser; | ||
| use OCA\User_LDAP\User\User; | ||
| use OCP\IUser; | ||
| use OCP\IUserBackend; | ||
| use OCP\IUserManager; | ||
| use OCP\LDAP\MultipleUsersReturnedException; | ||
| use OCP\Notification\IManager as INotificationManager; | ||
| use OCP\User\Backend\ICountMappedUsersBackend; | ||
| use OCP\User\Backend\ILimitAwareCountUsersBackend; | ||
|
|
@@ -29,6 +32,7 @@ public function __construct( | |
| protected UserPluginManager $userPluginManager, | ||
| protected LoggerInterface $logger, | ||
| protected DeletedUsersIndex $deletedUsersIndex, | ||
| protected IUserManager $userManager, | ||
| ) { | ||
| parent::__construct($access); | ||
| } | ||
|
|
@@ -643,4 +647,38 @@ public function setUserEnabled(string $uid, bool $enabled, callable $queryDataba | |
| public function getDisabledUserList(?int $limit = null, int $offset = 0, string $search = ''): array { | ||
| throw new \Exception('This is implemented directly in User_Proxy'); | ||
| } | ||
|
|
||
| /** | ||
| * Fetches one user from LDAP based on a filter or a custom attribute and search term. | ||
| * | ||
| * If no custom filter is provided or the filter is empty, it creates a simple equality filter with the given attribute. | ||
| * If a custom filter is provided, it uses that filter directly and the attribute and search term are ignored. | ||
| * | ||
| * @throws MultipleUsersReturnedException if multiple users have been found (search query should not allow this) | ||
| * | ||
| * @param string $filter The LDAP filter to use. If null or empty string, a default filter is constructed. | ||
| * @param string $attribute The LDAP attribute name to search against (e.g., 'mail', 'cn', 'uid'). | ||
| * @param string $searchTerm The search term to match against the attribute. Will be escaped for LDAP filter safety. | ||
| * | ||
| * @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 === '') { | ||
| $searchTerm = $this->access->escapeFilterPart($searchTerm); | ||
| $filter = "($attribute=$searchTerm)"; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.)
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
| } | ||
| $records = $this->access->searchUsers($filter, ['dn']); | ||
| if (count($records) === 1) { | ||
| $ldapUser = $this->access->userManager->get($records[0]['dn'][0]); | ||
| $user = $this->userManager->get($ldapUser->getUsername()); | ||
| return $user; | ||
| } elseif (count($records) > 1) { | ||
| $this->logger->error( | ||
| 'Multiple users found for filter: ' . $filter, | ||
| ['app' => 'user_ldap'] | ||
| ); | ||
| throw new MultipleUsersReturnedException(); | ||
| } | ||
| return null; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -6,6 +6,8 @@ | |||||||
| */ | ||||||||
| namespace OCP\LDAP; | ||||||||
|
|
||||||||
| use OCP\IUser; | ||||||||
|
|
||||||||
| /** | ||||||||
| * Interface ILDAPProvider | ||||||||
| * | ||||||||
|
|
@@ -151,4 +153,13 @@ public function getUserAttribute(string $uid, string $attribute): ?string; | |||||||
| * @since 22.0.0 | ||||||||
| */ | ||||||||
| public function getMultiValueUserAttribute(string $uid, string $attribute): array; | ||||||||
|
|
||||||||
| /** | ||||||||
| * Search for a single user in ldap | ||||||||
| * | ||||||||
| * @return IUser|null Returns a IUser if found in ldap using the configured ldap filter | ||||||||
| * @throws MultipleUsersReturnedException if multiple users has been found (search query should not allow this) | ||||||||
| * @since 33.0.0 | ||||||||
| */ | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the API, we note down
Suggested change
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||
| public function findOneUser(string $filter, string $attribute, string $searchTerm): ?IUser; | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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:
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
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?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. Maybe adding in the findOneUserByLdapFilter docstring that it should be used carefully by the other apps (as an advanced setting)? |
||||||||
| } | ||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| <?php | ||
|
|
||
| /** | ||
| * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors | ||
| * SPDX-License-Identifier: AGPL-3.0-or-later | ||
| */ | ||
| namespace OCP\LDAP; | ||
|
|
||
| /** | ||
| * Exception for a ldap search that unexpectedly returns multiple users. | ||
| * @since 33.0.0 | ||
| */ | ||
| class MultipleUsersReturnedException extends \Exception { | ||
| } |
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.
$filtercannot be null, as the signature demands astring.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.