GUACAMOLE-996: Merge add support for specifying an LDAP group filter.

diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/ConfigurationService.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/ConfigurationService.java
index 769d4c3..2071dfa 100644
--- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/ConfigurationService.java
+++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/ConfigurationService.java
@@ -322,6 +322,26 @@
     }
 
     /**
+     * Returns the search filter that should be used when querying the
+     * LDAP server for Guacamole groups.  If no filter is specified,
+     * a default of "(objectClass=*)" is used.
+     *
+     * @return
+     *     The search filter that should be used when querying the
+     *     LDAP server for groups that are valid in Guacamole, or
+     *     "(objectClass=*)" if not specified.
+     *
+     * @throws GuacamoleException
+     *     If guacamole.properties cannot be parsed.
+     */
+    public ExprNode getGroupSearchFilter() throws GuacamoleException {
+        return environment.getProperty(
+            LDAPGuacamoleProperties.LDAP_GROUP_SEARCH_FILTER,
+            new PresenceNode("objectClass")
+        );
+    }
+
+    /**
      * Returns the maximum number of seconds to wait for LDAP operations.
      *
      * @return
diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/LDAPGuacamoleProperties.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/LDAPGuacamoleProperties.java
index 2313629..5bf5cfb 100644
--- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/LDAPGuacamoleProperties.java
+++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/LDAPGuacamoleProperties.java
@@ -211,6 +211,17 @@
     };
 
     /**
+     * A search filter to apply to group LDAP queries.
+     */
+    public static final LdapFilterGuacamoleProperty LDAP_GROUP_SEARCH_FILTER =
+            new LdapFilterGuacamoleProperty() {
+
+        @Override
+        public String getName() { return "ldap-group-search-filter"; }
+
+    };
+
+    /**
      * Whether or not we should follow referrals.
      */
     public static final BooleanGuacamoleProperty LDAP_FOLLOW_REFERRALS =
diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/group/UserGroupService.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/group/UserGroupService.java
index 66f4612..6d97a93 100644
--- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/group/UserGroupService.java
+++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/group/UserGroupService.java
@@ -28,10 +28,10 @@
 import java.util.Set;
 import org.apache.directory.api.ldap.model.entry.Entry;
 import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.filter.AndNode;
 import org.apache.directory.api.ldap.model.filter.EqualityNode;
 import org.apache.directory.api.ldap.model.filter.ExprNode;
 import org.apache.directory.api.ldap.model.filter.NotNode;
-import org.apache.directory.api.ldap.model.filter.PresenceNode;
 import org.apache.directory.api.ldap.model.name.Dn;
 import org.apache.directory.ldap.client.api.LdapNetworkConnection;
 import org.apache.guacamole.auth.ldap.conf.ConfigurationService;
@@ -81,16 +81,22 @@
      */
     private ExprNode getGroupSearchFilter() throws GuacamoleException {
 
+        // Use filter defined by "ldap-group-search-filter" as basis for all
+        // retrieval of user groups
+        ExprNode groupFilter = confService.getGroupSearchFilter();
+
         // Explicitly exclude guacConfigGroup object class only if it should
         // be assumed to be defined (query may fail due to no such object
         // class existing otherwise)
-        if (confService.getConfigurationBaseDN() != null)
-            return new NotNode(new EqualityNode("objectClass","guacConfigGroup"));
+        if (confService.getConfigurationBaseDN() != null) {
+            groupFilter = new AndNode(
+                groupFilter,
+                new NotNode(new EqualityNode<String>("objectClass", "guacConfigGroup"))
+            );
+        }
 
-        // Read any object as a group if LDAP is not being used for connection
-        // storage (guacConfigGroup)
-        return new PresenceNode("objectClass");
-
+        return groupFilter;
+        
     }
 
     /**
diff --git a/guacamole-docker/bin/start.sh b/guacamole-docker/bin/start.sh
index e6bd50e..062e16a 100755
--- a/guacamole-docker/bin/start.sh
+++ b/guacamole-docker/bin/start.sh
@@ -443,6 +443,7 @@
     set_optional_property "ldap-user-search-filter"         "$LDAP_USER_SEARCH_FILTER"
     set_optional_property "ldap-config-base-dn"             "$LDAP_CONFIG_BASE_DN"
     set_optional_property "ldap-group-base-dn"              "$LDAP_GROUP_BASE_DN"
+    set_optional_property "ldap-group-search-filter"        "$LDAP_GROUP_SEARCH_FILTER"
     set_optional_property "ldap-member-attribute-type"      "$LDAP_MEMBER_ATTRIBUTE_TYPE"
     set_optional_property "ldap-group-name-attribute"       "$LDAP_GROUP_NAME_ATTRIBUTE"
     set_optional_property "ldap-dereference-aliases"        "$LDAP_DEREFERENCE_ALIASES"