From 6fdad6039fa0f8020c94c1dbaebe0184f73d8df0 Mon Sep 17 00:00:00 2001 From: Jay Modi Date: Thu, 13 Jul 2017 10:08:22 -0600 Subject: [PATCH] Allow the Active Directory UPN authenticator to work with suffixes (elastic/x-pack-elasticsearch#1958) The active directory user principal name format typically takes the form user@domain, which is what the current implementation expects. However, active directory also allows the definition of other suffixes that are not actual domains. A user can still authenticate using this user principal name but the behavior of our realm would cause it to fail as it parsed the suffix as a domain and used it as the search base for the user. Instead, we should use the default user search base and only look for entries that have this exact user principal name. In a scenario where a realm is configured for multiple domains in the same forest, the search base should be the base for the entire forest. relates elastic/x-pack-elasticsearch#1744 Original commit: elastic/x-pack-elasticsearch@de00c4817ed54183725bead9d9db0d92a1031212 --- .../active-directory-realm.asciidoc | 8 +++----- docs/en/settings/security-settings.asciidoc | 8 +++----- .../ldap/ActiveDirectorySessionFactory.java | 17 +++++++++++------ 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/docs/en/security/authentication/active-directory-realm.asciidoc b/docs/en/security/authentication/active-directory-realm.asciidoc index 17f5bdde90f..6e4de52c365 100644 --- a/docs/en/security/authentication/active-directory-realm.asciidoc +++ b/docs/en/security/authentication/active-directory-realm.asciidoc @@ -242,12 +242,10 @@ operation are supported: failover and load balancing `(&(objectClass=user)(sAMAccountName={0}))`. For more information, see https://msdn.microsoft.com/en-us/library/aa746475(v=vs.85).aspx[Search Filter Syntax]. | `user_search.upn_filter` | no | Specifies a filter to use to lookup a user given a user principal name. - The default filter looks up `user` objects with either - a matching `userPrincipalName` or a `sAMAccountName` matching the account - portion of the user principal name. If specified, this + The default filter looks up `user` objects with + a matching `userPrincipalName`. If specified, this must be a valid LDAP user search filter, for example - `(&(objectClass=user)(sAMAccountName={0}))`. `{0}` is the value - preceding the `@` sign in the user principal name and `{1}` is + `(&(objectClass=user)(userPrincipalName={1}))`. `{1}` is the full user principal name provided by the user. For more information, see https://msdn.microsoft.com/en-us/library/aa746475(v=vs.85).aspx[Search Filter Syntax]. | `user_search.down_level_filter` | no | Specifies a filter to use to lookup a user given a down level logon name (DOMAIN\user). diff --git a/docs/en/settings/security-settings.asciidoc b/docs/en/settings/security-settings.asciidoc index 5df44c40dd1..42d3987513f 100644 --- a/docs/en/settings/security-settings.asciidoc +++ b/docs/en/settings/security-settings.asciidoc @@ -396,12 +396,10 @@ filter looks up `user` objects with either `sAMAccountName` or `user_search.upn_filter`:: Specifies a filter to use to lookup a user given a user principal name. -The default filter looks up `user` objects with either -a matching `userPrincipalName` or a `sAMAccountName` matching the account -portion of the user principal name. If specified, this +The default filter looks up `user` objects with +a matching `userPrincipalName`. If specified, this must be a valid LDAP user search filter, for example -`(&(objectClass=user)(sAMAccountName={0}))`. `{0}` is the value preceding the -`@` sign in the user principal name and `{1}` is the full user principal name +`(&(objectClass=user)(userPrincipalName={1}))`. `{1}` is the full user principal name provided by the user. `user_search.down_level_filter`:: diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactory.java b/plugin/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactory.java index e55c00892d9..ddc3f3b5aab 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactory.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactory.java @@ -20,11 +20,13 @@ import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.action.ActionListener; import org.elasticsearch.common.cache.Cache; import org.elasticsearch.common.cache.CacheBuilder; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.xpack.security.authc.RealmConfig; +import org.elasticsearch.xpack.security.authc.RealmSettings; import org.elasticsearch.xpack.security.authc.ldap.support.LdapMetaDataResolver; import org.elasticsearch.xpack.security.authc.ldap.support.LdapSearchScope; import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession; @@ -517,24 +519,27 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory { */ static class UpnADAuthenticator extends ADAuthenticator { - static final String UPN_USER_FILTER = "(&(objectClass=user)(|(sAMAccountName={0})(userPrincipalName={1})))"; + static final String UPN_USER_FILTER = "(&(objectClass=user)(userPrincipalName={1}))"; UpnADAuthenticator(RealmConfig config, TimeValue timeout, boolean ignoreReferralErrors, Logger logger, GroupsResolver groupsResolver, LdapMetaDataResolver metaDataResolver, String domainDN) { super(config, timeout, ignoreReferralErrors, logger, groupsResolver, metaDataResolver, domainDN, AD_UPN_USER_SEARCH_FILTER_SETTING, UPN_USER_FILTER); + if (userSearchFilter.contains("{0}")) { + new DeprecationLogger(logger).deprecated("The use of the account name variable {0} in the setting [" + + RealmSettings.getFullSettingKey(config, AD_UPN_USER_SEARCH_FILTER_SETTING) + + "] has been deprecated and will be removed in a future version!"); + } } void searchForDN(LDAPInterface connection, String username, SecureString password, int timeLimitSeconds, ActionListener listener) { String[] parts = username.split("@"); - assert parts.length == 2; + assert parts.length == 2 : "there should have only been two values for " + username + " after splitting on '@'"; final String accountName = parts[0]; - final String domainName = parts[1]; - final String domainDN = buildDnFromDomain(domainName); try { - Filter filter = createFilter(UPN_USER_FILTER, accountName, username); - searchForEntry(connection, domainDN, LdapSearchScope.SUB_TREE.scope(), filter, + Filter filter = createFilter(userSearchFilter, accountName, username); + searchForEntry(connection, userSearchDN, LdapSearchScope.SUB_TREE.scope(), filter, timeLimitSeconds, ignoreReferralErrors, listener, attributesToSearchFor(groupsResolver.attributes())); } catch (LDAPException e) {