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@de00c4817e
This commit is contained in:
Jay Modi 2017-07-13 10:08:22 -06:00 committed by GitHub
parent c753ddf7f2
commit 6fdad6039f
3 changed files with 17 additions and 16 deletions

View File

@ -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).

View File

@ -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`::

View File

@ -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<SearchResultEntry> 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) {