add support for nested groups

This commit is contained in:
root 2013-12-06 16:46:52 +01:00
parent 9371944e43
commit 48e426b589
3 changed files with 73 additions and 10 deletions

View file

@ -61,8 +61,7 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
return false;
}
//usually, LDAP attributes are said to be case insensitive. But there are exceptions of course.
$members = $this->access->readAttribute($dn_group,
$this->access->connection->ldapGroupMemberAssocAttr);
$members = array_keys($this->_groupMembers($dn_group));
if(!$members) {
$this->access->connection->writeToCache('inGroup'.$uid.':'.$gid, false);
return false;
@ -89,6 +88,39 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
return $isInGroup;
}
private function _groupMembers($dn_group, &$groups_seen = null) {
if ($groups_seen == null) {
$groups_seen = array();
}
$all_members = array();
if (array_key_exists($dn_group, $groups_seen)) {
// avoid loops
return array();
}
// used extensively in cron job, caching makes sense for nested groups
$cache_key = '_groupMembers'.$dn_group;
if($this->access->connection->isCached($cache_key)) {
\OCP\Util::writeLog('user_ldap', 'LEO _groupMembers('.$dn_group.') using cached value', \OCP\Util::DEBUG);
return $this->access->connection->getFromCache($cache_key);
}
$groups_seen[$dn_group] = 1;
$members = $this->access->readAttribute($dn_group, $this->access->connection->ldapGroupMemberAssocAttr,
$this->access->connection->ldapGroupFilter);
if ($members) {
foreach ($members as $member_dn) {
$all_members[$member_dn] = 1;
if ($this->access->connection->ldapNestedGroups) {
$submembers = $this->_groupMembers($member_dn, $groups_seen);
if ($submembers) {
$all_members = array_merge($all_members, $submembers);
}
}
}
}
$this->access->connection->writeToCache($cache_key, $all_members);
return $all_members;
}
/**
* @brief Get all groups a user belongs to
* @param $uid Name of the user
@ -124,18 +156,45 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
$uid = $userDN;
}
$filter = $this->access->combineFilterWithAnd(array(
$this->access->connection->ldapGroupFilter,
$this->access->connection->ldapGroupMemberAssocAttr.'='.$uid
));
$groups = $this->access->fetchListOfGroups($filter,
array($this->access->connection->ldapGroupDisplayName, 'dn'));
$groups = array_values($this->_getGroupsByMember($uid));
$groups = array_unique($this->access->ownCloudGroupNames($groups), SORT_LOCALE_STRING);
\OCP\Util::writeLog('user_ldap', 'LEO _getGroupsByMember('.$uid.'): '.implode(", ", $groups), \OCP\Util::DEBUG);
$this->access->connection->writeToCache($cacheKey, $groups);
return $groups;
}
/* private */ public function _getGroupsByMember($dn, &$seen = null) {
if ($seen == null) {
$seen = array();
}
$all_groups = array();
if (array_key_exists($dn, $seen)) {
// avoid loops
return array();
}
$seen[$dn] = 1;
$filter = $this->combineFilterWithAnd(array(
$this->access->connection->ldapGroupFilter,
$this->access->connection->ldapGroupMemberAssocAttr.'='.$dn
));
$groups = $this->fetchListOfGroups($filter,
array($this->access->connection->ldapGroupDisplayName, 'dn'));
if ($groups) {
foreach ($groups as $groupobj) {
$group_dn = $groupobj['dn'];
$all_groups[$group_dn] = $groupobj;
if ($this->access->connection->ldapNestedGroups) {
$supergroups = $this->_getGroupsByMember($group_dn, $seen);
if ($supergroups) {
$all_groups = array_merge($all_groups, $supergroups);
}
}
}
}
return $all_groups;
}
/**
* @brief get a list of all users in a group
* @returns array with user ids
@ -172,8 +231,8 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
return array();
}
$members = $this->access->readAttribute($groupDN,
$this->access->connection->ldapGroupMemberAssocAttr);
$members = array_keys($this->_groupMembers($groupDN));
\OCP\Util::writeLog('user_ldap', 'LEO _groupMembers('.$groupDN.'): '.implode(", ", $members), \OCP\Util::DEBUG);
if(!$members) {
//in case users could not be retrieved, return empty resultset
$this->access->connection->writeToCache($cachekey, array());

View file

@ -76,6 +76,7 @@ class Configuration {
'ldapExpertUUIDUserAttr' => null,
'ldapExpertUUIDGroupAttr' => null,
'lastJpegPhotoLookup' => null,
'ldapNestedGroups' => false,
);
public function __construct($configPrefix, $autoread = true) {
@ -338,6 +339,7 @@ class Configuration {
'ldap_expert_uuid_group_attr' => '',
'has_memberof_filter_support' => 0,
'last_jpegPhoto_lookup' => 0,
'ldap_nested_groups' => 0,
);
}
@ -389,6 +391,7 @@ class Configuration {
'ldap_expert_uuid_group_attr' => 'ldapExpertUUIDGroupAttr',
'has_memberof_filter_support' => 'hasMemberOfFilterSupport',
'last_jpegPhoto_lookup' => 'lastJpegPhotoLookup',
'ldap_nested_groups' => 'ldapNestedGroups',
);
return $array;
}

View file

@ -58,6 +58,7 @@
<p><strong><?php p($l->t('Username-LDAP User Mapping'));?></strong></p>
<p class="ldapIndent"><?php p($l->t('Usernames are used to store and assign (meta) data. In order to precisely identify and recognize users, each LDAP user will have a internal username. This requires a mapping from username to LDAP user. The created username is mapped to the UUID of the LDAP user. Additionally the DN is cached as well to reduce LDAP interaction, but it is not used for identification. If the DN changes, the changes will be found. The internal username is used all over. Clearing the mappings will have leftovers everywhere. Clearing the mappings is not configuration sensitive, it affects all LDAP configurations! Never clear the mappings in a production environment, only in a testing or experimental stage.'));?></p>
<p class="ldapIndent"><button id="ldap_action_clear_user_mappings" name="ldap_action_clear_user_mappings"><?php p($l->t('Clear Username-LDAP User Mapping'));?></button><br/><button id="ldap_action_clear_group_mappings" name="ldap_action_clear_group_mappings"><?php p($l->t('Clear Groupname-LDAP Group Mapping'));?></button></p>
<p class="ldapIndent"><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>
<?php print_unescaped($_['settingControls']); ?>
</fieldset>
</div>