From d7d11a0c6f9880e3327f067598a66fbf628a7150 Mon Sep 17 00:00:00 2001 From: Joshua Smith Date: Tue, 29 Oct 2019 16:27:57 -0700 Subject: [PATCH] ARTEMIS-2535 Add ignorePartialResultException option to LDAPLoginModule Active Directory servers are unable to handle referrals automatically. This causes a PartialResultException to be thrown if a referral is encountered beneath the base search DN, even if the LDAPLoginModule is set to ignore referrals. This option may be set to 'true' to ignore these exceptions, allowing login to proceed with the query results received before the exception was encountered. Note: there are no tests for this change as I could not reproduce the issue with the ApacheDS test server. The issue is specific to directory servers that don't support the ManageDsaIT control such as Active Directory. --- .../core/security/jaas/LDAPLoginModule.java | 64 ++++++++++++++----- docs/user-manual/en/security.md | 6 ++ 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/LDAPLoginModule.java b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/LDAPLoginModule.java index b56fde8116..ed9b8bad76 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/LDAPLoginModule.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/LDAPLoginModule.java @@ -23,6 +23,7 @@ import javax.naming.Name; import javax.naming.NameParser; import javax.naming.NamingEnumeration; import javax.naming.NamingException; +import javax.naming.PartialResultException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; @@ -84,6 +85,7 @@ public class LDAPLoginModule implements LoginModule { private static final String SASL_LOGIN_CONFIG_SCOPE = "saslLoginConfigScope"; private static final String AUTHENTICATE_USER = "authenticateUser"; private static final String REFERRAL = "referral"; + private static final String IGNORE_PARTIAL_RESULT_EXCEPTION = "ignorePartialResultException"; private static final String PASSWORD_CODEC = "passwordCodec"; private static final String CONNECTION_POOL = "connectionPool"; private static final String CONNECTION_TIMEOUT = "connectionTimeout"; @@ -131,6 +133,7 @@ public class LDAPLoginModule implements LoginModule { new LDAPLoginProperty(SASL_LOGIN_CONFIG_SCOPE, (String) options.get(SASL_LOGIN_CONFIG_SCOPE)), new LDAPLoginProperty(AUTHENTICATE_USER, (String) options.get(AUTHENTICATE_USER)), new LDAPLoginProperty(REFERRAL, (String) options.get(REFERRAL)), + new LDAPLoginProperty(IGNORE_PARTIAL_RESULT_EXCEPTION, (String) options.get(IGNORE_PARTIAL_RESULT_EXCEPTION)), new LDAPLoginProperty(CONNECTION_POOL, (String) options.get(CONNECTION_POOL)), new LDAPLoginProperty(CONNECTION_TIMEOUT, (String) options.get(CONNECTION_TIMEOUT))}; @@ -296,6 +299,7 @@ public class LDAPLoginModule implements LoginModule { MessageFormat userSearchMatchingFormat; boolean userSearchSubtreeBool; + boolean ignorePartialResultExceptionBool; if (logger.isDebugEnabled()) { logger.debug("Create the LDAP initial context."); @@ -314,6 +318,7 @@ public class LDAPLoginModule implements LoginModule { userSearchMatchingFormat = new MessageFormat(getLDAPPropertyValue(USER_SEARCH_MATCHING)); userSearchSubtreeBool = Boolean.valueOf(getLDAPPropertyValue(USER_SEARCH_SUBTREE)).booleanValue(); + ignorePartialResultExceptionBool = Boolean.valueOf(getLDAPPropertyValue(IGNORE_PARTIAL_RESULT_EXCEPTION)).booleanValue(); try { @@ -357,8 +362,17 @@ public class LDAPLoginModule implements LoginModule { SearchResult result = results.next(); - if (results.hasMore()) { - // ignore for now + try { + if (results.hasMore()) { + // ignore for now + } + } catch (PartialResultException e) { + // Workaround for AD servers not handling referrals correctly. + if (ignorePartialResultExceptionBool) { + logger.debug("PartialResultException encountered and ignored", e); + } else { + throw e; + } } if (result.isRelative()) { @@ -447,9 +461,11 @@ public class LDAPLoginModule implements LoginModule { MessageFormat roleSearchMatchingFormat; boolean roleSearchSubtreeBool; boolean expandRolesBool; + boolean ignorePartialResultExceptionBool; roleSearchMatchingFormat = new MessageFormat(getLDAPPropertyValue(ROLE_SEARCH_MATCHING)); roleSearchSubtreeBool = Boolean.valueOf(getLDAPPropertyValue(ROLE_SEARCH_SUBTREE)).booleanValue(); expandRolesBool = Boolean.valueOf(getLDAPPropertyValue(EXPAND_ROLES)).booleanValue(); + ignorePartialResultExceptionBool = Boolean.valueOf(getLDAPPropertyValue(IGNORE_PARTIAL_RESULT_EXCEPTION)).booleanValue(); final String filter = roleSearchMatchingFormat.format(new String[]{doRFC2254Encoding(dn), doRFC2254Encoding(username)}); @@ -477,13 +493,22 @@ public class LDAPLoginModule implements LoginModule { throw ex; } - while (results.hasMore()) { - SearchResult result = results.next(); - if (expandRolesBool) { - haveSeenNames.add(result.getNameInNamespace()); - pendingNameExpansion.add(result.getNameInNamespace()); + try { + while (results.hasMore()) { + SearchResult result = results.next(); + if (expandRolesBool) { + haveSeenNames.add(result.getNameInNamespace()); + pendingNameExpansion.add(result.getNameInNamespace()); + } + addRoleAttribute(result, currentRoles); + } + } catch (PartialResultException e) { + // Workaround for AD servers not handling referrals correctly. + if (ignorePartialResultExceptionBool) { + logger.debug("PartialResultException encountered and ignored", e); + } else { + throw e; } - addRoleAttribute(result, currentRoles); } if (expandRolesBool) { MessageFormat expandRolesMatchingFormat = new MessageFormat(getLDAPPropertyValue(EXPAND_ROLES_MATCHING)); @@ -504,13 +529,22 @@ public class LDAPLoginModule implements LoginModule { ex.initCause(cause); throw ex; } - while (results.hasMore()) { - SearchResult result = results.next(); - name = result.getNameInNamespace(); - if (!haveSeenNames.contains(name)) { - addRoleAttribute(result, currentRoles); - haveSeenNames.add(name); - pendingNameExpansion.add(name); + try { + while (results.hasMore()) { + SearchResult result = results.next(); + name = result.getNameInNamespace(); + if (!haveSeenNames.contains(name)) { + addRoleAttribute(result, currentRoles); + haveSeenNames.add(name); + pendingNameExpansion.add(name); + } + } + } catch (PartialResultException e) { + // Workaround for AD servers not handling referrals correctly. + if (ignorePartialResultExceptionBool) { + logger.debug("PartialResultException encountered and ignored", e); + } else { + throw e; } } } diff --git a/docs/user-manual/en/security.md b/docs/user-manual/en/security.md index 063fc28913..140fdc8bfb 100644 --- a/docs/user-manual/en/security.md +++ b/docs/user-manual/en/security.md @@ -708,6 +708,12 @@ system. It is implemented by - `referral` - specify how to handle referrals; valid values: `ignore`, `follow`, `throw`; default is `ignore`. + +- `ignorePartialResultException` - boolean flag for use when searching Active + Directory (AD). AD servers don't handle referrals automatically, which causes + a `PartialResultException` to be thrown when referrals are encountered by a + search, even if `referral` is set to `ignore`. Set to `true` to ignore these + exceptions; default is `false`. - `expandRoles` - boolean indicating whether to enable the role expansion functionality or not; default false. If enabled, then roles within roles will