From 59f1a70d5ebdf0906e8352f81f6ae2d1bd00a0d1 Mon Sep 17 00:00:00 2001
From: Rune Darrud <theflyingcorpse@gmail.com>
Date: Tue, 30 Aug 2016 22:26:56 +0200
Subject: [PATCH] Add support for nested AD groups resolved from the user

This will make sure that nested groups also work with roles.

Signed-off-by: Alexander A. Klimov <alexander.klimov@icinga.com>

refs #12598
---
 .../UserGroup/LdapUserGroupBackendForm.php    | 13 +++++
 .../UserGroup/LdapUserGroupBackend.php        | 53 +++++++++++++++++--
 2 files changed, 61 insertions(+), 5 deletions(-)

diff --git a/application/forms/Config/UserGroup/LdapUserGroupBackendForm.php b/application/forms/Config/UserGroup/LdapUserGroupBackendForm.php
index 35b32580f..ac89d1777 100644
--- a/application/forms/Config/UserGroup/LdapUserGroupBackendForm.php
+++ b/application/forms/Config/UserGroup/LdapUserGroupBackendForm.php
@@ -89,6 +89,19 @@ class LdapUserGroupBackendForm extends Form
             $groupConfigDisabled = $userConfigDisabled = true;
         }
 
+        if ($formData['type'] === 'msldap') {
+            $this->addElement(
+                'checkbox',
+                'nested_group_search_in_ad',
+                array(
+                    'description'   => $this->translate(
+                        'Check this box for nested group search in Active Directory based on the user'
+                    ),
+                    'label'         => $this->translate('Nested Group Search')
+                )
+            );
+        }
+
         $this->createGroupConfigElements($defaults, $groupConfigDisabled);
         if (count($userBackends) === 1 || (isset($formData['user_backend']) && $formData['user_backend'] === 'none')) {
             $this->createUserConfigElements($defaults, $userConfigDisabled);
diff --git a/library/Icinga/Authentication/UserGroup/LdapUserGroupBackend.php b/library/Icinga/Authentication/UserGroup/LdapUserGroupBackend.php
index 3f912b0ca..d8db257af 100644
--- a/library/Icinga/Authentication/UserGroup/LdapUserGroupBackend.php
+++ b/library/Icinga/Authentication/UserGroup/LdapUserGroupBackend.php
@@ -93,6 +93,13 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
      */
     protected $groupFilter;
 
+    /**
+     * ActiveDirectory nested group on the user?
+     *
+     * @var bool
+     */
+    protected $nestedGroupSearchInAD;
+
     /**
      * The columns which are not permitted to be queried
      *
@@ -364,6 +371,33 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
         return $this->groupFilter;
     }
 
+    /**
+     * Set nestedGroupSearchInAD for the group query
+     *
+     * @param string $enable
+     *
+     * @return bool
+     */
+    public function setNestedGroupSearchInAD($enable)
+    {
+        if ($enable == "1") {
+           $this->nestedGroupSearchInAD = true;
+        } else {
+           $this->nestedGroupSearchInAD = false;
+        }
+        return $this;
+    }
+
+    /**
+     * Get nestedGroupSearchInAD for the group query
+     *
+     * @return bool
+     */
+    public function getNestedGroupSearchInAD()
+    {
+        return $this->nestedGroupSearchInAD;
+    }
+
     /**
      * Return whether the attribute name where to find a group's member holds ambiguous values
      *
@@ -620,10 +654,16 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
             }
         }
 
+	if ($this->nestedGroupSearchInAD) {
+                $groupMemberAttribute = $this->groupMemberAttribute . ':1.2.840.113556.1.4.1941:';
+        } else {
+                $groupMemberAttribute = $this->groupMemberAttribute;
+        }
+
         $groupQuery = $this->ds
             ->select()
             ->from($this->groupClass, array($this->groupNameAttribute))
-            ->where($this->groupMemberAttribute, $queryValue)
+            ->where($groupMemberAttribute, $queryValue)
             ->setBase($this->groupBaseDn);
         if ($this->groupFilter) {
             $groupQuery->setNativeFilter($this->groupFilter);
@@ -706,7 +746,8 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
             ->setUserNameAttribute($config->get('user_name_attribute', $defaults->user_name_attribute))
             ->setGroupMemberAttribute($config->get('group_member_attribute', $defaults->group_member_attribute))
             ->setGroupFilter($config->group_filter)
-            ->setUserFilter($config->user_filter);
+            ->setUserFilter($config->user_filter)
+            ->setNestedGroupSearchInAD($config->get('nested_group_search_in_ad', $defaults->nested_group_search_in_ad));
     }
 
     /**
@@ -721,7 +762,8 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
             'user_class'                => 'inetOrgPerson',
             'group_name_attribute'      => 'gid',
             'user_name_attribute'       => 'uid',
-            'group_member_attribute'    => 'member'
+            'group_member_attribute'    => 'member',
+            'nested_group_search_in_ad' => '0'
         ));
     }
 
@@ -737,7 +779,8 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
             'user_class'                => 'user',
             'group_name_attribute'      => 'sAMAccountName',
             'user_name_attribute'       => 'sAMAccountName',
-            'group_member_attribute'    => 'member'
+            'group_member_attribute'    => 'member',
+            'nested_group_search_in_ad' => '0'
         ));
     }
-}
\ No newline at end of file
+}