]> source.dussan.org Git - nextcloud-server.git/commitdiff
code changes for user_ldap Dynamic Group Membership
authorAlex Weirig <alex.weirig@technolink.lu>
Thu, 14 Jan 2016 12:26:40 +0000 (13:26 +0100)
committerArthur Schiwon <blizzz@owncloud.com>
Wed, 3 Feb 2016 20:50:27 +0000 (21:50 +0100)
Added new setting of “Dynamic Group Member URL”
(ldapDynamicGroupMemberURL) - see LDAP settings advanced tab.

Added public function getDynamicGroupMembers.

Updated function _groupMembers.

Updated function getUserGroups.

apps/user_ldap/group_ldap.php
apps/user_ldap/js/wizard/wizardTabAdvanced.js
apps/user_ldap/lib/configuration.php
apps/user_ldap/templates/settings.php

index 76152e1780a74832bc9d1968b8a68f7ec551c6d6..add66d8e870d6fd42da47a2b3b5bb3922710d25a 100644 (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);
 
index 7367bfe87aeac407b4b7b7c1b4e002956d82fb00..9e898ba2fc8bd213a62184c6fbac9514814853e5 100644 (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…)
index 75d244255c6420e59d8177b206b485681a203a81..11090f1301b3c8b91ec14bd41d7c3ee67ca3495a 100644 (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;
        }
index 88900e22bf71f4db19b001f057a3cb07fd697ddd..1c0c9a8acb7b90d1900b6d8935b02244a9f26991 100644 (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>