Merge pull request #6509 from nextcloud/backport-5689
[stable12] LDAP: simplify returning the homePath and fixing #4117
This commit is contained in:
commit
9945d2f039
|
@ -134,6 +134,19 @@ class Manager {
|
||||||
return $user;
|
return $user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* removes a user entry from the cache
|
||||||
|
* @param $uid
|
||||||
|
*/
|
||||||
|
public function invalidate($uid) {
|
||||||
|
if(!isset($this->usersByUid[$uid])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$dn = $this->usersByUid[$uid]->getDN();
|
||||||
|
unset($this->usersByUid[$uid]);
|
||||||
|
unset($this->usersByDN[$dn]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief checks whether the Access instance has been set
|
* @brief checks whether the Access instance has been set
|
||||||
* @throws \Exception if Access has not been set
|
* @throws \Exception if Access has not been set
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
namespace OCA\User_LDAP\User;
|
namespace OCA\User_LDAP\User;
|
||||||
|
|
||||||
use OCA\User_LDAP\Mapping\UserMapping;
|
use OCA\User_LDAP\Mapping\UserMapping;
|
||||||
|
use OCP\IConfig;
|
||||||
|
use OCP\IDBConnection;
|
||||||
|
|
||||||
class OfflineUser {
|
class OfflineUser {
|
||||||
/**
|
/**
|
||||||
|
@ -60,11 +62,11 @@ class OfflineUser {
|
||||||
*/
|
*/
|
||||||
protected $hasActiveShares;
|
protected $hasActiveShares;
|
||||||
/**
|
/**
|
||||||
* @var \OCP\IConfig $config
|
* @var IConfig $config
|
||||||
*/
|
*/
|
||||||
protected $config;
|
protected $config;
|
||||||
/**
|
/**
|
||||||
* @var \OCP\IDBConnection $db
|
* @var IDBConnection $db
|
||||||
*/
|
*/
|
||||||
protected $db;
|
protected $db;
|
||||||
/**
|
/**
|
||||||
|
@ -74,11 +76,11 @@ class OfflineUser {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $ocName
|
* @param string $ocName
|
||||||
* @param \OCP\IConfig $config
|
* @param IConfig $config
|
||||||
* @param \OCP\IDBConnection $db
|
* @param IDBConnection $db
|
||||||
* @param \OCA\User_LDAP\Mapping\UserMapping $mapping
|
* @param \OCA\User_LDAP\Mapping\UserMapping $mapping
|
||||||
*/
|
*/
|
||||||
public function __construct($ocName, \OCP\IConfig $config, \OCP\IDBConnection $db, UserMapping $mapping) {
|
public function __construct($ocName, IConfig $config, IDBConnection $db, UserMapping $mapping) {
|
||||||
$this->ocName = $ocName;
|
$this->ocName = $ocName;
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
$this->db = $db;
|
$this->db = $db;
|
||||||
|
|
|
@ -41,19 +41,20 @@ use OCA\User_LDAP\Exceptions\NotOnLDAP;
|
||||||
use OCA\User_LDAP\User\OfflineUser;
|
use OCA\User_LDAP\User\OfflineUser;
|
||||||
use OCA\User_LDAP\User\User;
|
use OCA\User_LDAP\User\User;
|
||||||
use OCP\IConfig;
|
use OCP\IConfig;
|
||||||
|
use OCP\IUser;
|
||||||
use OCP\Notification\IManager as INotificationManager;
|
use OCP\Notification\IManager as INotificationManager;
|
||||||
use OCP\Util;
|
use OCP\Util;
|
||||||
|
|
||||||
class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserInterface, IUserLDAP {
|
class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserInterface, IUserLDAP {
|
||||||
/** @var string[] $homesToKill */
|
|
||||||
protected $homesToKill = array();
|
|
||||||
|
|
||||||
/** @var \OCP\IConfig */
|
/** @var \OCP\IConfig */
|
||||||
protected $ocConfig;
|
protected $ocConfig;
|
||||||
|
|
||||||
/** @var INotificationManager */
|
/** @var INotificationManager */
|
||||||
protected $notificationManager;
|
protected $notificationManager;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $currentUserInDeletionProcess;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Access $access
|
* @param Access $access
|
||||||
* @param \OCP\IConfig $ocConfig
|
* @param \OCP\IConfig $ocConfig
|
||||||
|
@ -63,6 +64,24 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
|
||||||
parent::__construct($access);
|
parent::__construct($access);
|
||||||
$this->ocConfig = $ocConfig;
|
$this->ocConfig = $ocConfig;
|
||||||
$this->notificationManager = $notificationManager;
|
$this->notificationManager = $notificationManager;
|
||||||
|
$this->registerHooks();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function registerHooks() {
|
||||||
|
Util::connectHook('OC_User','pre_deleteUser', $this, 'preDeleteUser');
|
||||||
|
Util::connectHook('OC_User','post_deleteUser', $this, 'postDeleteUser');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function preDeleteUser(array $param) {
|
||||||
|
$user = $param[0];
|
||||||
|
if(!$user instanceof IUser) {
|
||||||
|
throw new \RuntimeException('IUser expected');
|
||||||
|
}
|
||||||
|
$this->currentUserInDeletionProcess = $user->getUID();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function postDeleteUser() {
|
||||||
|
$this->currentUserInDeletionProcess = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -359,10 +378,8 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
|
||||||
|
|
||||||
//Get Home Directory out of user preferences so we can return it later,
|
//Get Home Directory out of user preferences so we can return it later,
|
||||||
//necessary for removing directories as done by OC_User.
|
//necessary for removing directories as done by OC_User.
|
||||||
$home = $this->ocConfig->getUserValue($uid, 'user_ldap', 'homePath', '');
|
|
||||||
$this->homesToKill[$uid] = $home;
|
|
||||||
$this->access->getUserMapper()->unmap($uid);
|
$this->access->getUserMapper()->unmap($uid);
|
||||||
|
$this->access->userManager->invalidate($uid);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,11 +392,6 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function getHome($uid) {
|
public function getHome($uid) {
|
||||||
if(isset($this->homesToKill[$uid]) && !empty($this->homesToKill[$uid])) {
|
|
||||||
//a deleted user who needs some clean up
|
|
||||||
return $this->homesToKill[$uid];
|
|
||||||
}
|
|
||||||
|
|
||||||
// user Exists check required as it is not done in user proxy!
|
// user Exists check required as it is not done in user proxy!
|
||||||
if(!$this->userExists($uid)) {
|
if(!$this->userExists($uid)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -391,16 +403,18 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
|
||||||
return $path;
|
return $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// early return path if it is a deleted user
|
||||||
$user = $this->access->userManager->get($uid);
|
$user = $this->access->userManager->get($uid);
|
||||||
if(is_null($user) || ($user instanceof OfflineUser && !$this->userExistsOnLDAP($user->getOCName()))) {
|
if($user instanceof OfflineUser) {
|
||||||
|
if($this->currentUserInDeletionProcess === $user->getUID()) {
|
||||||
|
return $user->getHomePath();
|
||||||
|
} else {
|
||||||
|
throw new NoUserException($uid . ' is not a valid user anymore');
|
||||||
|
}
|
||||||
|
} else if ($user === null) {
|
||||||
throw new NoUserException($uid . ' is not a valid user anymore');
|
throw new NoUserException($uid . ' is not a valid user anymore');
|
||||||
}
|
}
|
||||||
if($user instanceof OfflineUser) {
|
|
||||||
// apparently this user survived the userExistsOnLDAP check,
|
|
||||||
// we request the user instance again in order to retrieve a User
|
|
||||||
// instance instead
|
|
||||||
$user = $this->access->userManager->get($uid);
|
|
||||||
}
|
|
||||||
$path = $user->getHomePath();
|
$path = $user->getHomePath();
|
||||||
$this->access->cacheUserHome($uid, $path);
|
$this->access->cacheUserHome($uid, $path);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2016, ownCloud, Inc.
|
||||||
|
*
|
||||||
|
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||||
|
* @author Joas Schilling <coding@schilljs.com>
|
||||||
|
*
|
||||||
|
* @license AGPL-3.0
|
||||||
|
*
|
||||||
|
* This code is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OCA\User_LDAP\Tests\Integration\Lib\User;
|
||||||
|
|
||||||
|
use OC\User\NoUserException;
|
||||||
|
use OCA\User_LDAP\Jobs\CleanUp;
|
||||||
|
use OCA\User_LDAP\Mapping\UserMapping;
|
||||||
|
use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest;
|
||||||
|
use OCA\User_LDAP\User_LDAP;
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../../Bootstrap.php';
|
||||||
|
|
||||||
|
class IntegrationTestUserCleanUp extends AbstractIntegrationTest {
|
||||||
|
/** @var UserMapping */
|
||||||
|
protected $mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prepares the LDAP environment and sets up a test configuration for
|
||||||
|
* the LDAP backend.
|
||||||
|
*/
|
||||||
|
public function init() {
|
||||||
|
require(__DIR__ . '/../../setup-scripts/createExplicitUsers.php');
|
||||||
|
parent::init();
|
||||||
|
$this->mapping = new UserMapping(\OC::$server->getDatabaseConnection());
|
||||||
|
$this->mapping->clear();
|
||||||
|
$this->access->setUserMapper($this->mapping);
|
||||||
|
|
||||||
|
$userBackend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager());
|
||||||
|
\OC_User::useBackend($userBackend);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds a map entry for the user, so we know the username
|
||||||
|
*
|
||||||
|
* @param $dn
|
||||||
|
* @param $username
|
||||||
|
*/
|
||||||
|
private function prepareUser($dn, $username) {
|
||||||
|
// assigns our self-picked oc username to the dn
|
||||||
|
$this->mapping->map($dn, $username, 'fakeUUID-' . $username);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function deleteUserFromLDAP($dn) {
|
||||||
|
$cr = $this->connection->getConnectionResource();
|
||||||
|
ldap_delete($cr, $dn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tests whether a display name consisting of two parts is created correctly
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function case1() {
|
||||||
|
$username = 'alice1337';
|
||||||
|
$dn = 'uid=alice,ou=Users,' . $this->base;
|
||||||
|
$this->prepareUser($dn, $username);
|
||||||
|
|
||||||
|
$user = \OC::$server->getUserManager()->get($username);
|
||||||
|
if($user === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->deleteUserFromLDAP($dn);
|
||||||
|
|
||||||
|
$job = new CleanUp();
|
||||||
|
$job->run([]);
|
||||||
|
|
||||||
|
$user->delete();
|
||||||
|
|
||||||
|
return null === \OC::$server->getUserManager()->get($username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var string $host */
|
||||||
|
/** @var int $port */
|
||||||
|
/** @var string $adn */
|
||||||
|
/** @var string $apwd */
|
||||||
|
/** @var string $bdn */
|
||||||
|
$test = new IntegrationTestUserCleanUp($host, $port, $adn, $apwd, $bdn);
|
||||||
|
$test->init();
|
||||||
|
$test->run();
|
|
@ -295,7 +295,7 @@ class UserTest extends \Test\TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUpdateQuotaToNoneAllProvided() {
|
public function testUpdateQuotaToNoneAllProvided() {
|
||||||
list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) =
|
list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) =
|
||||||
$this->getTestInstances();
|
$this->getTestInstances();
|
||||||
|
|
||||||
list($access, $connection) =
|
list($access, $connection) =
|
||||||
|
|
|
@ -35,6 +35,7 @@ use OCA\User_LDAP\FilesystemHelper;
|
||||||
use OCA\User_LDAP\Helper;
|
use OCA\User_LDAP\Helper;
|
||||||
use OCA\User_LDAP\ILDAPWrapper;
|
use OCA\User_LDAP\ILDAPWrapper;
|
||||||
use OCA\User_LDAP\LogWrapper;
|
use OCA\User_LDAP\LogWrapper;
|
||||||
|
use OCA\User_LDAP\Mapping\UserMapping;
|
||||||
use OCA\User_LDAP\User\Manager;
|
use OCA\User_LDAP\User\Manager;
|
||||||
use OCA\User_LDAP\User\OfflineUser;
|
use OCA\User_LDAP\User\OfflineUser;
|
||||||
use OC\HintException;
|
use OC\HintException;
|
||||||
|
@ -59,7 +60,10 @@ use OCP\Notification\IManager as INotificationManager;
|
||||||
class User_LDAPTest extends TestCase {
|
class User_LDAPTest extends TestCase {
|
||||||
protected $backend;
|
protected $backend;
|
||||||
protected $access;
|
protected $access;
|
||||||
|
/** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
|
||||||
protected $configMock;
|
protected $configMock;
|
||||||
|
/** @var OfflineUser|\PHPUnit_Framework_MockObject_MockObject */
|
||||||
|
protected $offlineUser;
|
||||||
|
|
||||||
protected function setUp() {
|
protected function setUp() {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
@ -80,10 +84,9 @@ class User_LDAPTest extends TestCase {
|
||||||
|
|
||||||
$this->configMock = $this->createMock(IConfig::class);
|
$this->configMock = $this->createMock(IConfig::class);
|
||||||
|
|
||||||
$offlineUser = $this->getMockBuilder('\OCA\User_LDAP\User\OfflineUser')
|
$this->offlineUser = $this->createMock(OfflineUser::class);
|
||||||
->disableOriginalConstructor()
|
|
||||||
->getMock();
|
|
||||||
|
|
||||||
|
/** @var Manager|\PHPUnit_Framework_MockObject_MockObject $um */
|
||||||
$um = $this->getMockBuilder(Manager::class)
|
$um = $this->getMockBuilder(Manager::class)
|
||||||
->setMethods(['getDeletedUser'])
|
->setMethods(['getDeletedUser'])
|
||||||
->setConstructorArgs([
|
->setConstructorArgs([
|
||||||
|
@ -100,7 +103,7 @@ class User_LDAPTest extends TestCase {
|
||||||
|
|
||||||
$um->expects($this->any())
|
$um->expects($this->any())
|
||||||
->method('getDeletedUser')
|
->method('getDeletedUser')
|
||||||
->will($this->returnValue($offlineUser));
|
->will($this->returnValue($this->offlineUser));
|
||||||
|
|
||||||
$helper = new Helper(\OC::$server->getConfig());
|
$helper = new Helper(\OC::$server->getConfig());
|
||||||
|
|
||||||
|
@ -281,10 +284,11 @@ class User_LDAPTest extends TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDeleteUserSuccess() {
|
public function testDeleteUserSuccess() {
|
||||||
|
$uid = 'jeremy';
|
||||||
|
$home = '/var/vhome/jdings/';
|
||||||
|
|
||||||
$access = $this->getAccessMock();
|
$access = $this->getAccessMock();
|
||||||
$mapping = $this->getMockBuilder('\OCA\User_LDAP\Mapping\UserMapping')
|
$mapping = $this->createMock(UserMapping::class);
|
||||||
->disableOriginalConstructor()
|
|
||||||
->getMock();
|
|
||||||
$mapping->expects($this->once())
|
$mapping->expects($this->once())
|
||||||
->method('unmap')
|
->method('unmap')
|
||||||
->will($this->returnValue(true));
|
->will($this->returnValue(true));
|
||||||
|
@ -292,18 +296,20 @@ class User_LDAPTest extends TestCase {
|
||||||
->method('getUserMapper')
|
->method('getUserMapper')
|
||||||
->will($this->returnValue($mapping));
|
->will($this->returnValue($mapping));
|
||||||
|
|
||||||
$config = $this->createMock(IConfig::class);
|
$this->configMock->expects($this->any())
|
||||||
$config->expects($this->exactly(2))
|
|
||||||
->method('getUserValue')
|
->method('getUserValue')
|
||||||
->will($this->onConsecutiveCalls('1', '/var/vhome/jdings/'));
|
->with($uid, 'user_ldap', 'isDeleted')
|
||||||
|
->willReturn('1');
|
||||||
|
|
||||||
$backend = new UserLDAP($access, $config, $this->createMock(INotificationManager::class));
|
$this->offlineUser->expects($this->once())
|
||||||
|
->method('getHomePath')
|
||||||
|
->willReturn($home);
|
||||||
|
|
||||||
$result = $backend->deleteUser('jeremy');
|
$backend = new UserLDAP($access, $this->configMock, $this->createMock(INotificationManager::class));
|
||||||
|
|
||||||
|
$result = $backend->deleteUser($uid);
|
||||||
$this->assertTrue($result);
|
$this->assertTrue($result);
|
||||||
|
$this->assertSame($backend->getHome($uid), $home);
|
||||||
$home = $backend->getHome('jeremy');
|
|
||||||
$this->assertSame($home, '/var/vhome/jdings/');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -571,11 +577,11 @@ class User_LDAPTest extends TestCase {
|
||||||
$this->assertFalse($result);
|
$this->assertFalse($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDeleteUser() {
|
public function testDeleteUserExisting() {
|
||||||
$access = $this->getAccessMock();
|
$access = $this->getAccessMock();
|
||||||
$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class));
|
$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class));
|
||||||
|
|
||||||
//we do not support deleting users at all
|
//we do not support deleting existing users at all
|
||||||
$result = $backend->deleteUser('gunslinger');
|
$result = $backend->deleteUser('gunslinger');
|
||||||
$this->assertFalse($result);
|
$this->assertFalse($result);
|
||||||
}
|
}
|
||||||
|
@ -693,8 +699,10 @@ class User_LDAPTest extends TestCase {
|
||||||
* @expectedException \OC\User\NoUserException
|
* @expectedException \OC\User\NoUserException
|
||||||
*/
|
*/
|
||||||
public function testGetHomeDeletedUser() {
|
public function testGetHomeDeletedUser() {
|
||||||
|
$uid = 'newyorker';
|
||||||
|
|
||||||
$access = $this->getAccessMock();
|
$access = $this->getAccessMock();
|
||||||
$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class));
|
$backend = new UserLDAP($access, $this->configMock, $this->createMock(INotificationManager::class));
|
||||||
$this->prepareMockForUserExists($access);
|
$this->prepareMockForUserExists($access);
|
||||||
|
|
||||||
$access->connection->expects($this->any())
|
$access->connection->expects($this->any())
|
||||||
|
@ -710,9 +718,7 @@ class User_LDAPTest extends TestCase {
|
||||||
->method('readAttribute')
|
->method('readAttribute')
|
||||||
->will($this->returnValue([]));
|
->will($this->returnValue([]));
|
||||||
|
|
||||||
$userMapper = $this->getMockBuilder('\OCA\User_LDAP\Mapping\UserMapping')
|
$userMapper = $this->createMock(UserMapping::class);
|
||||||
->disableOriginalConstructor()
|
|
||||||
->getMock();
|
|
||||||
|
|
||||||
$access->expects($this->any())
|
$access->expects($this->any())
|
||||||
->method('getUserMapper')
|
->method('getUserMapper')
|
||||||
|
@ -722,9 +728,13 @@ class User_LDAPTest extends TestCase {
|
||||||
->method('getUserValue')
|
->method('getUserValue')
|
||||||
->will($this->returnValue(true));
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
//no path at all – triggers OC default behaviour
|
$this->offlineUser->expects($this->never())
|
||||||
$result = $backend->getHome('newyorker');
|
->method('getHomePath');
|
||||||
$this->assertFalse($result);
|
$this->offlineUser->expects($this->once())
|
||||||
|
->method('getUID')
|
||||||
|
->willReturn($uid);
|
||||||
|
|
||||||
|
$backend->getHome($uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function prepareAccessForGetDisplayName(&$access) {
|
private function prepareAccessForGetDisplayName(&$access) {
|
||||||
|
|
Loading…
Reference in New Issue