diff options
-rw-r--r-- | apps/user_ldap/css/settings.css | 5 | ||||
-rw-r--r-- | apps/user_ldap/js/wizard/wizardTabAdvanced.js | 15 | ||||
-rw-r--r-- | apps/user_ldap/lib/Access.php | 29 | ||||
-rw-r--r-- | apps/user_ldap/lib/Configuration.php | 4 | ||||
-rw-r--r-- | apps/user_ldap/lib/Connection.php | 1 | ||||
-rw-r--r-- | apps/user_ldap/lib/Exceptions/ConstraintViolationException.php | 26 | ||||
-rw-r--r-- | apps/user_ldap/lib/ILDAPWrapper.php | 9 | ||||
-rw-r--r-- | apps/user_ldap/lib/LDAP.php | 17 | ||||
-rw-r--r-- | apps/user_ldap/lib/User_LDAP.php | 32 | ||||
-rw-r--r-- | apps/user_ldap/lib/User_Proxy.php | 11 | ||||
-rw-r--r-- | apps/user_ldap/templates/settings.php | 2 | ||||
-rw-r--r-- | apps/user_ldap/tests/AccessTest.php | 109 | ||||
-rw-r--r-- | apps/user_ldap/tests/LDAPTest.php | 50 | ||||
-rw-r--r-- | apps/user_ldap/tests/User_LDAPTest.php | 142 | ||||
-rw-r--r-- | apps/user_ldap/tests/User_ProxyTest.php | 61 |
15 files changed, 507 insertions, 6 deletions
diff --git a/apps/user_ldap/css/settings.css b/apps/user_ldap/css/settings.css index c99efc48c5b..129064ff8b0 100644 --- a/apps/user_ldap/css/settings.css +++ b/apps/user_ldap/css/settings.css @@ -3,6 +3,11 @@ width: 85%; } +.inlinetable { + display: inline-table; + vertical-align: bottom; +} + .tablerow { display: table-row; white-space: nowrap; diff --git a/apps/user_ldap/js/wizard/wizardTabAdvanced.js b/apps/user_ldap/js/wizard/wizardTabAdvanced.js index d1e5002d40a..d0922bbff32 100644 --- a/apps/user_ldap/js/wizard/wizardTabAdvanced.js +++ b/apps/user_ldap/js/wizard/wizardTabAdvanced.js @@ -95,6 +95,10 @@ OCA = OCA || {}; $element: $('#ldap_paging_size'), setMethod: 'setPagingSize' }, + ldap_turn_on_pwd_change: { + $element: $('#ldap_turn_on_pwd_change'), + setMethod: 'setPasswordChangeEnabled' + }, //Special Attributes ldap_quota_attr: { @@ -288,6 +292,17 @@ OCA = OCA || {}; setPagingSize: function(size) { this.setElementValue(this.managedItems.ldap_paging_size.$element, size); }, + + /** + * sets whether the password changes per user should be enabled + * + * @param {string} doPasswordChange contains an int + */ + setPasswordChangeEnabled: function(doPasswordChange) { + this.setElementValue( + this.managedItems.ldap_turn_on_pwd_change.$element, doPasswordChange + ); + }, /** * sets the email attribute diff --git a/apps/user_ldap/lib/Access.php b/apps/user_ldap/lib/Access.php index e7facd80ae0..d88378c1888 100644 --- a/apps/user_ldap/lib/Access.php +++ b/apps/user_ldap/lib/Access.php @@ -40,6 +40,8 @@ namespace OCA\User_LDAP; +use OC\HintException; +use OCA\User_LDAP\Exceptions\ConstraintViolationException; use OCA\User_LDAP\User\IUserTools; use OCA\User_LDAP\User\Manager; use OCA\User_LDAP\User\OfflineUser; @@ -221,6 +223,33 @@ class Access extends LDAPUtility implements IUserTools { \OCP\Util::writeLog('user_ldap', 'Requested attribute '.$attr.' not found for '.$dn, \OCP\Util::DEBUG); return false; } + + /** + * Set password for an LDAP user identified by a DN + * + * @param string $userDN the user in question + * @param string $password the new password + * @return bool + * @throws HintException + * @throws \Exception + */ + public function setPassword($userDN, $password) { + if(intval($this->connection->turnOnPasswordChange) !== 1) { + throw new \Exception('LDAP password changes are disabled.'); + } + $cr = $this->connection->getConnectionResource(); + if(!$this->ldap->isResource($cr)) { + //LDAP not available + \OCP\Util::writeLog('user_ldap', 'LDAP resource not available.', \OCP\Util::DEBUG); + return false; + } + + try { + return $this->ldap->modReplace($cr, $userDN, $password); + } catch(ConstraintViolationException $e) { + throw new HintException('Password change rejected.', \OC::$server->getL10N('user_ldap')->t('Password change rejected. Hint: ').$e->getMessage(), $e->getCode()); + } + } /** * checks whether the given attributes value is probably a DN diff --git a/apps/user_ldap/lib/Configuration.php b/apps/user_ldap/lib/Configuration.php index 80b353360c3..eb4fcd3fbe6 100644 --- a/apps/user_ldap/lib/Configuration.php +++ b/apps/user_ldap/lib/Configuration.php @@ -11,6 +11,7 @@ * @author Lukas Reschke <lukas@statuscode.ch> * @author Morris Jobke <hey@morrisjobke.de> * @author Robin McCorkell <robin@mccorkell.me.uk> + * @author Roger Szabo <roger.szabo@web.de> * * @license AGPL-3.0 * @@ -90,6 +91,7 @@ class Configuration { 'lastJpegPhotoLookup' => null, 'ldapNestedGroups' => false, 'ldapPagingSize' => null, + 'turnOnPasswordChange' => false, 'ldapDynamicGroupMemberURL' => null, ); @@ -449,6 +451,7 @@ class Configuration { 'last_jpegPhoto_lookup' => 0, 'ldap_nested_groups' => 0, 'ldap_paging_size' => 500, + 'ldap_turn_on_pwd_change' => 0, 'ldap_experienced_admin' => 0, 'ldap_dynamic_group_member_url' => '', ); @@ -505,6 +508,7 @@ class Configuration { 'last_jpegPhoto_lookup' => 'lastJpegPhotoLookup', 'ldap_nested_groups' => 'ldapNestedGroups', 'ldap_paging_size' => 'ldapPagingSize', + 'ldap_turn_on_pwd_change' => 'turnOnPasswordChange', 'ldap_experienced_admin' => 'ldapExperiencedAdmin', 'ldap_dynamic_group_member_url' => 'ldapDynamicGroupMemberURL', ); diff --git a/apps/user_ldap/lib/Connection.php b/apps/user_ldap/lib/Connection.php index 6028486e8bb..d74afa42fe8 100644 --- a/apps/user_ldap/lib/Connection.php +++ b/apps/user_ldap/lib/Connection.php @@ -42,6 +42,7 @@ use OC\ServerNotAvailableException; * @property string ldapUserFilter * @property string ldapUserDisplayName * @property string ldapUserDisplayName2 + * @property boolean turnOnPasswordChange * @property boolean hasPagedResultSupport * @property string[] ldapBaseUsers * @property int|string ldapPagingSize holds an integer diff --git a/apps/user_ldap/lib/Exceptions/ConstraintViolationException.php b/apps/user_ldap/lib/Exceptions/ConstraintViolationException.php new file mode 100644 index 00000000000..997b01b2d4e --- /dev/null +++ b/apps/user_ldap/lib/Exceptions/ConstraintViolationException.php @@ -0,0 +1,26 @@ +<?php +/** + * @copyright Copyright (c) 2016 Roger Szabo <roger.szabo@web.de> + * + * @author Roger Szabo <roger.szabo@web.de> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\User_LDAP\Exceptions; + +class ConstraintViolationException extends \Exception {} diff --git a/apps/user_ldap/lib/ILDAPWrapper.php b/apps/user_ldap/lib/ILDAPWrapper.php index 4fd3b31428a..e2089fa8a47 100644 --- a/apps/user_ldap/lib/ILDAPWrapper.php +++ b/apps/user_ldap/lib/ILDAPWrapper.php @@ -163,6 +163,15 @@ interface ILDAPWrapper { * @return resource|false an LDAP search result resource, false on error */ public function search($link, $baseDN, $filter, $attr, $attrsOnly = 0, $limit = 0); + + /** + * Replace the value of a userPassword by $password + * @param resource $link LDAP link resource + * @param string $userDN the DN of the user whose password is to be replaced + * @param string $password the new value for the userPassword + * @return bool true on success, false otherwise + */ + public function modReplace($link, $userDN, $password); /** * Sets the value of the specified option to be $value diff --git a/apps/user_ldap/lib/LDAP.php b/apps/user_ldap/lib/LDAP.php index 74d83e4ab4f..cac09f25993 100644 --- a/apps/user_ldap/lib/LDAP.php +++ b/apps/user_ldap/lib/LDAP.php @@ -9,6 +9,7 @@ * @author Lukas Reschke <lukas@statuscode.ch> * @author Morris Jobke <hey@morrisjobke.de> * @author Robin McCorkell <robin@mccorkell.me.uk> + * @author Roger Szabo <roger.szabo@web.de> * * @license AGPL-3.0 * @@ -29,6 +30,7 @@ namespace OCA\User_LDAP; use OC\ServerNotAvailableException; +use OCA\User_LDAP\Exceptions\ConstraintViolationException; class LDAP implements ILDAPWrapper { protected $curFunc = ''; @@ -194,6 +196,16 @@ class LDAP implements ILDAPWrapper { /** * @param LDAP $link + * @param string $userDN + * @param string $password + * @return bool + */ + public function modReplace($link, $userDN, $password) { + return $this->invokeLDAPMethod('mod_replace', $link, $userDN, array('userPassword' => $password)); + } + + /** + * @param LDAP $link * @param string $option * @param int $value * @return bool|mixed @@ -248,7 +260,7 @@ class LDAP implements ILDAPWrapper { /** * @return mixed */ - private function invokeLDAPMethod() { + protected function invokeLDAPMethod() { $arguments = func_get_args(); $func = 'ldap_' . array_shift($arguments); if(function_exists($func)) { @@ -288,6 +300,9 @@ class LDAP implements ILDAPWrapper { throw new \Exception('LDAP authentication method rejected', $errorCode); } else if ($errorCode === 1) { throw new \Exception('LDAP Operations error', $errorCode); + } else if ($errorCode === 19) { + ldap_get_option($this->curArgs[0], LDAP_OPT_ERROR_STRING, $extended_error); + throw new ConstraintViolationException(!empty($extended_error)?$extended_error:$errorMsg, $errorCode); } else { \OCP\Util::writeLog('user_ldap', 'LDAP error '.$errorMsg.' (' . diff --git a/apps/user_ldap/lib/User_LDAP.php b/apps/user_ldap/lib/User_LDAP.php index 9f2468bcc85..8dfde2d8148 100644 --- a/apps/user_ldap/lib/User_LDAP.php +++ b/apps/user_ldap/lib/User_LDAP.php @@ -35,6 +35,7 @@ namespace OCA\User_LDAP; +use OC\User\Backend; use OC\User\NoUserException; use OCA\User_LDAP\Exceptions\NotOnLDAP; use OCA\User_LDAP\User\OfflineUser; @@ -175,6 +176,26 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn } /** + * Set password + * @param string $uid The username + * @param string $password The new password + * @return bool + */ + public function setPassword($uid, $password) { + $user = $this->access->userManager->get($uid); + + if(!$user instanceof User) { + throw new \Exception('LDAP setPassword: Could not get user object for uid ' . $uid . + '. Maybe the LDAP entry has no set display name attribute?'); + } + if($user->getUsername() !== false) { + return $this->access->setPassword($user->getDN(), $password); + } + + return false; + } + + /** * Get a list of all users * * @param string $search @@ -449,11 +470,12 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn * compared with OC_USER_BACKEND_CREATE_USER etc. */ public function implementsActions($actions) { - return (bool)((\OC\User\Backend::CHECK_PASSWORD - | \OC\User\Backend::GET_HOME - | \OC\User\Backend::GET_DISPLAYNAME - | \OC\User\Backend::PROVIDE_AVATAR - | \OC\User\Backend::COUNT_USERS) + return (bool)((Backend::CHECK_PASSWORD + | Backend::GET_HOME + | Backend::GET_DISPLAYNAME + | Backend::PROVIDE_AVATAR + | Backend::COUNT_USERS + | ((intval($this->access->connection->turnOnPasswordChange) === 1)?(Backend::SET_PASSWORD):0)) & $actions); } diff --git a/apps/user_ldap/lib/User_Proxy.php b/apps/user_ldap/lib/User_Proxy.php index cced469a7ae..2cdf401880e 100644 --- a/apps/user_ldap/lib/User_Proxy.php +++ b/apps/user_ldap/lib/User_Proxy.php @@ -262,6 +262,17 @@ class User_Proxy extends Proxy implements \OCP\IUserBackend, \OCP\UserInterface, public function deleteUser($uid) { return $this->handleRequest($uid, 'deleteUser', array($uid)); } + + /** + * Set password + * @param string $uid The username + * @param string $password The new password + * @return bool + * + */ + public function setPassword($uid, $password) { + return $this->handleRequest($uid, 'setPassword', array($uid, $password)); + } /** * @return bool diff --git a/apps/user_ldap/templates/settings.php b/apps/user_ldap/templates/settings.php index eb4c7b99127..e53456c703c 100644 --- a/apps/user_ldap/templates/settings.php +++ b/apps/user_ldap/templates/settings.php @@ -101,6 +101,8 @@ style('user_ldap', 'settings'); <p><label for="ldap_dynamic_group_member_url"><?php p($l->t('Dynamic Group Member URL'));?></label><input type="text" id="ldap_dynamic_group_member_url" name="ldap_dynamic_group_member_url" title="<?php p($l->t('The LDAP attribute that on group objects contains an LDAP search URL that determines what objects belong to the group. (An empty setting disables dynamic group membership functionality.)'));?>" data-default="<?php p($_['ldap_dynamic_group_member_url_default']); ?>" /></p> <p><label for="ldap_nested_groups"><?php p($l->t('Nested Groups'));?></label><input type="checkbox" id="ldap_nested_groups" name="ldap_nested_groups" value="1" data-default="<?php p($_['ldap_nested_groups_default']); ?>" title="<?php p($l->t('When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)'));?>" /></p> <p><label for="ldap_paging_size"><?php p($l->t('Paging chunksize'));?></label><input type="number" id="ldap_paging_size" name="ldap_paging_size" title="<?php p($l->t('Chunksize used for paged LDAP searches that may return bulky results like user or group enumeration. (Setting it 0 disables paged LDAP searches in those situations.)'));?>" data-default="<?php p($_['ldap_paging_size_default']); ?>" /></p> + <p><label for="ldap_turn_on_pwd_change"><?php p($l->t('Enable LDAP password changes per user'));?></label><span class="inlinetable"><span class="tablerow left"><input type="checkbox" id="ldap_turn_on_pwd_change" name="ldap_turn_on_pwd_change" value="1" data-default="<?php p($_['ldap_turn_on_pwd_change_default']); ?>" title="<?php p($l->t('Allow LDAP users to change their password and allow Super Administrators and Group Administrators to change the password of their LDAP users. Only works when access control policies are configured accordingly on the LDAP server. As passwords are sent in plaintext to the LDAP server, transport encryption must be used and password hashing should be configured on the LDAP server.'));?>" /><span class="tablecell"><?php p($l->t('(New password is sent as plain text to LDAP)'));?></span></span> + </span><br/></p> </div> <h3><?php p($l->t('Special Attributes'));?></h3> <div> diff --git a/apps/user_ldap/tests/AccessTest.php b/apps/user_ldap/tests/AccessTest.php index d7d04e31d08..271e8eb605b 100644 --- a/apps/user_ldap/tests/AccessTest.php +++ b/apps/user_ldap/tests/AccessTest.php @@ -1,12 +1,14 @@ <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. + * @copyright Copyright (c) 2016, Lukas Reschke <lukas@statuscode.ch> * * @author Andreas Fischer <bantu@owncloud.com> * @author Arthur Schiwon <blizzz@arthur-schiwon.de> * @author Joas Schilling <coding@schilljs.com> * @author Morris Jobke <hey@morrisjobke.de> * @author Thomas Müller <thomas.mueller@tmit.eu> + * @author Lukas Reschke <lukas@statuscode.ch> * * @license AGPL-3.0 * @@ -28,9 +30,11 @@ namespace OCA\User_LDAP\Tests; use OCA\User_LDAP\Access; use OCA\User_LDAP\Connection; +use OCA\User_LDAP\Exceptions\ConstraintViolationException; use OCA\User_LDAP\FilesystemHelper; use OCA\User_LDAP\Helper; use OCA\User_LDAP\ILDAPWrapper; +use OCA\User_LDAP\LDAP; use OCA\User_LDAP\LogWrapper; use OCA\User_LDAP\User\Manager; use OCP\IAvatarManager; @@ -47,6 +51,31 @@ use OCP\IUserManager; * @package OCA\User_LDAP\Tests */ class AccessTest extends \Test\TestCase { + /** @var Connection|\PHPUnit_Framework_MockObject_MockObject */ + private $connection; + /** @var LDAP|\PHPUnit_Framework_MockObject_MockObject */ + private $ldap; + /** @var Manager|\PHPUnit_Framework_MockObject_MockObject */ + private $userManager; + /** @var Helper|\PHPUnit_Framework_MockObject_MockObject */ + private $helper; + /** @var Access */ + private $access; + + public function setUp() { + $this->connection = $this->createMock(Connection::class); + $this->ldap = $this->createMock(LDAP::class); + $this->userManager = $this->createMock(Manager::class); + $this->helper = $this->createMock(Helper::class); + + $this->access = new Access( + $this->connection, + $this->ldap, + $this->userManager, + $this->helper + ); + } + private function getConnectorAndLdapMock() { $lw = $this->createMock(ILDAPWrapper::class); $connector = $this->getMockBuilder(Connection::class) @@ -317,4 +346,84 @@ class AccessTest extends \Test\TestCase { $values = $access->readAttribute('uid=whoever,dc=example,dc=org', $attribute); $this->assertSame($values[0], strtolower($dnFromServer)); } + + /** + * @expectedException \Exception + * @expectedExceptionMessage LDAP password changes are disabled + */ + public function testSetPasswordWithDisabledChanges() { + $this->connection + ->method('__get') + ->willReturn(false); + + $this->access->setPassword('CN=foo', 'MyPassword'); + } + + public function testSetPasswordWithLdapNotAvailable() { + $this->connection + ->method('__get') + ->willReturn(true); + $connection = $this->createMock(LDAP::class); + $this->connection + ->expects($this->once()) + ->method('getConnectionResource') + ->willReturn($connection); + $this->ldap + ->expects($this->once()) + ->method('isResource') + ->with($connection) + ->willReturn(false); + + $this->assertFalse($this->access->setPassword('CN=foo', 'MyPassword')); + } + + /** + * @expectedException \OC\HintException + * @expectedExceptionMessage Password change rejected. + */ + public function testSetPasswordWithRejectedChange() { + $this->connection + ->method('__get') + ->willReturn(true); + $connection = $this->createMock(LDAP::class); + $this->connection + ->expects($this->once()) + ->method('getConnectionResource') + ->willReturn($connection); + $this->ldap + ->expects($this->once()) + ->method('isResource') + ->with($connection) + ->willReturn(true); + $this->ldap + ->expects($this->once()) + ->method('modReplace') + ->with($connection, 'CN=foo', 'MyPassword') + ->willThrowException(new ConstraintViolationException()); + + $this->access->setPassword('CN=foo', 'MyPassword'); + } + + public function testSetPassword() { + $this->connection + ->method('__get') + ->willReturn(true); + $connection = $this->createMock(LDAP::class); + $this->connection + ->expects($this->once()) + ->method('getConnectionResource') + ->willReturn($connection); + $this->ldap + ->expects($this->once()) + ->method('isResource') + ->with($connection) + ->willReturn(true); + $this->ldap + ->expects($this->once()) + ->method('modReplace') + ->with($connection, 'CN=foo', 'MyPassword') + ->willReturn(true); + + $this->assertTrue($this->access->setPassword('CN=foo', 'MyPassword')); + } } diff --git a/apps/user_ldap/tests/LDAPTest.php b/apps/user_ldap/tests/LDAPTest.php new file mode 100644 index 00000000000..1ac8cef12de --- /dev/null +++ b/apps/user_ldap/tests/LDAPTest.php @@ -0,0 +1,50 @@ +<?php +/** + * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\User_LDAP\Tests; + +use OCA\User_LDAP\LDAP; +use Test\TestCase; + +class LDAPTest extends TestCase { + /** @var LDAP|\PHPUnit_Framework_MockObject_MockObject */ + private $ldap; + + public function setUp() { + parent::setUp(); + $this->ldap = $this->getMockBuilder(LDAP::class) + ->setMethods(['invokeLDAPMethod']) + ->getMock(); + } + + public function testModReplace() { + $link = $this->createMock(LDAP::class); + $userDN = 'CN=user'; + $password = 'MyPassword'; + $this->ldap + ->expects($this->once()) + ->method('invokeLDAPMethod') + ->with('mod_replace', $link, $userDN, array('userPassword' => $password)) + ->willReturn(true); + + $this->assertTrue($this->ldap->modReplace($link, $userDN, $password)); + } +} diff --git a/apps/user_ldap/tests/User_LDAPTest.php b/apps/user_ldap/tests/User_LDAPTest.php index 05837097929..606eff4e7a7 100644 --- a/apps/user_ldap/tests/User_LDAPTest.php +++ b/apps/user_ldap/tests/User_LDAPTest.php @@ -9,6 +9,7 @@ * @author Morris Jobke <hey@morrisjobke.de> * @author Robin McCorkell <robin@mccorkell.me.uk> * @author Thomas Müller <thomas.mueller@tmit.eu> + * @author Roger Szabo <roger.szabo@web.de> * * @license AGPL-3.0 * @@ -36,8 +37,10 @@ use OCA\User_LDAP\ILDAPWrapper; use OCA\User_LDAP\LogWrapper; use OCA\User_LDAP\User\Manager; use OCA\User_LDAP\User\OfflineUser; +use OC\HintException; use OCA\User_LDAP\User\User; use OCA\User_LDAP\User_LDAP as UserLDAP; +use OCA\User_LDAP\User_LDAP; use OCP\IAvatarManager; use OCP\IConfig; use OCP\IDBConnection; @@ -958,5 +961,144 @@ class User_LDAPTest extends TestCase { // and once again to verify that caching works $backend->loginName2UserName($loginName); } + + /** + * Prepares the Access mock for setPassword tests + * @param \OCA\User_LDAP\Access|\PHPUnit_Framework_MockObject_MockObject $access mock + * @return void + */ + private function prepareAccessForSetPassword(&$access, $enablePasswordChange = true) { + $access->connection->expects($this->any()) + ->method('__get') + ->will($this->returnCallback(function($name) use (&$enablePasswordChange) { + if($name === 'ldapLoginFilter') { + return '%uid'; + } + if($name === 'turnOnPasswordChange') { + return $enablePasswordChange?1:0; + } + return null; + })); + + $access->connection->expects($this->any()) + ->method('getFromCache') + ->will($this->returnCallback(function($uid) { + if($uid === 'userExists'.'roland') { + return true; + } + return null; + })); + + $access->expects($this->any()) + ->method('fetchListOfUsers') + ->will($this->returnCallback(function($filter) { + if($filter === 'roland') { + return array(array('dn' => ['dnOfRoland,dc=test'])); + } + return array(); + })); + + $access->expects($this->any()) + ->method('fetchUsersByLoginName') + ->will($this->returnCallback(function($uid) { + if($uid === 'roland') { + return array(array('dn' => ['dnOfRoland,dc=test'])); + } + return array(); + })); + + $access->expects($this->any()) + ->method('dn2username') + ->with($this->equalTo('dnOfRoland,dc=test')) + ->will($this->returnValue('roland')); + $access->expects($this->any()) + ->method('stringResemblesDN') + ->with($this->equalTo('dnOfRoland,dc=test')) + ->will($this->returnValue(true)); + + $access->expects($this->any()) + ->method('setPassword') + ->will($this->returnCallback(function($uid, $password) { + if(strlen($password) <= 5) { + throw new HintException('Password fails quality checking policy', '', 19); + } + return true; + })); + } + + /** + * @expectedException \OC\HintException + * @expectedExceptionMessage Password fails quality checking policy + */ + public function testSetPasswordInvalid() { + $access = $this->getAccessMock(); + + $this->prepareAccessForSetPassword($access); + $backend = new UserLDAP($access, $this->createMock(IConfig::class)); + \OC_User::useBackend($backend); + + $this->assertTrue(\OC_User::setPassword('roland', 'dt')); + } + + public function testSetPasswordValid() { + $access = $this->getAccessMock(); + + $this->prepareAccessForSetPassword($access); + $backend = new UserLDAP($access, $this->createMock(IConfig::class)); + \OC_User::useBackend($backend); + + $this->assertTrue(\OC_User::setPassword('roland', 'dt12234$')); + } + + public function testSetPasswordValidDisabled() { + $access = $this->getAccessMock(); + + $this->prepareAccessForSetPassword($access, false); + $backend = new UserLDAP($access, $this->createMock(IConfig::class)); + \OC_User::useBackend($backend); + + $this->assertFalse(\OC_User::setPassword('roland', 'dt12234$')); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage LDAP setPassword: Could not get user object for uid NotExistingUser. Maybe the LDAP entry has no set display name attribute? + */ + public function testSetPasswordWithInvalidUser() { + $access = $this->createMock(Access::class); + $access->userManager = $this->createMock(IUserManager::class); + $access->userManager + ->expects($this->once()) + ->method('get') + ->with('NotExistingUser') + ->willReturn(null); + $config = $this->createMock(IConfig::class); + $ldap = new User_LDAP( + $access, + $config + ); + $ldap->setPassword('NotExistingUser', 'Password'); + } + + public function testSetPasswordWithUsernameFalse() { + $user = $this->createMock(User::class); + $user + ->expects($this->once()) + ->method('getUsername') + ->willReturn(false); + $access = $this->createMock(Access::class); + $access->userManager = $this->createMock(IUserManager::class); + $access->userManager + ->expects($this->once()) + ->method('get') + ->with('NotExistingUser') + ->willReturn($user); + $config = $this->createMock(IConfig::class); + $ldap = new User_LDAP( + $access, + $config + ); + $this->assertFalse($ldap->setPassword('NotExistingUser', 'Password')); + } } diff --git a/apps/user_ldap/tests/User_ProxyTest.php b/apps/user_ldap/tests/User_ProxyTest.php new file mode 100644 index 00000000000..6d779d758e4 --- /dev/null +++ b/apps/user_ldap/tests/User_ProxyTest.php @@ -0,0 +1,61 @@ +<?php +/** + * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\User_LDAP\Tests; + +use OCA\User_LDAP\ILDAPWrapper; +use OCA\User_LDAP\User_Proxy; +use OCP\IConfig; +use Test\TestCase; + +class User_ProxyTest extends TestCase { + /** @var ILDAPWrapper|\PHPUnit_Framework_MockObject_MockObject */ + private $ldapWrapper; + /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ + private $config; + /** @var User_Proxy|\PHPUnit_Framework_MockObject_MockObject */ + private $proxy; + + public function setUp() { + parent::setUp(); + + $this->ldapWrapper = $this->createMock(ILDAPWrapper::class); + $this->config = $this->createMock(IConfig::class); + $this->proxy = $this->getMockBuilder(User_Proxy::class) + ->setConstructorArgs([ + [], + $this->ldapWrapper, + $this->config, + ]) + ->setMethods(['handleRequest']) + ->getMock(); + } + + public function testSetPassword() { + $this->proxy + ->expects($this->once()) + ->method('handleRequest') + ->with('MyUid', 'setPassword', ['MyUid', 'MyPassword']) + ->willReturn(true); + + $this->assertTrue($this->proxy->setPassword('MyUid', 'MyPassword')); + } +} |