summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/user_ldap/group_ldap.php81
-rw-r--r--apps/user_ldap/js/wizard/wizardTabAdvanced.js13
-rw-r--r--apps/user_ldap/lib/configuration.php6
-rw-r--r--apps/user_ldap/templates/settings.php1
-rw-r--r--apps/user_ldap/tests/group_ldap.php13
5 files changed, 109 insertions, 5 deletions
diff --git a/apps/user_ldap/group_ldap.php b/apps/user_ldap/group_ldap.php
index 76152e1780a..05ab9ddfaae 100644
--- a/apps/user_ldap/group_ldap.php
+++ b/apps/user_ldap/group_ldap.php
@@ -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
@@ -148,6 +149,46 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
/**
* @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
* @return array|mixed|null
*/
@@ -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,41 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
$groups = [];
$primaryGroup = $this->getUserPrimaryGroup($userDN);
+ $dynamicGroupMemberURL = strtolower($this->access->connection->ldapDynamicGroupMemberURL);
+
+ 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 $dynamicGroup) {
+ if (!array_key_exists($dynamicGroupMemberURL, $dynamicGroup)) {
+ continue;
+ }
+ $pos = strpos($dynamicGroup[$dynamicGroupMemberURL][0], '(');
+ if ($pos !== false) {
+ $memberUrlFilter = substr($dynamicGroup[$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($dynamicGroup['dn'][0], ',');
+ if ($pos !== false) {
+ $membershipGroup = substr($dynamicGroup['dn'][0],3,$pos-3);
+ $groups[] = $membershipGroup;
+ }
+ }
+ } else {
+ \OCP\Util::writeLog('user_ldap', 'No search filter found on member url '.
+ 'of group ' . print_r($dynamicGroup, true), \OCP\Util::DEBUG);
+ }
+ }
+ }
+
// 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
diff --git a/apps/user_ldap/js/wizard/wizardTabAdvanced.js b/apps/user_ldap/js/wizard/wizardTabAdvanced.js
index 7367bfe87ae..9e898ba2fc8 100644
--- a/apps/user_ldap/js/wizard/wizardTabAdvanced.js
+++ b/apps/user_ldap/js/wizard/wizardTabAdvanced.js
@@ -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'
@@ -245,6 +249,15 @@ OCA = OCA || {};
},
/**
+ * 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…)
*
diff --git a/apps/user_ldap/lib/configuration.php b/apps/user_ldap/lib/configuration.php
index 75d244255c6..11090f1301b 100644
--- a/apps/user_ldap/lib/configuration.php
+++ b/apps/user_ldap/lib/configuration.php
@@ -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;
}
diff --git a/apps/user_ldap/templates/settings.php b/apps/user_ldap/templates/settings.php
index 88900e22bf7..1c0c9a8acb7 100644
--- a/apps/user_ldap/templates/settings.php
+++ b/apps/user_ldap/templates/settings.php
@@ -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>
diff --git a/apps/user_ldap/tests/group_ldap.php b/apps/user_ldap/tests/group_ldap.php
index 5f9ded878ca..667a1c3acb2 100644
--- a/apps/user_ldap/tests/group_ldap.php
+++ b/apps/user_ldap/tests/group_ldap.php
@@ -67,10 +67,13 @@ class Test_Group_Ldap extends \Test\TestCase {
private function enableGroups($access) {
$access->connection->expects($this->any())
- ->method('__get')
- ->will($this->returnCallback(function() {
- return 1;
- }));
+ ->method('__get')
+ ->will($this->returnCallback(function($name) {
+ if($name === 'ldapDynamicGroupMemberURL') {
+ return '';
+ }
+ return 1;
+ }));
}
public function testCountEmptySearchString() {
@@ -430,6 +433,8 @@ class Test_Group_Ldap extends \Test\TestCase {
->will($this->returnCallback(function($name) {
if($name === 'useMemberOfToDetectMembership') {
return 0;
+ } else if($name === 'ldapDynamicGroupMemberURL') {
+ return '';
}
return 1;
}));