summaryrefslogtreecommitdiffstats
path: root/apps/user_ldap
diff options
context:
space:
mode:
Diffstat (limited to 'apps/user_ldap')
-rw-r--r--apps/user_ldap/group_ldap.php235
-rw-r--r--apps/user_ldap/lib/access.php94
-rw-r--r--apps/user_ldap/lib/connection.php7
-rw-r--r--apps/user_ldap/lib/ildapwrapper.php9
-rw-r--r--apps/user_ldap/lib/ldap.php11
-rw-r--r--apps/user_ldap/tests/access.php52
-rw-r--r--apps/user_ldap/tests/data/sid.datbin0 -> 24 bytes
-rw-r--r--apps/user_ldap/tests/group_ldap.php152
8 files changed, 516 insertions, 44 deletions
diff --git a/apps/user_ldap/group_ldap.php b/apps/user_ldap/group_ldap.php
index 1a35691be85..0d3a70575ba 100644
--- a/apps/user_ldap/group_ldap.php
+++ b/apps/user_ldap/group_ldap.php
@@ -50,20 +50,29 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
if(!$this->enabled) {
return false;
}
- if($this->access->connection->isCached('inGroup'.$uid.':'.$gid)) {
- return $this->access->connection->getFromCache('inGroup'.$uid.':'.$gid);
+ $cacheKey = 'inGroup'.$uid.':'.$gid;
+ if($this->access->connection->isCached($cacheKey)) {
+ return $this->access->connection->getFromCache($cacheKey);
}
- $dn_user = $this->access->username2dn($uid);
- $dn_group = $this->access->groupname2dn($gid);
+
+ $userDN = $this->access->username2dn($uid);
+ $groupDN = $this->access->groupname2dn($gid);
// just in case
- if(!$dn_group || !$dn_user) {
- $this->access->connection->writeToCache('inGroup'.$uid.':'.$gid, false);
+ if(!$groupDN || !$userDN) {
+ $this->access->connection->writeToCache($cacheKey, false);
return false;
}
+
+ //check primary group first
+ if($gid === $this->getUserPrimaryGroup($userDN)) {
+ $this->access->connection->writeToCache($cacheKey, true);
+ return true;
+ }
+
//usually, LDAP attributes are said to be case insensitive. But there are exceptions of course.
- $members = array_keys($this->_groupMembers($dn_group));
+ $members = array_keys($this->_groupMembers($groupDN));
if(!$members) {
- $this->access->connection->writeToCache('inGroup'.$uid.':'.$gid, false);
+ $this->access->connection->writeToCache($cacheKey, false);
return false;
}
@@ -82,8 +91,8 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
$members = $dns;
}
- $isInGroup = in_array($dn_user, $members);
- $this->access->connection->writeToCache('inGroup'.$uid.':'.$gid, $isInGroup);
+ $isInGroup = in_array($userDN, $members);
+ $this->access->connection->writeToCache($cacheKey, $isInGroup);
return $isInGroup;
}
@@ -91,6 +100,7 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
/**
* @param string $dnGroup
* @param array|null &$seen
+ * @return array|mixed|null
*/
private function _groupMembers($dnGroup, &$seen = null) {
if ($seen === null) {
@@ -126,6 +136,125 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
}
/**
+ * translates a primary group ID into an ownCloud internal name
+ * @param string $gid as given by primaryGroupID on AD
+ * @param string $dn a DN that belongs to the same domain as the group
+ * @return string|bool
+ */
+ public function primaryGroupID2Name($gid, $dn) {
+ $cacheKey = 'primaryGroupIDtoName';
+ if($this->access->connection->isCached($cacheKey)) {
+ $groupNames = $this->access->connection->getFromCache($cacheKey);
+ if(isset($groupNames[$gid])) {
+ return $groupNames[$gid];
+ }
+ }
+
+ $domainObjectSid = $this->access->getSID($dn);
+ if($domainObjectSid === false) {
+ return false;
+ }
+
+ //we need to get the DN from LDAP
+ $filter = $this->access->combineFilterWithAnd(array(
+ $this->access->connection->ldapGroupFilter,
+ 'objectsid=' . $domainObjectSid . '-' . $gid
+ ));
+ $result = $this->access->searchGroups($filter, array('dn'), 1);
+ if(empty($result)) {
+ return false;
+ }
+ $dn = $result[0];
+
+ //and now the group name
+ //NOTE once we have separate ownCloud group IDs and group names we can
+ //directly read the display name attribute instead of the DN
+ $name = $this->access->dn2groupname($dn);
+
+ $this->access->connection->writeToCache($cacheKey, $name);
+
+ return $name;
+ }
+
+ /**
+ * returns the entry's primary group ID
+ * @param string $dn
+ * @param string $attribute
+ * @return string|bool
+ */
+ private function getEntryGroupID($dn, $attribute) {
+ $value = $this->access->readAttribute($dn, $attribute);
+ if(is_array($value) && !empty($value)) {
+ return $value[0];
+ }
+ return false;
+ }
+
+ /**
+ * returns the group's primary ID
+ * @param string $dn
+ * @return string|bool
+ */
+ public function getGroupPrimaryGroupID($dn) {
+ return $this->getEntryGroupID($dn, 'primaryGroupToken');
+ }
+
+ /**
+ * returns the user's primary group ID
+ * @param string $dn
+ * @return string|bool
+ */
+ public function getUserPrimaryGroupIDs($dn) {
+ return $this->getEntryGroupID($dn, 'primaryGroupID');
+ }
+
+ /**
+ * returns a list of users that have the given group as primary group
+ *
+ * @param string $groupDN
+ * @param $limit
+ * @param int $offset
+ * @return string[]
+ */
+ public function getUsersInPrimaryGroup($groupDN, $limit = -1, $offset = 0) {
+ $groupID = $this->getGroupPrimaryGroupID($groupDN);
+ if($groupID === false) {
+ return array();
+ }
+
+ $filter = $this->access->combineFilterWithAnd(array(
+ $this->access->connection->ldapUserFilter,
+ 'primaryGroupID=' . $groupID
+ ));
+
+ $users = $this->access->fetchListOfUsers(
+ $filter,
+ array($this->access->connection->ldapUserDisplayName, 'dn'),
+ $limit,
+ $offset
+ );
+
+ return $users;
+ }
+
+ /**
+ * gets the primary group of a user
+ * @param string $dn
+ * @return string
+ */
+ public function getUserPrimaryGroup($dn) {
+ $groupID = $this->getUserPrimaryGroupIDs($dn);
+ if($groupID !== false) {
+ $groupName = $this->primaryGroupID2Name($groupID, $dn);
+ if($groupName !== false) {
+ return $groupName;
+ }
+ }
+
+ return false;
+ }
+
+ /**
* Get all groups a user belongs to
* @param string $uid Name of the user
* @return array with group names
@@ -161,7 +290,14 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
}
$groups = array_values($this->getGroupsByMember($uid));
- $groups = array_unique($this->access->ownCloudGroupNames($groups), SORT_LOCALE_STRING);
+ $groups = $this->access->ownCloudGroupNames($groups);
+
+ $primaryGroup = $this->getUserPrimaryGroup($userDN);
+ if($primaryGroup !== false) {
+ $groups[] = $primaryGroup;
+ }
+
+ $groups = array_unique($groups, SORT_LOCALE_STRING);
$this->access->connection->writeToCache($cacheKey, $groups);
return $groups;
@@ -170,6 +306,7 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
/**
* @param string $dn
* @param array|null &$seen
+ * @return array
*/
private function getGroupsByMember($dn, &$seen = null) {
if ($seen === null) {
@@ -205,6 +342,11 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
/**
* get a list of all users in a group
+ *
+ * @param string $gid
+ * @param string $search
+ * @param int $limit
+ * @param int $offset
* @return array with user ids
*/
public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) {
@@ -214,9 +356,9 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
if(!$this->groupExists($gid)) {
return array();
}
- $cachekey = 'usersInGroup-'.$gid.'-'.$search.'-'.$limit.'-'.$offset;
+ $cacheKey = 'usersInGroup-'.$gid.'-'.$search.'-'.$limit.'-'.$offset;
// check for cache of the exact query
- $groupUsers = $this->access->connection->getFromCache($cachekey);
+ $groupUsers = $this->access->connection->getFromCache($cacheKey);
if(!is_null($groupUsers)) {
return $groupUsers;
}
@@ -225,7 +367,7 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
$groupUsers = $this->access->connection->getFromCache('usersInGroup-'.$gid.'-'.$search);
if(!is_null($groupUsers)) {
$groupUsers = array_slice($groupUsers, $offset, $limit);
- $this->access->connection->writeToCache($cachekey, $groupUsers);
+ $this->access->connection->writeToCache($cacheKey, $groupUsers);
return $groupUsers;
}
@@ -235,14 +377,14 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
$groupDN = $this->access->groupname2dn($gid);
if(!$groupDN) {
// group couldn't be found, return empty resultset
- $this->access->connection->writeToCache($cachekey, array());
+ $this->access->connection->writeToCache($cacheKey, array());
return array();
}
$members = array_keys($this->_groupMembers($groupDN));
if(!$members) {
- //in case users could not be retrieved, return empty resultset
- $this->access->connection->writeToCache($cachekey, array());
+ //in case users could not be retrieved, return empty result set
+ $this->access->connection->writeToCache($cacheKey, array());
return array();
}
@@ -250,7 +392,7 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
$isMemberUid = (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid');
foreach($members as $member) {
if($isMemberUid) {
- //we got uids, need to get their DNs to 'tranlsate' them to usernames
+ //we got uids, need to get their DNs to 'translate' them to user names
$filter = $this->access->combineFilterWithAnd(array(
\OCP\Util::mb_str_replace('%uid', $member,
$this->access->connection->ldapLoginFilter, 'UTF-8'),
@@ -276,10 +418,16 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
}
}
}
+
natsort($groupUsers);
$this->access->connection->writeToCache('usersInGroup-'.$gid.'-'.$search, $groupUsers);
$groupUsers = array_slice($groupUsers, $offset, $limit);
- $this->access->connection->writeToCache($cachekey, $groupUsers);
+
+ //and get users that have the group as primary
+ $primaryUsers = $this->getUsersInPrimaryGroup($groupDN, $limit, $offset);
+ $groupUsers = array_unique(array_merge($groupUsers, $primaryUsers));
+
+ $this->access->connection->writeToCache($cacheKey, $groupUsers);
return $groupUsers;
}
@@ -291,32 +439,32 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
* @return int|bool
*/
public function countUsersInGroup($gid, $search = '') {
- $cachekey = 'countUsersInGroup-'.$gid.'-'.$search;
+ $cacheKey = 'countUsersInGroup-'.$gid.'-'.$search;
if(!$this->enabled || !$this->groupExists($gid)) {
return false;
}
- $groupUsers = $this->access->connection->getFromCache($cachekey);
+ $groupUsers = $this->access->connection->getFromCache($cacheKey);
if(!is_null($groupUsers)) {
return $groupUsers;
}
$groupDN = $this->access->groupname2dn($gid);
if(!$groupDN) {
- // group couldn't be found, return empty resultset
- $this->access->connection->writeToCache($cachekey, false);
+ // group couldn't be found, return empty result set
+ $this->access->connection->writeToCache($cacheKey, false);
return false;
}
$members = array_keys($this->_groupMembers($groupDN));
if(!$members) {
- //in case users could not be retrieved, return empty resultset
- $this->access->connection->writeToCache($cachekey, false);
+ //in case users could not be retrieved, return empty result set
+ $this->access->connection->writeToCache($cacheKey, false);
return false;
}
if(empty($search)) {
$groupUsers = count($members);
- $this->access->connection->writeToCache($cachekey, $groupUsers);
+ $this->access->connection->writeToCache($cacheKey, $groupUsers);
return $groupUsers;
}
$isMemberUid =
@@ -334,7 +482,7 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
$groupUsers = array();
foreach($members as $member) {
if($isMemberUid) {
- //we got uids, need to get their DNs to 'tranlsate' them to usernames
+ //we got uids, need to get their DNs to 'translate' them to user names
$filter = $this->access->combineFilterWithAnd(array(
\OCP\Util::mb_str_replace('%uid', $member,
$this->access->connection->ldapLoginFilter, 'UTF-8'),
@@ -359,11 +507,19 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
}
}
+ //and get users that have the group as primary
+ $primaryUsers = $this->getUsersInPrimaryGroup($groupDN);
+ $groupUsers = array_unique(array_merge($groupUsers, $primaryUsers));
+
return count($groupUsers);
}
/**
* get a list of all groups
+ *
+ * @param string $search
+ * @param $limit
+ * @param int $offset
* @return array with group names
*
* Returns a list with all groups (used by getGroups)
@@ -372,11 +528,11 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
if(!$this->enabled) {
return array();
}
- $cachekey = 'getGroups-'.$search.'-'.$limit.'-'.$offset;
+ $cacheKey = 'getGroups-'.$search.'-'.$limit.'-'.$offset;
//Check cache before driving unnecessary searches
- \OCP\Util::writeLog('user_ldap', 'getGroups '.$cachekey, \OCP\Util::DEBUG);
- $ldap_groups = $this->access->connection->getFromCache($cachekey);
+ \OCP\Util::writeLog('user_ldap', 'getGroups '.$cacheKey, \OCP\Util::DEBUG);
+ $ldap_groups = $this->access->connection->getFromCache($cacheKey);
if(!is_null($ldap_groups)) {
return $ldap_groups;
}
@@ -397,26 +553,30 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
$offset);
$ldap_groups = $this->access->ownCloudGroupNames($ldap_groups);
- $this->access->connection->writeToCache($cachekey, $ldap_groups);
+ $this->access->connection->writeToCache($cacheKey, $ldap_groups);
return $ldap_groups;
}
/**
* get a list of all groups using a paged search
+ *
+ * @param string $search
+ * @param int $limit
+ * @param int $offset
* @return array with group names
*
* Returns a list with all groups
- * Uses a paged search if available to override a
- * server side search limit.
- * (active directory has a limit of 1000 by default)
+ * Uses a paged search if available to override a
+ * server side search limit.
+ * (active directory has a limit of 1000 by default)
*/
public function getGroups($search = '', $limit = -1, $offset = 0) {
if(!$this->enabled) {
return array();
}
- $pagingsize = $this->access->connection->ldapPagingSize;
+ $pagingSize = $this->access->connection->ldapPagingSize;
if ((! $this->access->connection->hasPagedResultSupport)
- || empty($pagingsize)) {
+ || empty($pagingSize)) {
return $this->getGroupsChunk($search, $limit, $offset);
}
$maxGroups = 100000; // limit max results (just for safety reasons)
@@ -428,7 +588,7 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
$chunkOffset = $offset;
$allGroups = array();
while ($chunkOffset < $overallLimit) {
- $chunkLimit = min($pagingsize, $overallLimit - $chunkOffset);
+ $chunkLimit = min($pagingSize, $overallLimit - $chunkOffset);
$ldapGroups = $this->getGroupsChunk($search, $chunkLimit, $chunkOffset);
$nread = count($ldapGroups);
\OCP\Util::writeLog('user_ldap', 'getGroups('.$search.'): read '.$nread.' at offset '.$chunkOffset.' (limit: '.$chunkLimit.')', \OCP\Util::DEBUG);
@@ -445,6 +605,7 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
/**
* @param string $group
+ * @return bool
*/
public function groupMatchesFilter($group) {
return (strripos($group, $this->groupSearch) !== false);
diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php
index ca5d1386995..e3b6566bcf0 100644
--- a/apps/user_ldap/lib/access.php
+++ b/apps/user_ldap/lib/access.php
@@ -28,6 +28,9 @@ namespace OCA\user_ldap\lib;
* @package OCA\user_ldap\lib
*/
class Access extends LDAPUtility implements user\IUserTools {
+ /**
+ * @var \OCA\user_ldap\lib\Connection
+ */
public $connection;
public $userManager;
//never ever check this var directly, always use getPagedSearchResultState
@@ -61,8 +64,8 @@ class Access extends LDAPUtility implements user\IUserTools {
/**
* reads a given attribute for an LDAP record identified by a DN
- * @param $dn the record in question
- * @param $attr the attribute that shall be retrieved
+ * @param string $dn the record in question
+ * @param string $attr the attribute that shall be retrieved
* if empty, just check the record's existence
* @param string $filter
* @return array|false an array of values on success or an empty
@@ -181,6 +184,33 @@ class Access extends LDAPUtility implements user\IUserTools {
}
/**
+ * returns a DN-string that is cleaned from not domain parts, e.g.
+ * cn=foo,cn=bar,dc=foobar,dc=server,dc=org
+ * becomes dc=foobar,dc=server,dc=org
+ * @param string $dn
+ * @return string
+ */
+ public function getDomainDNFromDN($dn) {
+ $allParts = $this->ldap->explodeDN($dn, 0);
+ if($allParts === false) {
+ //not a valid DN
+ return '';
+ }
+ $domainParts = array();
+ $dcFound = false;
+ foreach($allParts as $part) {
+ if(!$dcFound && strpos($part, 'dc=') === 0) {
+ $dcFound = true;
+ }
+ if($dcFound) {
+ $domainParts[] = $part;
+ }
+ }
+ $domainDN = implode(',', $domainParts);
+ return $domainDN;
+ }
+
+ /**
* gives back the database table for the query
* @param bool $isUser
* @return string
@@ -534,7 +564,7 @@ class Access extends LDAPUtility implements user\IUserTools {
if(!\OC_Group::groupExists($altName)) {
return $altName;
}
- $altName = $name . '_' . $lastNo + $attempts;
+ $altName = $name . '_' . ($lastNo + $attempts);
$attempts++;
}
return false;
@@ -581,6 +611,7 @@ class Access extends LDAPUtility implements user\IUserTools {
/**
* @param boolean $isUsers
+ * @return array
*/
private function mappedComponents($isUsers) {
$table = $this->getMapTable($isUsers);
@@ -834,7 +865,7 @@ class Access extends LDAPUtility implements user\IUserTools {
private function count($filter, $base, $attr = null, $limit = null, $offset = null, $skipHandling = false) {
\OCP\Util::writeLog('user_ldap', 'Count filter: '.print_r($filter, true), \OCP\Util::DEBUG);
- if(is_null($limit)) {
+ if(is_null($limit) || $limit <= 0) {
$limit = intval($this->connection->ldapPagingSize);
}
@@ -894,6 +925,10 @@ class Access extends LDAPUtility implements user\IUserTools {
* @return array with the search result
*/
private function search($filter, $base, $attr = null, $limit = null, $offset = null, $skipHandling = false) {
+ if($limit <= 0) {
+ //otherwise search will fail
+ $limit = null;
+ }
$search = $this->executeSearch($filter, $base, $attr, $limit, $offset);
if($search === false) {
return array();
@@ -908,7 +943,7 @@ class Access extends LDAPUtility implements user\IUserTools {
$this->processPagedSearchStatus($sr, $filter, $base, 1, $limit,
$offset, $pagedSearchOK,
$skipHandling);
- return;
+ return array();
}
// Do the server-side sorting
@@ -1233,6 +1268,55 @@ class Access extends LDAPUtility implements user\IUserTools {
}
/**
+ * gets a SID of the domain of the given dn
+ * @param string $dn
+ * @return string|bool
+ */
+ public function getSID($dn) {
+ $domainDN = $this->getDomainDNFromDN($dn);
+ $cacheKey = 'getSID-'.$domainDN;
+ if($this->connection->isCached($cacheKey)) {
+ return $this->connection->getFromCache($cacheKey);
+ }
+
+ $objectSid = $this->readAttribute($domainDN, 'objectsid');
+ if(!is_array($objectSid) || empty($objectSid)) {
+ $this->connection->writeToCache($cacheKey, false);
+ return false;
+ }
+ $domainObjectSid = $this->convertSID2Str($objectSid[0]);
+ $this->connection->writeToCache($cacheKey, $domainObjectSid);
+
+ return $domainObjectSid;
+ }
+
+ /**
+ * converts a binary SID into a string representation
+ * @param string $sid
+ * @return string
+ * @link http://blogs.freebsdish.org/tmclaugh/2010/07/21/finding-a-users-primary-group-in-ad/#comment-2855
+ */
+ public function convertSID2Str($sid) {
+ try {
+ $srl = ord($sid[0]);
+ $numberSubID = ord($sid[1]);
+ $x = substr($sid, 2, 6);
+ $h = unpack('N', "\x0\x0" . substr($x,0,2));
+ $l = unpack('N', substr($x,2,6));
+ $iav = bcadd(bcmul($h[1], bcpow(2,32)), $l[1]);
+ $subIDs = array();
+ for ($i=0; $i<$numberSubID; $i++) {
+ $subID = unpack('V', substr($sid, 8+4*$i, 4));
+ $subIDs[] = $subID[1];
+ }
+ } catch (\Exception $e) {
+ return '';
+ }
+
+ return sprintf('S-%d-%d-%s', $srl, $iav, implode('-', $subIDs));
+ }
+
+ /**
* converts a stored DN so it can be used as base parameter for LDAP queries, internally we store them for usage in LDAP filters
* @param string $dn the DN
* @return string
diff --git a/apps/user_ldap/lib/connection.php b/apps/user_ldap/lib/connection.php
index bafb0e0b895..336ea7b3bbc 100644
--- a/apps/user_ldap/lib/connection.php
+++ b/apps/user_ldap/lib/connection.php
@@ -23,6 +23,13 @@
namespace OCA\user_ldap\lib;
+//magic properties (incomplete)
+/**
+ * responsible for LDAP connections in context with the provided configuration
+ * @property string ldapUserFilter
+ * @property string ldapUserDisplayName
+ * @property boolean hasPagedResultSupport
+*/
class Connection extends LDAPUtility {
private $ldapConnectionRes = null;
private $configPrefix;
diff --git a/apps/user_ldap/lib/ildapwrapper.php b/apps/user_ldap/lib/ildapwrapper.php
index 97ae0810116..590f6d7ac7a 100644
--- a/apps/user_ldap/lib/ildapwrapper.php
+++ b/apps/user_ldap/lib/ildapwrapper.php
@@ -90,6 +90,15 @@ interface ILDAPWrapper {
public function error($link);
/**
+ * Splits DN into its component parts
+ * @param string $dn
+ * @param int @withAttrib
+ * @return array|false
+ * @link http://www.php.net/manual/en/function.ldap-explode-dn.php
+ */
+ public function explodeDN($dn, $withAttrib);
+
+ /**
* Return first result id
* @param resource $link LDAP link resource
* @param resource $result LDAP result resource
diff --git a/apps/user_ldap/lib/ldap.php b/apps/user_ldap/lib/ldap.php
index 2b20b2ab738..967754db7d3 100644
--- a/apps/user_ldap/lib/ldap.php
+++ b/apps/user_ldap/lib/ldap.php
@@ -99,6 +99,17 @@ class LDAP implements ILDAPWrapper {
}
/**
+ * Splits DN into its component parts
+ * @param string $dn
+ * @param int @withAttrib
+ * @return array|false
+ * @link http://www.php.net/manual/en/function.ldap-explode-dn.php
+ */
+ public function explodeDN($dn, $withAttrib) {
+ return $this->invokeLDAPMethod('ldap_explode_dn', $dn, $withAttrib);
+ }
+
+ /**
* @param LDAP $link
* @param LDAP $result
* @return mixed
diff --git a/apps/user_ldap/tests/access.php b/apps/user_ldap/tests/access.php
index 8ead5d68482..2ff7540b8ef 100644
--- a/apps/user_ldap/tests/access.php
+++ b/apps/user_ldap/tests/access.php
@@ -77,4 +77,54 @@ class Test_Access extends \PHPUnit_Framework_TestCase {
$expected = 'foo\\\\*bar';
$this->assertTrue($expected === $access->escapeFilterPart($input));
}
-} \ No newline at end of file
+
+ public function testConvertSID2StrSuccess() {
+ list($lw, $con, $um) = $this->getConnecterAndLdapMock();
+ $access = new Access($con, $lw, $um);
+
+ $sidBinary = file_get_contents(__DIR__ . '/data/sid.dat');
+ $sidExpected = 'S-1-5-21-249921958-728525901-1594176202';
+
+ $this->assertSame($sidExpected, $access->convertSID2Str($sidBinary));
+ }
+
+ public function testConvertSID2StrInputError() {
+ list($lw, $con, $um) = $this->getConnecterAndLdapMock();
+ $access = new Access($con, $lw, $um);
+
+ $sidIllegal = 'foobar';
+ $sidExpected = '';
+
+ $this->assertSame($sidExpected, $access->convertSID2Str($sidIllegal));
+ }
+
+ public function testGetDomainDNFromDNSuccess() {
+ list($lw, $con, $um) = $this->getConnecterAndLdapMock();
+ $access = new Access($con, $lw, $um);
+
+ $inputDN = 'uid=zaphod,cn=foobar,dc=my,dc=server,dc=com';
+ $domainDN = 'dc=my,dc=server,dc=com';
+
+ $lw->expects($this->once())
+ ->method('explodeDN')
+ ->with($inputDN, 0)
+ ->will($this->returnValue(explode(',', $inputDN)));
+
+ $this->assertSame($domainDN, $access->getDomainDNFromDN($inputDN));
+ }
+
+ public function testGetDomainDNFromDNError() {
+ list($lw, $con, $um) = $this->getConnecterAndLdapMock();
+ $access = new Access($con, $lw, $um);
+
+ $inputDN = 'foobar';
+ $expected = '';
+
+ $lw->expects($this->once())
+ ->method('explodeDN')
+ ->with($inputDN, 0)
+ ->will($this->returnValue(false));
+
+ $this->assertSame($expected, $access->getDomainDNFromDN($inputDN));
+ }
+}
diff --git a/apps/user_ldap/tests/data/sid.dat b/apps/user_ldap/tests/data/sid.dat
new file mode 100644
index 00000000000..3d500c6a872
--- /dev/null
+++ b/apps/user_ldap/tests/data/sid.dat
Binary files differ
diff --git a/apps/user_ldap/tests/group_ldap.php b/apps/user_ldap/tests/group_ldap.php
index 1184fe1e82e..c4aed25a1cc 100644
--- a/apps/user_ldap/tests/group_ldap.php
+++ b/apps/user_ldap/tests/group_ldap.php
@@ -96,6 +96,10 @@ class Test_Group_Ldap extends \PHPUnit_Framework_TestCase {
->will($this->returnValue('cn=group,dc=foo,dc=bar'));
$access->expects($this->any())
+ ->method('fetchListOfUsers')
+ ->will($this->returnValue(array()));
+
+ $access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($name) {
//the search operation will call readAttribute, thus we need
@@ -111,7 +115,9 @@ class Test_Group_Ldap extends \PHPUnit_Framework_TestCase {
$access->expects($this->any())
->method('dn2username')
- ->will($this->returnValue('foobar'));
+ ->will($this->returnCallback(function() {
+ return 'foobar' . \OCP\Util::generateRandomBytes(7);
+ }));
$groupBackend = new GroupLDAP($access);
$users = $groupBackend->countUsersInGroup('group', '3');
@@ -119,4 +125,148 @@ class Test_Group_Ldap extends \PHPUnit_Framework_TestCase {
$this->assertSame(2, $users);
}
+ public function testPrimaryGroupID2NameSuccess() {
+ $access = $this->getAccessMock();
+ $this->enableGroups($access);
+
+ $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
+
+ $access->expects($this->once())
+ ->method('getSID')
+ ->with($userDN)
+ ->will($this->returnValue('S-1-5-21-249921958-728525901-1594176202'));
+
+ $access->expects($this->once())
+ ->method('searchGroups')
+ ->will($this->returnValue(array('cn=foo,dc=barfoo,dc=bar')));
+
+ $access->expects($this->once())
+ ->method('dn2groupname')
+ ->with('cn=foo,dc=barfoo,dc=bar')
+ ->will($this->returnValue('MyGroup'));
+
+ $groupBackend = new GroupLDAP($access);
+
+ $group = $groupBackend->primaryGroupID2Name('3117', $userDN);
+
+ $this->assertSame('MyGroup', $group);
+ }
+
+ public function testPrimaryGroupID2NameNoSID() {
+ $access = $this->getAccessMock();
+ $this->enableGroups($access);
+
+ $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
+
+ $access->expects($this->once())
+ ->method('getSID')
+ ->with($userDN)
+ ->will($this->returnValue(false));
+
+ $access->expects($this->never())
+ ->method('searchGroups');
+
+ $access->expects($this->never())
+ ->method('dn2groupname');
+
+ $groupBackend = new GroupLDAP($access);
+
+ $group = $groupBackend->primaryGroupID2Name('3117', $userDN);
+
+ $this->assertSame(false, $group);
+ }
+
+ public function testPrimaryGroupID2NameNoGroup() {
+ $access = $this->getAccessMock();
+ $this->enableGroups($access);
+
+ $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
+
+ $access->expects($this->once())
+ ->method('getSID')
+ ->with($userDN)
+ ->will($this->returnValue('S-1-5-21-249921958-728525901-1594176202'));
+
+ $access->expects($this->once())
+ ->method('searchGroups')
+ ->will($this->returnValue(array()));
+
+ $access->expects($this->never())
+ ->method('dn2groupname');
+
+ $groupBackend = new GroupLDAP($access);
+
+ $group = $groupBackend->primaryGroupID2Name('3117', $userDN);
+
+ $this->assertSame(false, $group);
+ }
+
+ public function testPrimaryGroupID2NameNoName() {
+ $access = $this->getAccessMock();
+ $this->enableGroups($access);
+
+ $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
+
+ $access->expects($this->once())
+ ->method('getSID')
+ ->with($userDN)
+ ->will($this->returnValue('S-1-5-21-249921958-728525901-1594176202'));
+
+ $access->expects($this->once())
+ ->method('searchGroups')
+ ->will($this->returnValue(array('cn=foo,dc=barfoo,dc=bar')));
+
+ $access->expects($this->once())
+ ->method('dn2groupname')
+ ->will($this->returnValue(false));
+
+ $groupBackend = new GroupLDAP($access);
+
+ $group = $groupBackend->primaryGroupID2Name('3117', $userDN);
+
+ $this->assertSame(false, $group);
+ }
+
+ public function testGetEntryGroupIDValue() {
+ //tests getEntryGroupID via getGroupPrimaryGroupID
+ //which is basically identical to getUserPrimaryGroupIDs
+ $access = $this->getAccessMock();
+ $this->enableGroups($access);
+
+ $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
+ $attr = 'primaryGroupToken';
+
+ $access->expects($this->once())
+ ->method('readAttribute')
+ ->with($dn, $attr)
+ ->will($this->returnValue(array('3117')));
+
+ $groupBackend = new GroupLDAP($access);
+
+ $gid = $groupBackend->getGroupPrimaryGroupID($dn);
+
+ $this->assertSame('3117', $gid);
+ }
+
+ public function testGetEntryGroupIDNoValue() {
+ //tests getEntryGroupID via getGroupPrimaryGroupID
+ //which is basically identical to getUserPrimaryGroupIDs
+ $access = $this->getAccessMock();
+ $this->enableGroups($access);
+
+ $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
+ $attr = 'primaryGroupToken';
+
+ $access->expects($this->once())
+ ->method('readAttribute')
+ ->with($dn, $attr)
+ ->will($this->returnValue(false));
+
+ $groupBackend = new GroupLDAP($access);
+
+ $gid = $groupBackend->getGroupPrimaryGroupID($dn);
+
+ $this->assertSame(false, $gid);
+ }
+
}