@@ -21,21 +21,21 @@ import static io.xh.hoist.util.DateTimeUtils.SECONDS
21
21
* - timeoutMs - time to wait for any individual search to resolve.
22
22
* - cacheExpireSecs - length of time to cache results. Set to -1 to disable caching.
23
23
* - skipTlsCertVerification - true to accept untrusted certificates when binding
24
- * - servers - list of servers to be queried, each containing:
25
- * - host
26
- * - baseUserDn
27
- * - baseGroupDn
24
+ * - useMatchingRuleInChain - true to use Microsoft Active Directory's proprietary
25
+ * "LDAP_MATCHING_RULE_IN_CHAIN" rule (the magic `1.2.840.113556.1.4.1941` string below).
26
+ * This can be a more efficient way to resolve users in nested groups but should be used
27
+ * with caution, as it can trigger a large database walk, which has a significant
28
+ * performance impact that is unnecessary when queries are not expected to return deeply
29
+ * nested groups.
30
+ * - servers - list of servers to be queried, each containing:
31
+ * - host
32
+ * - baseUserDn
33
+ * - baseGroupDn
28
34
* - 'xhLdapUsername' - dn of query user.
29
35
* - 'xhLdapPassword' - password for user
30
36
*
31
37
* This service will cache results, per server, for the configured interval.
32
38
* This service may return partial results if any particular server fails to return results.
33
- *
34
- * Note that the implementation of `lookupGroupMembers()` is currently specific to Microsoft Active
35
- * Directory, due to the use of the proprietary "LDAP_MATCHING_RULE_IN_CHAIN" rule OID (the magic
36
- * `1.2.840.113556.1.4.1941` string below). This is an efficient way to resolve users in nested
37
- * groups, but would require an alternate implementation if this service is required to work with
38
- * more generic LDAP deployments.
39
39
*/
40
40
class LdapService extends BaseService {
41
41
@@ -157,7 +157,27 @@ class LdapService extends BaseService {
157
157
158
158
private List<LdapPerson > lookupGroupMembersInternal (String dn , boolean strictMode ) {
159
159
// See class-level comment regarding this AD-specific query
160
- searchMany(" (|(memberOf=$dn ) (memberOf:1.2.840.113556.1.4.1941:=$dn ))" , LdapPerson , strictMode)
160
+ config. useMatchingRuleInChain ?
161
+ searchMany(" (|(memberOf=$dn ) (memberOf:1.2.840.113556.1.4.1941:=$dn ))" , LdapPerson , strictMode) :
162
+ lookupMembersRecursive(dn, strictMode). values(). asList()
163
+ }
164
+
165
+ private Map<String , LdapPerson > lookupMembersRecursive (
166
+ String dn ,
167
+ boolean strictMode ,
168
+ Map<String , LdapPerson > members = new HashMap (),
169
+ Set<String > visited = new HashSet<String > ()
170
+ ) {
171
+ if (visited. add(dn)) {
172
+ // Add direct users
173
+ searchMany(" (memberOf=$dn )" , LdapPerson , strictMode)
174
+ .each { members[it. distinguishedname] = it}
175
+
176
+ // Recursively add nested groups
177
+ searchMany(" (memberOf=$dn )" , LdapGroup , strictMode)
178
+ .each {lookupMembersRecursive(it. distinguishedname, strictMode, members, visited)}
179
+ }
180
+ return members
161
181
}
162
182
163
183
private <T extends LdapObject > List<T> doQuery (Map server , String baseFilter , Class<T> objType , boolean strictMode ) {
0 commit comments