From 8aca7b5e331d7cc933d41dec4f4533064ac77690 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Wed, 22 Jul 2026 11:54:33 +0200 Subject: [PATCH 1/2] feat: Allow to check user existence outside specific user backends Signed-off-by: Carl Schwan --- lib/private/User/Manager.php | 18 ++++++++++++++---- lib/public/IUserManager.php | 5 +++-- tests/Core/Command/User/AddTest.php | 5 +++++ 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/lib/private/User/Manager.php b/lib/private/User/Manager.php index e48304183bda8..546f95945e26a 100644 --- a/lib/private/User/Manager.php +++ b/lib/private/User/Manager.php @@ -121,15 +121,21 @@ public function clearBackends() { * @param string $uid * @return \OC\User\User|null Either the user or null if the specified user does not exist */ - public function get($uid) { + public function get($uid, array $excludeBackends = []) { if (is_null($uid) || $uid === '' || $uid === false) { return null; } - if (isset($this->cachedUsers[$uid])) { //check the cache first to prevent having to loop over the backends + + // check the cache first to prevent having to loop over the backends + if ($excludeBackends === [] && isset($this->cachedUsers[$uid])) { return $this->cachedUsers[$uid]; } $cachedBackend = $this->cache->get(sha1($uid)); + if (in_array($cachedBackend, $excludeBackends)) { + $cachedBackend = null; + } + if ($cachedBackend !== null && isset($this->backends[$cachedBackend])) { // Cache has the info of the user backend already, so ask that one directly $backend = $this->backends[$cachedBackend]; @@ -144,6 +150,10 @@ public function get($uid) { continue; } + if (in_array($i, $excludeBackends)) { + continue; + } + if ($backend->userExists($uid)) { // Hash $uid to ensure that only valid characters are used for the cache key $this->cache->set(sha1($uid), $i, 300); @@ -187,8 +197,8 @@ public function getUserObject($uid, $backend, $cacheUser = true) { * @param string $uid * @return bool */ - public function userExists($uid) { - $user = $this->get($uid); + public function userExists($uid, array $excludeBackends = []) { + $user = $this->get($uid, $excludeBackends); return ($user !== null); } diff --git a/lib/public/IUserManager.php b/lib/public/IUserManager.php index cd86d81cf6d0e..41888d2e049ca 100644 --- a/lib/public/IUserManager.php +++ b/lib/public/IUserManager.php @@ -77,13 +77,14 @@ public function get($uid); public function getDisplayName(string $uid): ?string; /** - * check if a user exists + * Check if a user exists. * * @param string $uid + * @param list $excludeBackends A list of IUserBackend::getBackendName() that need to be excluded from the search. * @return bool * @since 8.0.0 */ - public function userExists($uid); + public function userExists($uid, array $excludeBackends = []); /** * Check if the password is valid for the user diff --git a/tests/Core/Command/User/AddTest.php b/tests/Core/Command/User/AddTest.php index 902d073e74a27..84197ff9d2a3b 100644 --- a/tests/Core/Command/User/AddTest.php +++ b/tests/Core/Command/User/AddTest.php @@ -111,6 +111,11 @@ public function testAddEmail( $this->mailHelper->expects($isEmailValid && $shouldSendEmail ? static::once() : static::never()) ->method('sendMail'); + $this->consoleInput->method('getArgument') + ->willReturnMap([ + ['uid', 'JohnDoe'], + ]); + $this->consoleInput->method('getOption') ->will(static::returnValueMap([ ['generate-password', 'true'], From 7d64c9a84970a79b50b9c85731a3e165e49d2a53 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Thu, 6 Aug 2026 15:35:43 +0200 Subject: [PATCH 2/2] fix: Adapt tests Signed-off-by: Carl Schwan --- tests/lib/Repair/CleanTagsTest.php | 4 ++-- tests/lib/Share20/ManagerTest.php | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/lib/Repair/CleanTagsTest.php b/tests/lib/Repair/CleanTagsTest.php index 6fe7c6be9de0e..b7e59c091007c 100644 --- a/tests/lib/Repair/CleanTagsTest.php +++ b/tests/lib/Repair/CleanTagsTest.php @@ -103,8 +103,8 @@ public function testRun() { $this->userManager->expects($this->exactly(2)) ->method('userExists') ->willReturnMap([ - ['userExists', true], - ['TestRepairCleanTags', false], + ['userExists', [], true], + ['TestRepairCleanTags', [], false], ]); self::invokePrivate($this->repair, 'deleteOrphanTags', [$this->outputMock]); diff --git a/tests/lib/Share20/ManagerTest.php b/tests/lib/Share20/ManagerTest.php index 274cb7b62cdb6..eba1008070e31 100644 --- a/tests/lib/Share20/ManagerTest.php +++ b/tests/lib/Share20/ManagerTest.php @@ -986,8 +986,8 @@ public function testGeneralChecks($share, $exceptionMessage, $exception) { $thrown = null; $this->userManager->method('userExists')->willReturnMap([ - ['user0', true], - ['user1', true], + ['user0', [], true], + ['user1', [], true], ]); $this->groupManager->method('groupExists')->willReturnMap([ @@ -1030,8 +1030,8 @@ public function testGeneralCheckShareRoot() { $thrown = null; $this->userManager->method('userExists')->willReturnMap([ - ['user0', true], - ['user1', true], + ['user0', [], true], + ['user1', [], true], ]); $userFolder = $this->createMock(Folder::class);