code changes for user_ldap Dynamic Group Membership

Added new setting of “Dynamic Group Member URL”
(ldapDynamicGroupMemberURL) - see LDAP settings advanced tab.

Added public function getDynamicGroupMembers.

Updated function _groupMembers.

Updated function getUserGroups.
This commit is contained in:
Alex Weirig 2016-01-14 13:26:40 +01:00 committed by Arthur Schiwon
parent da04620155
commit 0d797637f3
4 changed files with 108 additions and 5 deletions

View File

@ -12,6 +12,7 @@
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
* @author Richard Bentley <rbentley@e2advance.com>
*
* @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
@ -146,6 +147,46 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
return $isInGroup;
}
/**
* @param string $dnGroup
* @return array
*
* For a group that has user membership defined by an LDAP search url attribute returns the users
* that match the search url otherwise returns an empty array.
*/
public function getDynamicGroupMembers($dnGroup) {
$dynamicGroupMemberURL = strtolower($this->access->connection->ldapDynamicGroupMemberURL);
if (empty($dynamicGroupMemberURL)) {
return array();
}
$dynamicMembers = array();
$memberURLs = $this->access->readAttribute(
$dnGroup,
$dynamicGroupMemberURL,
$this->access->connection->ldapGroupFilter
);
if ($memberURLs !== false) {
// this group has the 'memberURL' attribute so this is a dynamic group
// example 1: ldap:///cn=users,cn=accounts,dc=dcsubbase,dc=dcbase??one?(o=HeadOffice)
// example 2: ldap:///cn=users,cn=accounts,dc=dcsubbase,dc=dcbase??one?(&(o=HeadOffice)(uidNumber>=500))
$pos = strpos($memberURLs[0], '(');
if ($pos !== false) {
$memberUrlFilter = substr($memberURLs[0], $pos);
$foundMembers = $this->access->searchUsers($memberUrlFilter,'dn');
$dynamicMembers = array();
foreach($foundMembers as $value) {
$dynamicMembers[$value['dn'][0]] = 1;
}
} else {
\OCP\Util::writeLog('user_ldap', 'No search filter found on member url '.
'of group ' . $dnGroup, \OCP\Util::DEBUG);
}
}
return $dynamicMembers;
}
/**
* @param string $dnGroup
* @param array|null &$seen
@ -180,6 +221,9 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
}
}
}
$allMembers = array_merge($allMembers, $this->getDynamicGroupMembers($dnGroup));
$this->access->connection->writeToCache($cacheKey, $allMembers);
return $allMembers;
}
@ -387,6 +431,8 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
*
* This function fetches all groups a user belongs to. It does not check
* if the user exists at all.
*
* This function includes groups based on dynamic group membership.
*/
public function getUserGroups($uid) {
if(!$this->enabled) {
@ -405,6 +451,8 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
$groups = [];
$primaryGroup = $this->getUserPrimaryGroup($userDN);
$dynamicGroupMemberURL = strtolower($this->access->connection->ldapDynamicGroupMemberURL);
// if possible, read out membership via memberOf. It's far faster than
// performing a search, which still is a fallback later.
if(intval($this->access->connection->hasMemberOfFilterSupport) === 1
@ -422,11 +470,15 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
}
}
if($primaryGroup !== false) {
$groups[] = $primaryGroup;
if (empty($dynamicGroupMemberURL)) {
// if dynamic group membership is not enabled then we can return
// straight away
if($primaryGroup !== false) {
$groups[] = $primaryGroup;
}
$this->access->connection->writeToCache($cacheKey, $groups);
return $groups;
}
$this->access->connection->writeToCache($cacheKey, $groups);
return $groups;
}
//uniqueMember takes DN, memberuid the uid, so we need to distinguish
@ -458,6 +510,39 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
$groups[] = $primaryGroup;
}
if (!empty($dynamicGroupMemberURL)) {
// look through dynamic groups to add them to the result array if needed
$groupsToMatch = $this->access->fetchListOfGroups(
$this->access->connection->ldapGroupFilter,array('dn',$dynamicGroupMemberURL));
foreach($groupsToMatch as $value) {
if (!array_key_exists($dynamicGroupMemberURL, $value)) {
continue;
}
$pos = strpos($value[$dynamicGroupMemberURL][0], '(');
if ($pos !== false) {
$memberUrlFilter = substr($value[$dynamicGroupMemberURL][0],$pos);
// apply filter via ldap search to see if this user is in this
// dynamic group
$userMatch = $this->access->readAttribute(
$uid,
$this->access->connection->ldapUserDisplayName,
$memberUrlFilter
);
if ($userMatch !== false) {
// match found so this user is in this group
$pos = strpos($value['dn'][0], ',');
if ($pos !== false) {
$membershipGroup = substr($value['dn'][0],3,$pos-3);
$groups[] = $membershipGroup;
}
}
} else {
\OCP\Util::writeLog('user_ldap', 'No search filter found on member url '.
'of group ' . $dnGroup, \OCP\Util::DEBUG);
}
}
}
$groups = array_unique($groups, SORT_LOCALE_STRING);
$this->access->connection->writeToCache($cacheKey, $groups);

View File

@ -79,6 +79,10 @@ OCA = OCA || {};
$element: $('#ldap_group_member_assoc_attribute'),
setMethod: 'setGroupMemberAssociationAttribute'
},
ldap_dynamic_group_member_url: {
$element: $('#ldap_dynamic_group_member_url'),
setMethod: 'setDynamicGroupMemberURL'
},
ldap_nested_groups: {
$element: $('#ldap_nested_groups'),
setMethod: 'setUseNestedGroups'
@ -244,6 +248,15 @@ OCA = OCA || {};
this.setElementValue(this.managedItems.ldap_group_member_assoc_attribute.$element, attribute);
},
/**
* sets the dynamic group member url attribute
*
* @param {string} attribute
*/
setDynamicGroupMemberURL: function(attribute) {
this.setElementValue(this.managedItems.ldap_dynamic_group_member_url.$element, attribute);
},
/**
* enabled or disables the use of nested groups (groups in groups in
* groups)

View File

@ -7,6 +7,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Richard Bentley <rbentley@e2advance.com>
*
* @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
@ -83,6 +84,7 @@ class Configuration {
'lastJpegPhotoLookup' => null,
'ldapNestedGroups' => false,
'ldapPagingSize' => null,
'ldapDynamicGroupMemberURL' => null,
);
/**
@ -439,6 +441,7 @@ class Configuration {
'ldap_nested_groups' => 0,
'ldap_paging_size' => 500,
'ldap_experienced_admin' => 0,
'ldap_dynamic_group_member_url' => '',
);
}
@ -492,7 +495,8 @@ class Configuration {
'last_jpegPhoto_lookup' => 'lastJpegPhotoLookup',
'ldap_nested_groups' => 'ldapNestedGroups',
'ldap_paging_size' => 'ldapPagingSize',
'ldap_experienced_admin' => 'ldapExperiencedAdmin'
'ldap_experienced_admin' => 'ldapExperiencedAdmin',
'ldap_dynamic_group_member_url' => 'ldapDynamicGroupMemberURL',
);
return $array;
}

View File

@ -90,6 +90,7 @@ style('user_ldap', 'settings');
<p><label for="ldap_base_groups"><?php p($l->t('Base Group Tree'));?></label><textarea id="ldap_base_groups" name="ldap_base_groups" placeholder="<?php p($l->t('One Group Base DN per line'));?>" data-default="<?php p($_['ldap_base_groups_default']); ?>" title="<?php p($l->t('Base Group Tree'));?>"></textarea></p>
<p><label for="ldap_attributes_for_group_search"><?php p($l->t('Group Search Attributes'));?></label><textarea id="ldap_attributes_for_group_search" name="ldap_attributes_for_group_search" placeholder="<?php p($l->t('Optional; one attribute per line'));?>" data-default="<?php p($_['ldap_attributes_for_group_search_default']); ?>" title="<?php p($l->t('Group Search Attributes'));?>"></textarea></p>
<p><label for="ldap_group_member_assoc_attribute"><?php p($l->t('Group-Member association'));?></label><select id="ldap_group_member_assoc_attribute" name="ldap_group_member_assoc_attribute" data-default="<?php p($_['ldap_group_member_assoc_attribute_default']); ?>" ><option value="uniqueMember"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'uniqueMember')) p(' selected'); ?>>uniqueMember</option><option value="memberUid"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'memberUid')) p(' selected'); ?>>memberUid</option><option value="member"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'member')) p(' selected'); ?>>member (AD)</option></select></p>
<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>
</div>