From 5fec61a3bd0dbee9e31cf156148aa5bf5bb30c66 Mon Sep 17 00:00:00 2001 From: Anselm McClain Date: Fri, 26 Jul 2024 09:49:09 -0700 Subject: [PATCH 1/4] Add `LdapConfig` class to type+doc structure of `LdapService` soft-config --- CHANGELOG.md | 4 ++ .../io/xh/hoist/ldap/LdapService.groovy | 42 +++++++++---------- .../groovy/io/xh/hoist/ldap/LdapConfig.groovy | 21 ++++++++++ 3 files changed, 45 insertions(+), 22 deletions(-) create mode 100644 src/main/groovy/io/xh/hoist/ldap/LdapConfig.groovy diff --git a/CHANGELOG.md b/CHANGELOG.md index f2bafaed..8de69981 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ * Added configurable table name to `xhDbConnectionMonitor` status check to support edge case where XH tables are in a custom schema. +### ⚙️ Technical + +* Add `LdapConfig` class to type + document structure of primary `LdapService` soft-config. + ## 20.3.1 - 2024-07-23 ### 🐞 Bug Fixes diff --git a/grails-app/services/io/xh/hoist/ldap/LdapService.groovy b/grails-app/services/io/xh/hoist/ldap/LdapService.groovy index e3fd2339..d271731b 100644 --- a/grails-app/services/io/xh/hoist/ldap/LdapService.groovy +++ b/grails-app/services/io/xh/hoist/ldap/LdapService.groovy @@ -13,16 +13,9 @@ import static grails.async.Promises.task * Service to query a set of LDAP servers for People, Groups, and Group memberships. * * Requires the following application configs: - * - 'xhLdapConfig' with the following options - * - enabled - true to enable - * - timeoutMs - time to wait for any individual search to resolve. - * - cacheExpireSecs - length of time to cache results. Set to -1 to disable caching. - * - servers - list of servers to be queried, each containing: - * - host - * - baseUserDn - * - baseGroupDn - * - 'xhLdapUsername' - dn of query user. - * - 'xhLdapPassword' - password for user + * - 'xhLdapConfig' - see {@link LdapConfig} for shape / properties + * - 'xhLdapUsername' - dn of query user + * - 'xhLdapPassword' - password for query user * * This service will cache results, per server, for the configured interval. * This service may return partial results if any particular server fails to return results. @@ -46,10 +39,9 @@ class LdapService extends BaseService { } boolean getEnabled() { - config.enabled + config.enabled && queryUsername != 'none' } - LdapPerson lookupUser(String sName) { searchOne("(sAMAccountName=$sName) ", LdapPerson, true) } @@ -81,7 +73,7 @@ class LdapService extends BaseService { */ Map> lookupGroupMembers(Set dns, boolean strictMode = false) { dns.collectEntries { dn -> [dn, task { lookupGroupMembersInternal(dn, strictMode) }] } - .collectEntries { [it.key, it.value.get()]} + .collectEntries { [it.key, it.value.get()] } } /** @@ -127,29 +119,27 @@ class LdapService extends BaseService { searchMany("(|(memberOf=$dn) (memberOf:1.2.840.113556.1.4.1941:=$dn))", LdapPerson, strictMode) } - private List doQuery(Map server, String baseFilter, Class objType, boolean strictMode) { + private List doQuery(LdapServerConfig server, String baseFilter, Class objType, boolean strictMode) { if (!enabled) throw new RuntimeException('LdapService is not enabled.') boolean isPerson = LdapPerson.class.isAssignableFrom(objType) String host = server.host, - filter = "(&(objectCategory=${isPerson ? 'Person' : 'Group'})$baseFilter)", - key = server.toString() + filter + filter = "(&(objectCategory=${isPerson ? 'Person' : 'Group'})$baseFilter)", + key = server.toString() + filter List ret = cache.get(key) if (ret != null) return ret withDebug(["Querying LDAP", [host: host, filter: filter]]) { try (LdapNetworkConnection conn = new LdapNetworkConnection(host)) { - String baseDn = isPerson ? server.baseUserDn : server.baseGroupDn, - username = configService.getString('xhLdapUsername'), - password = configService.getPwd('xhLdapPassword') + String baseDn = isPerson ? server.baseUserDn : server.baseGroupDn String[] keys = objType.keys.toArray() as String[] conn.timeOut = config.timeoutMs as Long boolean didBind = false try { - conn.bind(username, password) + conn.bind(queryUsername, queryUserPwd) didBind = true ret = conn.search(baseDn, filter, SearchScope.SUBTREE, keys) .collect { objType.create(it.attributes as Collection) } @@ -167,8 +157,16 @@ class LdapService extends BaseService { return ret } - private Map getConfig() { - configService.getMap('xhLdapConfig') + private LdapConfig getConfig() { + new LdapConfig(configService.getMap('xhLdapConfig')) + } + + private String getQueryUsername() { + configService.getString('xhLdapUsername') + } + + private String getQueryUserPwd() { + configService.getPwd('xhLdapPassword') } private void initCache() { diff --git a/src/main/groovy/io/xh/hoist/ldap/LdapConfig.groovy b/src/main/groovy/io/xh/hoist/ldap/LdapConfig.groovy new file mode 100644 index 00000000..2f62421d --- /dev/null +++ b/src/main/groovy/io/xh/hoist/ldap/LdapConfig.groovy @@ -0,0 +1,21 @@ +package io.xh.hoist.ldap + +import groovy.transform.MapConstructor + +/** + * Typed representation of `xhLdapConfig` values. + */ +@MapConstructor +class LdapConfig { + Boolean enabled + Integer timeoutMs + Integer cacheExpireSecs + List servers +} + +@MapConstructor +class LdapServerConfig { + String host + String baseUserDn + String baseGroupDn +} From 4626c2b9974ac896b77fe91697c8193a004bae3b Mon Sep 17 00:00:00 2001 From: Anselm McClain Date: Mon, 5 Aug 2024 16:43:37 -0700 Subject: [PATCH 2/4] Rollback change to getEnabled() - dealing w/that in #379 --- grails-app/services/io/xh/hoist/ldap/LdapService.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grails-app/services/io/xh/hoist/ldap/LdapService.groovy b/grails-app/services/io/xh/hoist/ldap/LdapService.groovy index d271731b..668147b5 100644 --- a/grails-app/services/io/xh/hoist/ldap/LdapService.groovy +++ b/grails-app/services/io/xh/hoist/ldap/LdapService.groovy @@ -39,7 +39,7 @@ class LdapService extends BaseService { } boolean getEnabled() { - config.enabled && queryUsername != 'none' + config.enabled } LdapPerson lookupUser(String sName) { From 3c225509c88c643d2bd7ef611ea9f631d29d395d Mon Sep 17 00:00:00 2001 From: Anselm McClain Date: Mon, 5 Aug 2024 17:33:43 -0700 Subject: [PATCH 3/4] Remove dupe methods --- grails-app/services/io/xh/hoist/ldap/LdapService.groovy | 8 -------- 1 file changed, 8 deletions(-) diff --git a/grails-app/services/io/xh/hoist/ldap/LdapService.groovy b/grails-app/services/io/xh/hoist/ldap/LdapService.groovy index df83f50c..c3940539 100644 --- a/grails-app/services/io/xh/hoist/ldap/LdapService.groovy +++ b/grails-app/services/io/xh/hoist/ldap/LdapService.groovy @@ -170,14 +170,6 @@ class LdapService extends BaseService { configService.getPwd('xhLdapPassword') } - private String getQueryUsername() { - configService.getString('xhLdapUsername') - } - - private String getQueryUserPwd() { - configService.getPwd('xhLdapPassword') - } - private void initCache() { cache = new Cache(svc: this, expireTime: config.cacheExpireSecs * SECONDS) } From 9a48a5c1c8bd1b211ae7e40f9ea3af2b020fb2f1 Mon Sep 17 00:00:00 2001 From: Anselm McClain Date: Mon, 5 Aug 2024 18:59:16 -0700 Subject: [PATCH 4/4] Move new config classes into same file as service --- .../io/xh/hoist/ldap/LdapService.groovy | 20 ++++++++++++++++++ .../groovy/io/xh/hoist/ldap/LdapConfig.groovy | 21 ------------------- 2 files changed, 20 insertions(+), 21 deletions(-) delete mode 100644 src/main/groovy/io/xh/hoist/ldap/LdapConfig.groovy diff --git a/grails-app/services/io/xh/hoist/ldap/LdapService.groovy b/grails-app/services/io/xh/hoist/ldap/LdapService.groovy index c3940539..dcf18f20 100644 --- a/grails-app/services/io/xh/hoist/ldap/LdapService.groovy +++ b/grails-app/services/io/xh/hoist/ldap/LdapService.groovy @@ -1,5 +1,6 @@ package io.xh.hoist.ldap +import groovy.transform.MapConstructor import io.xh.hoist.BaseService import io.xh.hoist.cache.Cache import org.apache.directory.api.ldap.model.entry.Attribute @@ -179,3 +180,22 @@ class LdapService extends BaseService { super.clearCaches() } } + + +/** + * Typed representation of `xhLdapConfig` values. + */ +@MapConstructor +class LdapConfig { + Boolean enabled + Integer timeoutMs + Integer cacheExpireSecs + List servers +} + +@MapConstructor +class LdapServerConfig { + String host + String baseUserDn + String baseGroupDn +} diff --git a/src/main/groovy/io/xh/hoist/ldap/LdapConfig.groovy b/src/main/groovy/io/xh/hoist/ldap/LdapConfig.groovy deleted file mode 100644 index 2f62421d..00000000 --- a/src/main/groovy/io/xh/hoist/ldap/LdapConfig.groovy +++ /dev/null @@ -1,21 +0,0 @@ -package io.xh.hoist.ldap - -import groovy.transform.MapConstructor - -/** - * Typed representation of `xhLdapConfig` values. - */ -@MapConstructor -class LdapConfig { - Boolean enabled - Integer timeoutMs - Integer cacheExpireSecs - List servers -} - -@MapConstructor -class LdapServerConfig { - String host - String baseUserDn - String baseGroupDn -}