diff options
author | blizzz <blizzz@arthur-schiwon.de> | 2019-06-21 11:08:59 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-06-21 11:08:59 +0200 |
commit | c1eff72bdf91df623bb377967270befd5c1594f9 (patch) | |
tree | ec79e8297f225212bebbf3ef64b1e2e6106f937f /apps | |
parent | 08734326da2bf8aef1856129ac547e6d4358d805 (diff) | |
parent | 29449f85b688deb1f103f3f67993475a040b4d80 (diff) | |
download | nextcloud-server-c1eff72bdf91df623bb377967270befd5c1594f9.tar.gz nextcloud-server-c1eff72bdf91df623bb377967270befd5c1594f9.zip |
Merge pull request #15964 from nextcloud/enh/noid/user-creation-options
Opt-in for generation userid, requiring email addresses
Diffstat (limited to 'apps')
-rw-r--r-- | apps/provisioning_api/lib/Controller/UsersController.php | 26 | ||||
-rw-r--r-- | apps/provisioning_api/tests/Controller/UsersControllerTest.php | 159 | ||||
-rw-r--r-- | apps/user_ldap/lib/Access.php | 2 | ||||
-rw-r--r-- | apps/user_ldap/lib/Group_LDAP.php | 2 | ||||
-rw-r--r-- | apps/user_ldap/lib/User_LDAP.php | 22 | ||||
-rw-r--r-- | apps/user_ldap/tests/User_LDAPTest.php | 19 |
6 files changed, 218 insertions, 12 deletions
diff --git a/apps/provisioning_api/lib/Controller/UsersController.php b/apps/provisioning_api/lib/Controller/UsersController.php index b993188c97e..252db66c35e 100644 --- a/apps/provisioning_api/lib/Controller/UsersController.php +++ b/apps/provisioning_api/lib/Controller/UsersController.php @@ -46,7 +46,6 @@ use OCP\IGroup; use OCP\IGroupManager; use OCP\ILogger; use OCP\IRequest; -use OCP\IUser; use OCP\IUserManager; use OCP\IUserSession; use OCP\L10N\IFactory; @@ -197,6 +196,21 @@ class UsersController extends AUserData { } /** + * @throws OCSException + */ + private function createNewUserId(): string { + $attempts = 0; + do { + $uidCandidate = $this->secureRandom->generate(10, ISecureRandom::CHAR_HUMAN_READABLE); + if (!$this->userManager->userExists($uidCandidate)) { + return $uidCandidate; + } + $attempts++; + } while ($attempts < 10); + throw new OCSException('Could not create non-existing user id', 111); + } + + /** * @PasswordConfirmationRequired * @NoAdminRequired * @@ -223,6 +237,10 @@ class UsersController extends AUserData { $isAdmin = $this->groupManager->isAdmin($user->getUID()); $subAdminManager = $this->groupManager->getSubAdmin(); + if(empty($userid) && $this->config->getAppValue('core', 'newUser.generateUserID', 'no') === 'yes') { + $userid = $this->createNewUserId(); + } + if ($this->userManager->userExists($userid)) { $this->logger->error('Failed addUser attempt: User already exists.', ['app' => 'ocs_api']); throw new OCSException('User already exists', 102); @@ -275,6 +293,10 @@ class UsersController extends AUserData { $generatePasswordResetToken = true; } + if ($email === '' && $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes') { + throw new OCSException('Required email address was not provided', 110); + } + try { $newUser = $this->userManager->createUser($userid, $password); $this->logger->info('Successful addUser call with userid: ' . $userid, ['app' => 'ocs_api']); @@ -315,7 +337,7 @@ class UsersController extends AUserData { } } - return new DataResponse(); + return new DataResponse(['UserID' => $userid]); } catch (HintException $e ) { $this->logger->logException($e, [ diff --git a/apps/provisioning_api/tests/Controller/UsersControllerTest.php b/apps/provisioning_api/tests/Controller/UsersControllerTest.php index 7a7f0144524..63f9d4c376a 100644 --- a/apps/provisioning_api/tests/Controller/UsersControllerTest.php +++ b/apps/provisioning_api/tests/Controller/UsersControllerTest.php @@ -356,7 +356,10 @@ class UsersControllerTest extends TestCase { ->with('adminUser') ->willReturn(true); - $this->assertEquals([], $this->api->addUser('NewUser', 'PasswordOfTheNewUser')->getData()); + $this->assertTrue(key_exists( + 'UserID', + $this->api->addUser('NewUser', 'PasswordOfTheNewUser')->getData() + )); } public function testAddUserSuccessfulWithDisplayName() { @@ -413,7 +416,149 @@ class UsersControllerTest extends TestCase { ->method('editUser') ->with('NewUser', 'display', 'DisplayNameOfTheNewUser'); - $this->assertEquals([], $api->addUser('NewUser', 'PasswordOfTheNewUser', 'DisplayNameOfTheNewUser')->getData()); + $this->assertTrue(key_exists( + 'UserID', + $api->addUser('NewUser', 'PasswordOfTheNewUser', 'DisplayNameOfTheNewUser')->getData() + )); + } + + public function testAddUserSuccessfulGenerateUserID() { + $this->config + ->expects($this->any()) + ->method('getAppValue') + ->willReturnCallback(function($appid, $key, $default) { + if($key === 'newUser.generateUserID') { + return 'yes'; + } + return null; + }); + $this->userManager + ->expects($this->any()) + ->method('userExists') + ->with($this->anything()) + ->will($this->returnValue(false)); + $this->userManager + ->expects($this->once()) + ->method('createUser') + ->with($this->anything(), 'PasswordOfTheNewUser'); + $this->logger + ->expects($this->once()) + ->method('info') + ->with($this->stringStartsWith('Successful addUser call with userid: '), ['app' => 'ocs_api']); + $loggedInUser = $this->getMockBuilder(IUser::class) + ->disableOriginalConstructor() + ->getMock(); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('adminUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('adminUser') + ->willReturn(true); + $this->secureRandom->expects($this->any()) + ->method('generate') + ->with(10) + ->willReturnCallback(function() { return (string)rand(1000000000, 9999999999); }); + + $this->assertTrue(key_exists( + 'UserID', + $this->api->addUser('', 'PasswordOfTheNewUser')->getData() + )); + } + + /** + * @expectedException \OCP\AppFramework\OCS\OCSException + * @expectedExceptionCode 111 + * @expectedExceptionMessage Could not create non-existing user id + */ + public function testAddUserFailedToGenerateUserID() { + $this->config + ->expects($this->any()) + ->method('getAppValue') + ->willReturnCallback(function($appid, $key, $default) { + if($key === 'newUser.generateUserID') { + return 'yes'; + } + return null; + }); + $this->userManager + ->expects($this->any()) + ->method('userExists') + ->with($this->anything()) + ->will($this->returnValue(true)); + $this->userManager + ->expects($this->never()) + ->method('createUser'); + $loggedInUser = $this->getMockBuilder(IUser::class) + ->disableOriginalConstructor() + ->getMock(); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('adminUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('adminUser') + ->willReturn(true); + + $this->api->addUser('', 'PasswordOfTheNewUser')->getData(); + } + + /** + * @expectedException \OCP\AppFramework\OCS\OCSException + * @expectedExceptionCode 110 + * @expectedExceptionMessage Required email address was not provided + */ + public function testAddUserEmailRequired() { + $this->config + ->expects($this->any()) + ->method('getAppValue') + ->willReturnCallback(function($appid, $key, $default) { + if($key === 'newUser.requireEmail') { + return 'yes'; + } + return null; + }); + $this->userManager + ->expects($this->once()) + ->method('userExists') + ->with('NewUser') + ->will($this->returnValue(false)); + $this->userManager + ->expects($this->never()) + ->method('createUser'); + $loggedInUser = $this->getMockBuilder(IUser::class) + ->disableOriginalConstructor() + ->getMock(); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('adminUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('adminUser') + ->willReturn(true); + + $this->assertTrue(key_exists( + 'UserID', + $this->api->addUser('NewUser', 'PasswordOfTheNewUser')->getData() + )); } public function testAddUserExistingGroup() { @@ -471,7 +616,10 @@ class UsersControllerTest extends TestCase { ['Added userid NewUser to group ExistingGroup', ['app' => 'ocs_api']] ); - $this->assertEquals([], $this->api->addUser('NewUser', 'PasswordOfTheNewUser', '', '', ['ExistingGroup'])->getData()); + $this->assertTrue(key_exists( + 'UserID', + $this->api->addUser('NewUser', 'PasswordOfTheNewUser', '', '', ['ExistingGroup'])->getData() + )); } /** @@ -689,7 +837,10 @@ class UsersControllerTest extends TestCase { ) ->willReturn(true); - $this->assertEquals([], $this->api->addUser('NewUser', 'PasswordOfTheNewUser', '', '', ['ExistingGroup1', 'ExistingGroup2'])->getData()); + $this->assertTrue(key_exists( + 'UserID', + $this->api->addUser('NewUser', 'PasswordOfTheNewUser', '', '', ['ExistingGroup1', 'ExistingGroup2'])->getData() + )); } /** diff --git a/apps/user_ldap/lib/Access.php b/apps/user_ldap/lib/Access.php index 6a074bbed2e..5db9dddf8fa 100644 --- a/apps/user_ldap/lib/Access.php +++ b/apps/user_ldap/lib/Access.php @@ -635,7 +635,7 @@ class Access extends LDAPUtility { return false; } - protected function mapAndAnnounceIfApplicable( + public function mapAndAnnounceIfApplicable( AbstractMapping $mapper, string $fdn, string $name, diff --git a/apps/user_ldap/lib/Group_LDAP.php b/apps/user_ldap/lib/Group_LDAP.php index 5b25979b2d2..d9059b2372f 100644 --- a/apps/user_ldap/lib/Group_LDAP.php +++ b/apps/user_ldap/lib/Group_LDAP.php @@ -110,7 +110,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD $members = $this->access->connection->getFromCache($cacheKeyMembers); if(!is_null($members)) { $this->cachedGroupMembers[$gid] = $members; - $isInGroup = in_array($userDN, $members); + $isInGroup = in_array($userDN, $members, true); $this->access->connection->writeToCache($cacheKey, $isInGroup); return $isInGroup; } diff --git a/apps/user_ldap/lib/User_LDAP.php b/apps/user_ldap/lib/User_LDAP.php index ada07aa53a9..5e06547533d 100644 --- a/apps/user_ldap/lib/User_LDAP.php +++ b/apps/user_ldap/lib/User_LDAP.php @@ -622,8 +622,26 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn if ($this->userPluginManager->implementsActions(Backend::CREATE_USER)) { if ($dn = $this->userPluginManager->createUser($username, $password)) { if (is_string($dn)) { - //updates user mapping - $this->access->dn2ocname($dn, $username, true); + // the NC user creation work flow requires a know user id up front + $uuid = $this->access->getUUID($dn, true); + if(is_string($uuid)) { + $this->access->mapAndAnnounceIfApplicable( + $this->access->getUserMapper(), + $dn, + $username, + $uuid, + true + ); + $this->access->cacheUserExists($username); + } else { + \OC::$server->getLogger()->warning( + 'Failed to map created LDAP user with userid {userid}, because UUID could not be determined', + [ + 'app' => 'user_ldap', + 'userid' => $username, + ] + ); + } } else { throw new \UnexpectedValueException("LDAP Plugin: Method createUser changed to return the user DN instead of boolean."); } diff --git a/apps/user_ldap/tests/User_LDAPTest.php b/apps/user_ldap/tests/User_LDAPTest.php index e4f7bb8b6d2..9b8bda2b808 100644 --- a/apps/user_ldap/tests/User_LDAPTest.php +++ b/apps/user_ldap/tests/User_LDAPTest.php @@ -35,6 +35,7 @@ use OC\User\Backend; use OC\User\Session; use OCA\User_LDAP\Access; use OCA\User_LDAP\Connection; +use OCA\User_LDAP\Mapping\AbstractMapping; use OCA\User_LDAP\Mapping\UserMapping; use OCA\User_LDAP\User\Manager; use OCA\User_LDAP\User\OfflineUser; @@ -1437,16 +1438,30 @@ class User_LDAPTest extends TestCase { } public function testCreateUserWithPlugin() { + $uid = 'alien6372'; + $uuid = '123-2345-36756-123-2345234-4431'; + $pwd = 'passwørd'; + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(Backend::CREATE_USER) ->willReturn(true); $this->pluginManager->expects($this->once()) ->method('createUser') - ->with('uid','password') + ->with($uid, $pwd) ->willReturn('result'); - $this->assertEquals($this->backend->createUser('uid', 'password'),true); + $this->access->expects($this->atLeastOnce()) + ->method('getUUID') + ->willReturn($uuid); + $this->access->expects($this->once()) + ->method('mapAndAnnounceIfApplicable') + ->with($this->isInstanceOf(AbstractMapping::class), $this->anything(), $uid, $uuid, true); + $this->access->expects($this->any()) + ->method('getUserMapper') + ->willReturn($this->createMock(AbstractMapping::class)); + + $this->assertEquals($this->backend->createUser($uid, $pwd),true); } public function testCreateUserFailing() { |