mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-22 12:56:53 +00:00
Fix LDAP Authc connections deadlock (elastic/x-pack-elasticsearch#2587)
Do not execute bind on on the LDAP reader thread Each LDAP connection has a single associated thread, executing the handlers for async requests; this is managed by the LDAP library. The bind operation is blocking for the connection. It is a deadlock to call bind, if on the LDAP reader thread for the same connection, because waiting for the bind response blocks the thread processing responses (for this connection). This will execute the bind operation (and the subsequent runnable) on a thread pool after checking for the conflict above. Closes: elastic/x-pack-elasticsearch#2570, elastic/x-pack-elasticsearch#2620 Original commit: elastic/x-pack-elasticsearch@404a3d8737
This commit is contained in:
parent
20c0e01523
commit
98347088f9
@ -129,6 +129,10 @@ forbiddenPatterns {
|
||||
exclude '**/*.zip'
|
||||
}
|
||||
|
||||
forbiddenApisMain {
|
||||
signaturesURLs += file('forbidden/ldap-signatures.txt').toURI().toURL()
|
||||
}
|
||||
|
||||
task extractNativeLicenses(type: Copy) {
|
||||
dependsOn configurations.nativeBundle
|
||||
into "${buildDir}"
|
||||
|
5
plugin/forbidden/ldap-signatures.txt
Normal file
5
plugin/forbidden/ldap-signatures.txt
Normal file
@ -0,0 +1,5 @@
|
||||
@defaultMessage Bind operation is blocking and can lead to deadlocks if called inside LDAP Response handlers. Use LdapUtils methods.
|
||||
com.unboundid.ldap.sdk.LDAPConnection#bind(com.unboundid.ldap.sdk.BindRequest)
|
||||
com.unboundid.ldap.sdk.LDAPConnection#bind(java.lang.String, java.lang.String)
|
||||
com.unboundid.ldap.sdk.LDAPConnectionPool#bindAndRevertAuthentication(com.unboundid.ldap.sdk.BindRequest)
|
||||
com.unboundid.ldap.sdk.LDAPConnectionPool#bindAndRevertAuthentication(java.lang.String, java.lang.String, com.unboundid.ldap.sdk.Control[])
|
@ -7,7 +7,6 @@ package org.elasticsearch.xpack.security.authc.ldap;
|
||||
|
||||
import com.unboundid.ldap.sdk.Filter;
|
||||
import com.unboundid.ldap.sdk.LDAPConnection;
|
||||
import com.unboundid.ldap.sdk.LDAPConnectionOptions;
|
||||
import com.unboundid.ldap.sdk.LDAPConnectionPool;
|
||||
import com.unboundid.ldap.sdk.LDAPException;
|
||||
import com.unboundid.ldap.sdk.LDAPInterface;
|
||||
@ -18,6 +17,7 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.apache.lucene.util.IOUtils;
|
||||
import org.elasticsearch.ElasticsearchSecurityException;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.ActionRunnable;
|
||||
import org.elasticsearch.common.cache.Cache;
|
||||
import org.elasticsearch.common.cache.CacheBuilder;
|
||||
import org.elasticsearch.common.logging.DeprecationLogger;
|
||||
@ -25,6 +25,8 @@ 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.common.util.concurrent.AbstractRunnable;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.authc.RealmSettings;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapMetaDataResolver;
|
||||
@ -36,6 +38,7 @@ import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
|
||||
import org.elasticsearch.xpack.security.authc.support.CharArrays;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@ -73,7 +76,7 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
|
||||
final DownLevelADAuthenticator downLevelADAuthenticator;
|
||||
final UpnADAuthenticator upnADAuthenticator;
|
||||
|
||||
ActiveDirectorySessionFactory(RealmConfig config, SSLService sslService) throws LDAPException {
|
||||
ActiveDirectorySessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool) throws LDAPException {
|
||||
super(config, sslService, new ActiveDirectoryGroupsResolver(config.settings()), POOL_ENABLED, () -> {
|
||||
if (BIND_DN.exists(config.settings())) {
|
||||
return new SimpleBindRequest(getBindDN(config.settings()), BIND_PASSWORD.get(config.settings()));
|
||||
@ -88,7 +91,7 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
|
||||
}
|
||||
}
|
||||
return config.settings().get(AD_USER_SEARCH_BASEDN_SETTING, config.settings().get(AD_DOMAIN_NAME_SETTING));
|
||||
});
|
||||
}, threadPool);
|
||||
Settings settings = config.settings();
|
||||
String domainName = settings.get(AD_DOMAIN_NAME_SETTING);
|
||||
if (domainName == null) {
|
||||
@ -96,11 +99,11 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
|
||||
}
|
||||
String domainDN = buildDnFromDomain(domainName);
|
||||
defaultADAuthenticator = new DefaultADAuthenticator(config, timeout, ignoreReferralErrors, logger, groupResolver,
|
||||
metaDataResolver, domainDN);
|
||||
downLevelADAuthenticator = new DownLevelADAuthenticator(config, timeout, ignoreReferralErrors, logger, groupResolver,
|
||||
metaDataResolver, domainDN, sslService);
|
||||
upnADAuthenticator = new UpnADAuthenticator(config, timeout, ignoreReferralErrors, logger, groupResolver,
|
||||
metaDataResolver, domainDN);
|
||||
metaDataResolver, domainDN, threadPool);
|
||||
downLevelADAuthenticator = new DownLevelADAuthenticator(config, timeout, ignoreReferralErrors, logger, groupResolver,
|
||||
metaDataResolver, domainDN, sslService, threadPool);
|
||||
upnADAuthenticator = new UpnADAuthenticator(config, timeout, ignoreReferralErrors, logger, groupResolver,
|
||||
metaDataResolver, domainDN, threadPool);
|
||||
|
||||
}
|
||||
|
||||
@ -118,26 +121,20 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
|
||||
|
||||
@Override
|
||||
void getSessionWithPool(LDAPConnectionPool connectionPool, String user, SecureString password, ActionListener<LdapSession> listener) {
|
||||
getADAuthenticator(user).authenticate(connectionPool, user, password, listener);
|
||||
getADAuthenticator(user).authenticate(connectionPool, user, password, threadPool, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
void getSessionWithoutPool(String username, SecureString password, ActionListener<LdapSession> listener) {
|
||||
// the runnable action here allows us make the control/flow logic simpler to understand. If we got a connection then lets
|
||||
// authenticate. If there was a failure pass it back using the listener
|
||||
Runnable runnable;
|
||||
try {
|
||||
final LDAPConnection connection = LdapUtils.privilegedConnect(serverSet::getConnection);
|
||||
runnable = () -> getADAuthenticator(username).authenticate(connection, username, password,
|
||||
ActionListener.wrap(listener::onResponse,
|
||||
(e) -> {
|
||||
IOUtils.closeWhileHandlingException(connection);
|
||||
listener.onFailure(e);
|
||||
}));
|
||||
getADAuthenticator(username).authenticate(connection, username, password, ActionListener.wrap(listener::onResponse, e -> {
|
||||
IOUtils.closeWhileHandlingException(connection);
|
||||
listener.onFailure(e);
|
||||
}));
|
||||
} catch (LDAPException e) {
|
||||
runnable = () -> listener.onFailure(e);
|
||||
listener.onFailure(e);
|
||||
}
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -154,37 +151,41 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
|
||||
|
||||
@Override
|
||||
void getUnauthenticatedSessionWithoutPool(String user, ActionListener<LdapSession> listener) {
|
||||
if (BIND_DN.exists(config.settings())) {
|
||||
LDAPConnection connection = null;
|
||||
boolean startedSearching = false;
|
||||
try {
|
||||
connection = LdapUtils.privilegedConnect(serverSet::getConnection);
|
||||
connection.bind(new SimpleBindRequest(getBindDN(config.settings()), BIND_PASSWORD.get(config.settings())));
|
||||
final LDAPConnection finalConnection = connection;
|
||||
getADAuthenticator(user).searchForDN(finalConnection, user, null, Math.toIntExact(timeout.getSeconds()),
|
||||
ActionListener.wrap(entry -> {
|
||||
if (entry == null) {
|
||||
IOUtils.closeWhileHandlingException(finalConnection);
|
||||
listener.onResponse(null);
|
||||
} else {
|
||||
final String dn = entry.getDN();
|
||||
listener.onResponse(new LdapSession(logger, config, finalConnection, dn, groupResolver, metaDataResolver,
|
||||
timeout, null));
|
||||
}
|
||||
}, e -> {
|
||||
IOUtils.closeWhileHandlingException(finalConnection);
|
||||
listener.onFailure(e);
|
||||
}));
|
||||
startedSearching = true;
|
||||
} catch (LDAPException e) {
|
||||
listener.onFailure(e);
|
||||
} finally {
|
||||
if (connection != null && startedSearching == false) {
|
||||
IOUtils.closeWhileHandlingException(connection);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (BIND_DN.exists(config.settings()) == false) {
|
||||
listener.onResponse(null);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final LDAPConnection connection = LdapUtils.privilegedConnect(serverSet::getConnection);
|
||||
final SimpleBindRequest bind = new SimpleBindRequest(getBindDN(config.settings()), BIND_PASSWORD.get(config.settings()));
|
||||
LdapUtils.maybeForkThenBind(connection, bind, threadPool, new AbstractRunnable() {
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
IOUtils.closeWhileHandlingException(connection);
|
||||
listener.onFailure(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRun() throws Exception {
|
||||
getADAuthenticator(user).searchForDN(connection, user, null, Math.toIntExact(timeout.getSeconds()),
|
||||
ActionListener.wrap(entry -> {
|
||||
if (entry == null) {
|
||||
IOUtils.close(connection);
|
||||
listener.onResponse(null);
|
||||
} else {
|
||||
listener.onResponse(new LdapSession(logger, config, connection, entry.getDN(), groupResolver,
|
||||
metaDataResolver, timeout, null));
|
||||
}
|
||||
}, e -> {
|
||||
IOUtils.closeWhileHandlingException(connection);
|
||||
listener.onFailure(e);
|
||||
}));
|
||||
|
||||
}
|
||||
});
|
||||
} catch (LDAPException e) {
|
||||
listener.onFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -242,10 +243,11 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
|
||||
final String userSearchFilter;
|
||||
final String bindDN;
|
||||
final String bindPassword; // TODO this needs to be a setting in the secure settings store!
|
||||
final ThreadPool threadPool;
|
||||
|
||||
ADAuthenticator(RealmConfig realm, TimeValue timeout, boolean ignoreReferralErrors, Logger logger,
|
||||
GroupsResolver groupsResolver, LdapMetaDataResolver metaDataResolver, String domainDN,
|
||||
String userSearchFilterSetting, String defaultUserSearchFilter) {
|
||||
ADAuthenticator(RealmConfig realm, TimeValue timeout, boolean ignoreReferralErrors, Logger logger, GroupsResolver groupsResolver,
|
||||
LdapMetaDataResolver metaDataResolver, String domainDN, String userSearchFilterSetting, String defaultUserSearchFilter,
|
||||
ThreadPool threadPool) {
|
||||
this.realm = realm;
|
||||
this.timeout = timeout;
|
||||
this.ignoreReferralErrors = ignoreReferralErrors;
|
||||
@ -255,65 +257,71 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
|
||||
final Settings settings = realm.settings();
|
||||
this.bindDN = getBindDN(settings);
|
||||
this.bindPassword = BIND_PASSWORD.get(settings);
|
||||
this.threadPool = threadPool;
|
||||
userSearchDN = settings.get(AD_USER_SEARCH_BASEDN_SETTING, domainDN);
|
||||
userSearchScope = LdapSearchScope.resolve(settings.get(AD_USER_SEARCH_SCOPE_SETTING), LdapSearchScope.SUB_TREE);
|
||||
userSearchFilter = settings.get(userSearchFilterSetting, defaultUserSearchFilter);
|
||||
}
|
||||
|
||||
final void authenticate(LDAPConnection connection, String username, SecureString password,
|
||||
ActionListener<LdapSession> listener) {
|
||||
boolean success = false;
|
||||
try {
|
||||
connection.bind(new SimpleBindRequest(bindUsername(username), CharArrays.toUtf8Bytes(password.getChars()),
|
||||
new AuthorizationIdentityRequestControl()));
|
||||
if (bindDN.isEmpty() == false) {
|
||||
connection.bind(new SimpleBindRequest(bindDN, bindPassword));
|
||||
}
|
||||
searchForDN(connection, username, password, Math.toIntExact(timeout.seconds()), ActionListener.wrap((entry) -> {
|
||||
if (entry == null) {
|
||||
IOUtils.close(connection);
|
||||
// we did not find the user, cannot authenticate in this realm
|
||||
listener.onFailure(new ElasticsearchSecurityException("search for user [" + username
|
||||
+ "] by principle name yielded no results"));
|
||||
final void authenticate(LDAPConnection connection, String username, SecureString password, ActionListener<LdapSession> listener) {
|
||||
final byte[] passwordBytes = CharArrays.toUtf8Bytes(password.getChars());
|
||||
final SimpleBindRequest userBind = new SimpleBindRequest(bindUsername(username), passwordBytes,
|
||||
new AuthorizationIdentityRequestControl());
|
||||
LdapUtils.maybeForkThenBind(connection, userBind, threadPool, new ActionRunnable<LdapSession>(listener) {
|
||||
@Override
|
||||
protected void doRun() throws Exception {
|
||||
final ActionRunnable<LdapSession> searchRunnable = new ActionRunnable<LdapSession>(listener) {
|
||||
@Override
|
||||
protected void doRun() throws Exception {
|
||||
searchForDN(connection, username, password, Math.toIntExact(timeout.seconds()), ActionListener.wrap((entry) -> {
|
||||
if (entry == null) {
|
||||
// we did not find the user, cannot authenticate in this realm
|
||||
listener.onFailure(new ElasticsearchSecurityException(
|
||||
"search for user [" + username + "] by principal name yielded no results"));
|
||||
} else {
|
||||
listener.onResponse(new LdapSession(logger, realm, connection, entry.getDN(), groupsResolver,
|
||||
metaDataResolver, timeout, null));
|
||||
}
|
||||
Arrays.fill(passwordBytes, (byte) 0);
|
||||
}, e -> {
|
||||
Arrays.fill(passwordBytes, (byte) 0);
|
||||
listener.onFailure(e);
|
||||
}));
|
||||
}
|
||||
};
|
||||
if (bindDN.isEmpty()) {
|
||||
searchRunnable.run();
|
||||
} else {
|
||||
final String dn = entry.getDN();
|
||||
listener.onResponse(new LdapSession(logger, realm, connection, dn, groupsResolver, metaDataResolver,
|
||||
timeout, null));
|
||||
final SimpleBindRequest bind = new SimpleBindRequest(bindDN, bindPassword);
|
||||
LdapUtils.maybeForkThenBind(connection, bind, threadPool, searchRunnable);
|
||||
}
|
||||
}, (e) -> {
|
||||
IOUtils.closeWhileHandlingException(connection);
|
||||
listener.onFailure(e);
|
||||
}));
|
||||
success = true;
|
||||
} catch (LDAPException e) {
|
||||
listener.onFailure(e);
|
||||
} finally {
|
||||
if (success == false) {
|
||||
IOUtils.closeWhileHandlingException(connection);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final void authenticate(LDAPConnectionPool pool, String username, SecureString password,
|
||||
final void authenticate(LDAPConnectionPool pool, String username, SecureString password, ThreadPool threadPool,
|
||||
ActionListener<LdapSession> listener) {
|
||||
try {
|
||||
LdapUtils.privilegedConnect(() -> {
|
||||
SimpleBindRequest request = new SimpleBindRequest(bindUsername(username), CharArrays.toUtf8Bytes(password.getChars()));
|
||||
return pool.bindAndRevertAuthentication(request);
|
||||
});
|
||||
searchForDN(pool, username, password, Math.toIntExact(timeout.seconds()), ActionListener.wrap((entry) -> {
|
||||
if (entry == null) {
|
||||
// we did not find the user, cannot authenticate in this realm
|
||||
listener.onFailure(new ElasticsearchSecurityException("search for user [" + username
|
||||
+ "] by principle name yielded no results"));
|
||||
} else {
|
||||
final String dn = entry.getDN();
|
||||
listener.onResponse(new LdapSession(logger, realm, pool, dn, groupsResolver, metaDataResolver, timeout, null));
|
||||
}
|
||||
}, listener::onFailure));
|
||||
} catch (LDAPException e) {
|
||||
listener.onFailure(e);
|
||||
}
|
||||
final byte[] passwordBytes = CharArrays.toUtf8Bytes(password.getChars());
|
||||
final SimpleBindRequest bind = new SimpleBindRequest(bindUsername(username), passwordBytes);
|
||||
LdapUtils.maybeForkThenBind(pool, bind, threadPool, new ActionRunnable<LdapSession>(listener) {
|
||||
@Override
|
||||
protected void doRun() throws Exception {
|
||||
searchForDN(pool, username, password, Math.toIntExact(timeout.seconds()), ActionListener.wrap((entry) -> {
|
||||
if (entry == null) {
|
||||
// we did not find the user, cannot authenticate in this realm
|
||||
listener.onFailure(new ElasticsearchSecurityException(
|
||||
"search for user [" + username + "] by principal name yielded no results"));
|
||||
} else {
|
||||
listener.onResponse(
|
||||
new LdapSession(logger, realm, pool, entry.getDN(), groupsResolver, metaDataResolver, timeout, null));
|
||||
}
|
||||
Arrays.fill(passwordBytes, (byte) 0);
|
||||
}, e -> {
|
||||
Arrays.fill(passwordBytes, (byte) 0);
|
||||
listener.onFailure(e);
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
String bindUsername(String username) {
|
||||
@ -337,10 +345,11 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
|
||||
static class DefaultADAuthenticator extends ADAuthenticator {
|
||||
|
||||
final String domainName;
|
||||
DefaultADAuthenticator(RealmConfig realm, TimeValue timeout, boolean ignoreReferralErrors,
|
||||
Logger logger, GroupsResolver groupsResolver, LdapMetaDataResolver metaDataResolver, String domainDN) {
|
||||
|
||||
DefaultADAuthenticator(RealmConfig realm, TimeValue timeout, boolean ignoreReferralErrors, Logger logger,
|
||||
GroupsResolver groupsResolver, LdapMetaDataResolver metaDataResolver, String domainDN, ThreadPool threadPool) {
|
||||
super(realm, timeout, ignoreReferralErrors, logger, groupsResolver, metaDataResolver, domainDN, AD_USER_SEARCH_FILTER_SETTING,
|
||||
"(&(objectClass=user)(|(sAMAccountName={0})(userPrincipalName={0}@" + domainName(realm) + ")))");
|
||||
"(&(objectClass=user)(|(sAMAccountName={0})(userPrincipalName={0}@" + domainName(realm) + ")))", threadPool);
|
||||
domainName = domainName(realm);
|
||||
}
|
||||
|
||||
@ -381,10 +390,10 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
|
||||
final RealmConfig config;
|
||||
|
||||
DownLevelADAuthenticator(RealmConfig config, TimeValue timeout, boolean ignoreReferralErrors, Logger logger,
|
||||
GroupsResolver groupsResolver, LdapMetaDataResolver metaDataResolver, String domainDN,
|
||||
SSLService sslService) {
|
||||
GroupsResolver groupsResolver, LdapMetaDataResolver metaDataResolver, String domainDN, SSLService sslService,
|
||||
ThreadPool threadPool) {
|
||||
super(config, timeout, ignoreReferralErrors, logger, groupsResolver, metaDataResolver, domainDN,
|
||||
AD_DOWN_LEVEL_USER_SEARCH_FILTER_SETTING, DOWN_LEVEL_FILTER);
|
||||
AD_DOWN_LEVEL_USER_SEARCH_FILTER_SETTING, DOWN_LEVEL_FILTER, threadPool);
|
||||
this.domainDN = domainDN;
|
||||
this.settings = config.settings();
|
||||
this.sslService = sslService;
|
||||
@ -403,81 +412,74 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
|
||||
if (domainDN == null) {
|
||||
listener.onResponse(null);
|
||||
} else {
|
||||
try {
|
||||
searchForEntry(connection, domainDN, LdapSearchScope.SUB_TREE.scope(),
|
||||
createFilter(userSearchFilter,
|
||||
accountName), timeLimitSeconds, ignoreReferralErrors,
|
||||
listener, attributesToSearchFor(groupsResolver.attributes()));
|
||||
} catch (LDAPException e) {
|
||||
listener.onFailure(e);
|
||||
}
|
||||
searchForEntry(connection, domainDN, LdapSearchScope.SUB_TREE.scope(), createFilter(userSearchFilter, accountName),
|
||||
timeLimitSeconds, ignoreReferralErrors, listener, attributesToSearchFor(groupsResolver.attributes()));
|
||||
}
|
||||
}, listener::onFailure));
|
||||
}
|
||||
|
||||
void netBiosDomainNameToDn(LDAPInterface ldapInterface, String netBiosDomainName, String username, SecureString password,
|
||||
int timeLimitSeconds, ActionListener<String> listener) {
|
||||
final String cachedName = domainNameCache.get(netBiosDomainName);
|
||||
LDAPConnection ldapConnection = null;
|
||||
try {
|
||||
final Filter filter = createFilter(NETBIOS_NAME_FILTER_TEMPLATE, netBiosDomainName);
|
||||
final String cachedName = domainNameCache.get(netBiosDomainName);
|
||||
if (cachedName != null) {
|
||||
listener.onResponse(cachedName);
|
||||
} else if (usingGlobalCatalog(ldapInterface)) {
|
||||
// the global catalog does not replicate the necessary information to map a netbios
|
||||
// dns name to a DN so we need to instead connect to the normal ports. This code
|
||||
// uses the standard ports to avoid adding even more settings and is probably ok as
|
||||
// most AD users do not use non-standard ports
|
||||
final LDAPConnectionOptions options = connectionOptions(config, sslService, logger);
|
||||
boolean startedSearching = false;
|
||||
LDAPConnection searchConnection = null;
|
||||
LDAPConnection ldapConnection = null;
|
||||
try {
|
||||
Filter filter = createFilter(NETBIOS_NAME_FILTER_TEMPLATE, netBiosDomainName);
|
||||
if (ldapInterface instanceof LDAPConnection) {
|
||||
ldapConnection = (LDAPConnection) ldapInterface;
|
||||
} else {
|
||||
ldapConnection = LdapUtils.privilegedConnect(((LDAPConnectionPool) ldapInterface)::getConnection);
|
||||
}
|
||||
final LDAPConnection finalLdapConnection = ldapConnection;
|
||||
searchConnection = LdapUtils.privilegedConnect(
|
||||
() -> new LDAPConnection(finalLdapConnection.getSocketFactory(), options,
|
||||
finalLdapConnection.getConnectedAddress(),
|
||||
finalLdapConnection.getSSLSession() != null ? 636 : 389));
|
||||
|
||||
final SimpleBindRequest bindRequest =
|
||||
bindDN.isEmpty() ? new SimpleBindRequest(username, CharArrays.toUtf8Bytes(password.getChars())) :
|
||||
new SimpleBindRequest(bindDN, bindPassword);
|
||||
searchConnection.bind(bindRequest);
|
||||
final LDAPConnection finalConnection = searchConnection;
|
||||
search(finalConnection, domainDN, LdapSearchScope.SUB_TREE.scope(), filter,
|
||||
timeLimitSeconds, ignoreReferralErrors, ActionListener.wrap(
|
||||
(results) -> {
|
||||
IOUtils.close(finalConnection);
|
||||
handleSearchResults(results, netBiosDomainName, domainNameCache, listener);
|
||||
}, (e) -> {
|
||||
IOUtils.closeWhileHandlingException(finalConnection);
|
||||
listener.onFailure(e);
|
||||
}),
|
||||
"ncname");
|
||||
startedSearching = true;
|
||||
} finally {
|
||||
if (startedSearching == false) {
|
||||
IOUtils.closeWhileHandlingException(searchConnection);
|
||||
}
|
||||
if (ldapInterface instanceof LDAPConnectionPool && ldapConnection != null) {
|
||||
((LDAPConnectionPool) ldapInterface).releaseConnection(ldapConnection);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Filter filter = createFilter(NETBIOS_NAME_FILTER_TEMPLATE, netBiosDomainName);
|
||||
search(ldapInterface, domainDN, LdapSearchScope.SUB_TREE.scope(), filter,
|
||||
timeLimitSeconds, ignoreReferralErrors, ActionListener.wrap(
|
||||
(results) -> handleSearchResults(results, netBiosDomainName,
|
||||
domainNameCache, listener),
|
||||
} else if (usingGlobalCatalog(ldapInterface) == false) {
|
||||
search(ldapInterface, domainDN, LdapSearchScope.SUB_TREE.scope(), filter, timeLimitSeconds, ignoreReferralErrors,
|
||||
ActionListener.wrap((results) -> handleSearchResults(results, netBiosDomainName, domainNameCache, listener),
|
||||
listener::onFailure),
|
||||
"ncname");
|
||||
} else {
|
||||
// the global catalog does not replicate the necessary information to map a
|
||||
// netbios dns name to a DN so we need to instead connect to the normal ports.
|
||||
// This code uses the standard ports to avoid adding even more settings and is
|
||||
// probably ok as most AD users do not use non-standard ports
|
||||
if (ldapInterface instanceof LDAPConnection) {
|
||||
ldapConnection = (LDAPConnection) ldapInterface;
|
||||
} else {
|
||||
ldapConnection = LdapUtils.privilegedConnect(((LDAPConnectionPool) ldapInterface)::getConnection);
|
||||
}
|
||||
final LDAPConnection finalLdapConnection = ldapConnection;
|
||||
final LDAPConnection searchConnection = LdapUtils.privilegedConnect(
|
||||
() -> new LDAPConnection(finalLdapConnection.getSocketFactory(), connectionOptions(config, sslService, logger),
|
||||
finalLdapConnection.getConnectedAddress(), finalLdapConnection.getSSLSession() != null ? 636 : 389));
|
||||
final byte[] passwordBytes = CharArrays.toUtf8Bytes(password.getChars());
|
||||
final SimpleBindRequest bind = bindDN.isEmpty()
|
||||
? new SimpleBindRequest(username, passwordBytes)
|
||||
: new SimpleBindRequest(bindDN, bindPassword);
|
||||
LdapUtils.maybeForkThenBind(searchConnection, bind, threadPool, new ActionRunnable<String>(listener) {
|
||||
@Override
|
||||
protected void doRun() throws Exception {
|
||||
search(searchConnection, domainDN, LdapSearchScope.SUB_TREE.scope(), filter, timeLimitSeconds,
|
||||
ignoreReferralErrors,
|
||||
ActionListener.wrap(
|
||||
results -> {
|
||||
IOUtils.close(searchConnection);
|
||||
Arrays.fill(passwordBytes, (byte) 0);
|
||||
handleSearchResults(results, netBiosDomainName, domainNameCache, listener);
|
||||
}, e -> {
|
||||
IOUtils.closeWhileHandlingException(searchConnection);
|
||||
Arrays.fill(passwordBytes, (byte) 0);
|
||||
listener.onFailure(e);
|
||||
}),
|
||||
"ncname");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
IOUtils.closeWhileHandlingException(searchConnection);
|
||||
listener.onFailure(e);
|
||||
};
|
||||
});
|
||||
}
|
||||
} catch (LDAPException e) {
|
||||
listener.onFailure(e);
|
||||
} finally {
|
||||
if (ldapInterface instanceof LDAPConnectionPool && ldapConnection != null) {
|
||||
((LDAPConnectionPool) ldapInterface).releaseConnection(ldapConnection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -531,9 +533,9 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
|
||||
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) {
|
||||
GroupsResolver groupsResolver, LdapMetaDataResolver metaDataResolver, String domainDN, ThreadPool threadPool) {
|
||||
super(config, timeout, ignoreReferralErrors, logger, groupsResolver, metaDataResolver, domainDN,
|
||||
AD_UPN_USER_SEARCH_FILTER_SETTING, UPN_USER_FILTER);
|
||||
AD_UPN_USER_SEARCH_FILTER_SETTING, UPN_USER_FILTER, threadPool);
|
||||
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) +
|
||||
@ -541,6 +543,7 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void searchForDN(LDAPInterface connection, String username, SecureString password, int timeLimitSeconds,
|
||||
ActionListener<SearchResultEntry> listener) {
|
||||
String[] parts = username.split("@");
|
||||
|
@ -67,7 +67,7 @@ public final class LdapRealm extends CachingUsernamePasswordRealm {
|
||||
ResourceWatcherService watcherService,
|
||||
NativeRoleMappingStore nativeRoleMappingStore, ThreadPool threadPool)
|
||||
throws LDAPException {
|
||||
this(type, config, sessionFactory(config, sslService, type),
|
||||
this(type, config, sessionFactory(config, sslService, threadPool, type),
|
||||
new CompositeRoleMapper(type, config, watcherService, nativeRoleMappingStore),
|
||||
threadPool);
|
||||
}
|
||||
@ -83,12 +83,12 @@ public final class LdapRealm extends CachingUsernamePasswordRealm {
|
||||
roleMapper.refreshRealmOnChange(this);
|
||||
}
|
||||
|
||||
static SessionFactory sessionFactory(RealmConfig config, SSLService sslService, String type)
|
||||
static SessionFactory sessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool, String type)
|
||||
throws LDAPException {
|
||||
|
||||
final SessionFactory sessionFactory;
|
||||
if (AD_TYPE.equals(type)) {
|
||||
sessionFactory = new ActiveDirectorySessionFactory(config, sslService);
|
||||
sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
|
||||
} else {
|
||||
assert LDAP_TYPE.equals(type) : "type [" + type + "] is unknown. expected one of [" + AD_TYPE + ", " + LDAP_TYPE + "]";
|
||||
final boolean hasSearchSettings = LdapUserSearchSessionFactory.hasUserSearchSettings(config);
|
||||
@ -103,7 +103,7 @@ public final class LdapRealm extends CachingUsernamePasswordRealm {
|
||||
"Please provide the settings for the mode you wish to use. For more details refer to the ldap " +
|
||||
"authentication section of the X-Pack guide.");
|
||||
}
|
||||
sessionFactory = new LdapSessionFactory(config, sslService);
|
||||
sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
} else if (hasTemplates) {
|
||||
throw new IllegalArgumentException("settings were found for both user search [" +
|
||||
RealmSettings.getFullSettingKey(config, LdapUserSearchSessionFactory.SEARCH_PREFIX) +
|
||||
@ -113,7 +113,7 @@ public final class LdapRealm extends CachingUsernamePasswordRealm {
|
||||
"Please remove the settings for the mode you do not wish to use. For more details refer to the ldap " +
|
||||
"authentication section of the X-Pack guide.");
|
||||
} else {
|
||||
sessionFactory = new LdapUserSearchSessionFactory(config, sslService);
|
||||
sessionFactory = new LdapUserSearchSessionFactory(config, sslService, threadPool);
|
||||
}
|
||||
}
|
||||
return sessionFactory;
|
||||
|
@ -8,14 +8,15 @@ package org.elasticsearch.xpack.security.authc.ldap;
|
||||
import com.unboundid.ldap.sdk.LDAPConnection;
|
||||
import com.unboundid.ldap.sdk.LDAPException;
|
||||
import com.unboundid.ldap.sdk.SimpleBindRequest;
|
||||
import org.apache.logging.log4j.message.ParameterizedMessage;
|
||||
import org.apache.logging.log4j.util.Supplier;
|
||||
|
||||
import org.apache.lucene.util.IOUtils;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.authc.RealmSettings;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapMetaDataResolver;
|
||||
@ -52,8 +53,8 @@ public class LdapSessionFactory extends SessionFactory {
|
||||
private final GroupsResolver groupResolver;
|
||||
private final LdapMetaDataResolver metaDataResolver;
|
||||
|
||||
public LdapSessionFactory(RealmConfig config, SSLService sslService) {
|
||||
super(config, sslService);
|
||||
public LdapSessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool) {
|
||||
super(config, sslService, threadPool);
|
||||
Settings settings = config.settings();
|
||||
userDnTemplates = USER_DN_TEMPLATES_SETTING.get(settings).toArray(Strings.EMPTY_ARRAY);
|
||||
if (userDnTemplates.length == 0) {
|
||||
@ -73,48 +74,51 @@ public class LdapSessionFactory extends SessionFactory {
|
||||
*/
|
||||
@Override
|
||||
public void session(String username, SecureString password, ActionListener<LdapSession> listener) {
|
||||
LDAPException lastException = null;
|
||||
LDAPConnection connection = null;
|
||||
LdapSession ldapSession = null;
|
||||
final byte[] passwordBytes = CharArrays.toUtf8Bytes(password.getChars());
|
||||
boolean success = false;
|
||||
try {
|
||||
connection = LdapUtils.privilegedConnect(serverSet::getConnection);
|
||||
for (String template : userDnTemplates) {
|
||||
String dn = buildDnFromTemplate(username, template);
|
||||
try {
|
||||
connection.bind(new SimpleBindRequest(dn, passwordBytes));
|
||||
ldapSession = new LdapSession(logger, config, connection, dn, groupResolver, metaDataResolver, timeout, null);
|
||||
success = true;
|
||||
break;
|
||||
} catch (LDAPException e) {
|
||||
// we catch the ldapException here since we expect it can happen and we shouldn't be logging this all the time otherwise
|
||||
// it is just noise
|
||||
logger.trace((Supplier<?>) () -> new ParameterizedMessage(
|
||||
"failed LDAP authentication with user template [{}] and DN [{}]", template, dn), e);
|
||||
if (lastException == null) {
|
||||
lastException = e;
|
||||
new AbstractRunnable() {
|
||||
final LDAPConnection connection = LdapUtils.privilegedConnect(serverSet::getConnection);
|
||||
final byte[] passwordBytes = CharArrays.toUtf8Bytes(password.getChars());
|
||||
Exception containerException = null;
|
||||
int loopIndex = 0;
|
||||
|
||||
@Override
|
||||
protected void doRun() throws Exception {
|
||||
listener.onResponse(
|
||||
(new LdapSession(logger, config, connection, ((SimpleBindRequest) connection.getLastBindRequest()).getBindDN(),
|
||||
groupResolver, metaDataResolver, timeout, null)));
|
||||
Arrays.fill(passwordBytes, (byte) 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
// record failure
|
||||
if (containerException == null) {
|
||||
containerException = e;
|
||||
} else {
|
||||
lastException.addSuppressed(e);
|
||||
containerException.addSuppressed(e);
|
||||
}
|
||||
|
||||
if (loopIndex > userDnTemplates.length) {
|
||||
listener.onFailure(new IllegalStateException("User DN template iteration index out of bounds."));
|
||||
} else if (loopIndex == userDnTemplates.length) {
|
||||
// loop break
|
||||
IOUtils.closeWhileHandlingException(connection);
|
||||
Arrays.fill(passwordBytes, (byte) 0);
|
||||
listener.onFailure(containerException);
|
||||
} else {
|
||||
loop();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (LDAPException e) {
|
||||
assert lastException == null : "if we catch a LDAPException here, we should have never seen another exception";
|
||||
assert ldapSession == null : "LDAPSession should not have been established due to a connection failure";
|
||||
lastException = e;
|
||||
} finally {
|
||||
Arrays.fill(passwordBytes, (byte) 0);
|
||||
if (success == false) {
|
||||
IOUtils.closeWhileHandlingException(connection);
|
||||
}
|
||||
}
|
||||
|
||||
if (ldapSession != null) {
|
||||
listener.onResponse(ldapSession);
|
||||
} else {
|
||||
assert lastException != null : "if there is not LDAPSession, then we must have a exception";
|
||||
listener.onFailure(lastException);
|
||||
// loop body
|
||||
void loop() {
|
||||
final String template = userDnTemplates[loopIndex++];
|
||||
final SimpleBindRequest bind = new SimpleBindRequest(buildDnFromTemplate(username, template), passwordBytes);
|
||||
LdapUtils.maybeForkThenBind(connection, bind, threadPool, this);
|
||||
}
|
||||
}.loop();
|
||||
} catch (LDAPException e) {
|
||||
listener.onFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,9 +14,12 @@ import com.unboundid.ldap.sdk.SearchResultEntry;
|
||||
import com.unboundid.ldap.sdk.SimpleBindRequest;
|
||||
import org.apache.lucene.util.IOUtils;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.ActionRunnable;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.authc.RealmSettings;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSearchScope;
|
||||
@ -55,7 +58,7 @@ class LdapUserSearchSessionFactory extends PoolingSessionFactory {
|
||||
private final LdapSearchScope scope;
|
||||
private final String searchFilter;
|
||||
|
||||
LdapUserSearchSessionFactory(RealmConfig config, SSLService sslService) throws LDAPException {
|
||||
LdapUserSearchSessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool) throws LDAPException {
|
||||
super(config, sslService, groupResolver(config.settings()), POOL_ENABLED,
|
||||
() -> LdapUserSearchSessionFactory.bindRequest(config.settings()),
|
||||
() -> {
|
||||
@ -64,7 +67,7 @@ class LdapUserSearchSessionFactory extends PoolingSessionFactory {
|
||||
} else {
|
||||
return SEARCH_BASE_DN.get(config.settings());
|
||||
}
|
||||
});
|
||||
}, threadPool);
|
||||
Settings settings = config.settings();
|
||||
if (SEARCH_BASE_DN.exists(settings)) {
|
||||
userSearchBaseDn = SEARCH_BASE_DN.get(settings);
|
||||
@ -100,15 +103,21 @@ class LdapUserSearchSessionFactory extends PoolingSessionFactory {
|
||||
} else {
|
||||
final String dn = entry.getDN();
|
||||
final byte[] passwordBytes = CharArrays.toUtf8Bytes(password.getChars());
|
||||
try {
|
||||
LdapUtils.privilegedConnect(() -> connectionPool.bindAndRevertAuthentication(new SimpleBindRequest(dn, passwordBytes)));
|
||||
listener.onResponse(new LdapSession(logger, config, connectionPool, dn, groupResolver, metaDataResolver, timeout,
|
||||
entry.getAttributes()));
|
||||
} catch (LDAPException e) {
|
||||
listener.onFailure(e);
|
||||
} finally {
|
||||
Arrays.fill(passwordBytes, (byte) 0);
|
||||
}
|
||||
SimpleBindRequest bind = new SimpleBindRequest(dn, passwordBytes);
|
||||
LdapUtils.maybeForkThenBind(connectionPool, bind, threadPool, new ActionRunnable<LdapSession>(listener) {
|
||||
@Override
|
||||
protected void doRun() throws Exception {
|
||||
listener.onResponse(new LdapSession(logger, config, connectionPool, dn, groupResolver, metaDataResolver, timeout,
|
||||
entry.getAttributes()));
|
||||
Arrays.fill(passwordBytes, (byte) 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
Arrays.fill(passwordBytes, (byte) 0);
|
||||
listener.onFailure(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, listener::onFailure));
|
||||
}
|
||||
@ -127,53 +136,49 @@ class LdapUserSearchSessionFactory extends PoolingSessionFactory {
|
||||
*/
|
||||
@Override
|
||||
void getSessionWithoutPool(String user, SecureString password, ActionListener<LdapSession> listener) {
|
||||
boolean success = false;
|
||||
LDAPConnection connection = null;
|
||||
try {
|
||||
connection = LdapUtils.privilegedConnect(serverSet::getConnection);
|
||||
final LDAPConnection connection = LdapUtils.privilegedConnect(serverSet::getConnection);
|
||||
final SimpleBindRequest bind = bindRequest(config.settings());
|
||||
connection.bind(bind);
|
||||
final LDAPConnection finalConnection = connection;
|
||||
findUser(user, connection, ActionListener.wrap((entry) -> {
|
||||
// close the existing connection since we are executing in this handler of the previous request and cannot bind here
|
||||
// so we need to open a new connection to bind on and use for the session
|
||||
IOUtils.close(finalConnection);
|
||||
LdapUtils.maybeForkThenBind(connection, bind, threadPool, new AbstractRunnable() {
|
||||
@Override
|
||||
protected void doRun() throws Exception {
|
||||
findUser(user, connection, ActionListener.wrap((entry) -> {
|
||||
if (entry == null) {
|
||||
IOUtils.close(connection);
|
||||
listener.onResponse(null);
|
||||
} else {
|
||||
final String dn = entry.getDN();
|
||||
boolean sessionCreated = false;
|
||||
LDAPConnection userConnection = null;
|
||||
final byte[] passwordBytes = CharArrays.toUtf8Bytes(password.getChars());
|
||||
try {
|
||||
userConnection = LdapUtils.privilegedConnect(serverSet::getConnection);
|
||||
userConnection.bind(new SimpleBindRequest(dn, passwordBytes));
|
||||
LdapSession session = new LdapSession(logger, config, userConnection, dn, groupResolver,
|
||||
metaDataResolver, timeout, entry.getAttributes());
|
||||
sessionCreated = true;
|
||||
listener.onResponse(session);
|
||||
} catch (Exception e) {
|
||||
listener.onFailure(e);
|
||||
} finally {
|
||||
Arrays.fill(passwordBytes, (byte) 0);
|
||||
if (sessionCreated == false) {
|
||||
IOUtils.close(userConnection);
|
||||
final SimpleBindRequest userBind = new SimpleBindRequest(dn, passwordBytes);
|
||||
LdapUtils.maybeForkThenBind(connection, userBind, threadPool, new AbstractRunnable() {
|
||||
@Override
|
||||
protected void doRun() throws Exception {
|
||||
listener.onResponse(new LdapSession(logger, config, connection, dn, groupResolver, metaDataResolver,
|
||||
timeout, entry.getAttributes()));
|
||||
Arrays.fill(passwordBytes, (byte) 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
Arrays.fill(passwordBytes, (byte) 0);
|
||||
IOUtils.closeWhileHandlingException(connection);
|
||||
listener.onFailure(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
(e) -> {
|
||||
IOUtils.closeWhileHandlingException(finalConnection);
|
||||
}, e -> {
|
||||
IOUtils.closeWhileHandlingException(connection);
|
||||
listener.onFailure(e);
|
||||
}));
|
||||
success = true;
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
IOUtils.closeWhileHandlingException(connection);
|
||||
listener.onFailure(e);
|
||||
}
|
||||
});
|
||||
} catch (LDAPException e) {
|
||||
listener.onFailure(e);
|
||||
} finally {
|
||||
// need the success flag since the search is async and we don't want to close it if it is in progress
|
||||
if (success == false) {
|
||||
IOUtils.closeWhileHandlingException(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,38 +203,34 @@ class LdapUserSearchSessionFactory extends PoolingSessionFactory {
|
||||
|
||||
@Override
|
||||
void getUnauthenticatedSessionWithoutPool(String user, ActionListener<LdapSession> listener) {
|
||||
LDAPConnection connection = null;
|
||||
boolean success = false;
|
||||
try {
|
||||
connection = LdapUtils.privilegedConnect(serverSet::getConnection);
|
||||
connection.bind(bindRequest(config.settings()));
|
||||
final LDAPConnection finalConnection = connection;
|
||||
|
||||
findUser(user, finalConnection, ActionListener.wrap((entry) -> {
|
||||
if (entry == null) {
|
||||
listener.onResponse(null);
|
||||
} else {
|
||||
boolean sessionCreated = false;
|
||||
try {
|
||||
final String dn = entry.getDN();
|
||||
LdapSession session = new LdapSession(logger, config, finalConnection, dn, groupResolver, metaDataResolver, timeout,
|
||||
entry.getAttributes());
|
||||
sessionCreated = true;
|
||||
listener.onResponse(session);
|
||||
} finally {
|
||||
if (sessionCreated == false) {
|
||||
IOUtils.close(finalConnection);
|
||||
final LDAPConnection connection = LdapUtils.privilegedConnect(serverSet::getConnection);
|
||||
final SimpleBindRequest bind = bindRequest(config.settings());
|
||||
LdapUtils.maybeForkThenBind(connection, bind, threadPool, new AbstractRunnable() {
|
||||
@Override
|
||||
protected void doRun() throws Exception {
|
||||
findUser(user, connection, ActionListener.wrap((entry) -> {
|
||||
if (entry == null) {
|
||||
IOUtils.close(connection);
|
||||
listener.onResponse(null);
|
||||
} else {
|
||||
listener.onResponse(new LdapSession(logger, config, connection, entry.getDN(), groupResolver, metaDataResolver,
|
||||
timeout, entry.getAttributes()));
|
||||
}
|
||||
}
|
||||
}, e -> {
|
||||
IOUtils.closeWhileHandlingException(connection);
|
||||
listener.onFailure(e);
|
||||
}));
|
||||
}
|
||||
}, listener::onFailure));
|
||||
success = true;
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
IOUtils.closeWhileHandlingException(connection);
|
||||
listener.onFailure(e);
|
||||
}
|
||||
});
|
||||
} catch (LDAPException e) {
|
||||
listener.onFailure(e);
|
||||
} finally {
|
||||
if (success == false) {
|
||||
IOUtils.closeWhileHandlingException(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.util.set.Sets;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.authc.RealmSettings;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapMetaDataResolver;
|
||||
@ -69,11 +70,12 @@ abstract class PoolingSessionFactory extends SessionFactory implements Releasabl
|
||||
* @param poolingEnabled the setting that should be used to determine if connection pooling is enabled
|
||||
* @param bindRequestSupplier the supplier for a bind requests that should be used for pooled connections
|
||||
* @param healthCheckDNSupplier a supplier for the dn to query for health checks
|
||||
* @param threadPool a thread pool used for async queries execution
|
||||
*/
|
||||
PoolingSessionFactory(RealmConfig config, SSLService sslService, LdapSession.GroupsResolver groupResolver,
|
||||
Setting<Boolean> poolingEnabled, Supplier<BindRequest> bindRequestSupplier,
|
||||
Supplier<String> healthCheckDNSupplier) throws LDAPException {
|
||||
super(config, sslService);
|
||||
Setting<Boolean> poolingEnabled, Supplier<BindRequest> bindRequestSupplier, Supplier<String> healthCheckDNSupplier,
|
||||
ThreadPool threadPool) throws LDAPException {
|
||||
super(config, sslService, threadPool);
|
||||
this.groupResolver = groupResolver;
|
||||
this.metaDataResolver = new LdapMetaDataResolver(config.settings(), ignoreReferralErrors);
|
||||
this.useConnectionPool = poolingEnabled.get(config.settings());
|
||||
@ -178,6 +180,15 @@ abstract class PoolingSessionFactory extends SessionFactory implements Releasabl
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For tests use only
|
||||
*
|
||||
* @return the connection pool for LDAP queries
|
||||
*/
|
||||
LDAPConnectionPool getConnectionPool() {
|
||||
return connectionPool;
|
||||
}
|
||||
|
||||
public static Set<Setting<?>> getSettings() {
|
||||
return Sets.newHashSet(POOL_INITIAL_SIZE, POOL_SIZE, HEALTH_CHECK_ENABLED, HEALTH_CHECK_INTERVAL, HEALTH_CHECK_DN, BIND_DN,
|
||||
BIND_PASSWORD);
|
||||
|
@ -19,7 +19,6 @@ import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSearchScope;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession.GroupsResolver;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@ -101,6 +100,7 @@ class SearchGroupsResolver implements GroupsResolver {
|
||||
}, listener::onFailure));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] attributes() {
|
||||
if (Strings.hasLength(userAttribute)) {
|
||||
return new String[] { userAttribute };
|
||||
|
@ -13,7 +13,6 @@ import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.common.lease.Releasable;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.LdapRealm;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
@ -7,6 +7,7 @@ package org.elasticsearch.xpack.security.authc.ldap.support;
|
||||
|
||||
import com.unboundid.ldap.sdk.AsyncRequestID;
|
||||
import com.unboundid.ldap.sdk.AsyncSearchResultListener;
|
||||
import com.unboundid.ldap.sdk.BindRequest;
|
||||
import com.unboundid.ldap.sdk.DN;
|
||||
import com.unboundid.ldap.sdk.DereferencePolicy;
|
||||
import com.unboundid.ldap.sdk.Filter;
|
||||
@ -30,8 +31,11 @@ import org.elasticsearch.SpecialPermission;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.common.CheckedSupplier;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.SuppressForbidden;
|
||||
import org.elasticsearch.common.logging.ESLoggerFactory;
|
||||
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
|
||||
import org.elasticsearch.common.util.concurrent.CountDown;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.security.support.Exceptions;
|
||||
|
||||
import javax.naming.ldap.Rdn;
|
||||
@ -82,6 +86,69 @@ public final class LdapUtils {
|
||||
return Rdn.escapeValue(rdn);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method submits the {@code bind} request over the provided {@code ldap}
|
||||
* connection or connection pool. The connection authentication status changes,
|
||||
* see {@code LDAPConnection#bind}; in case of a connection pool the bind
|
||||
* authentication status is reverted, so that the connection can be safely
|
||||
* returned to the pool, see:
|
||||
* {@code LDAPConnectionPool#bindAndRevertAuthentication}.
|
||||
*
|
||||
* Bind calls are blocking and if a bind is executed on the LDAP Connection
|
||||
* Reader thread (as returned by {@code LdapUtils#isLdapConnectionThread}),
|
||||
* the thread will be blocked until it is interrupted by something else
|
||||
* such as a timeout timer.
|
||||
* <b>Do not call bind</b> outside of this method.
|
||||
*
|
||||
* @param ldap
|
||||
* The LDAP connection or connection pool on which to submit the bind
|
||||
* operation.
|
||||
* @param bind
|
||||
* The request object of the bind operation.
|
||||
* @param threadPool
|
||||
* The threads that will call the blocking bind operation, in case
|
||||
* the calling thread is a connection reader, see:
|
||||
* {@code LdapUtils#isLdapConnectionThread}.
|
||||
* @param runnable
|
||||
* The runnable that continues the program flow after the bind
|
||||
* operation. It is executed on the same thread as the prior bind.
|
||||
*/
|
||||
public static void maybeForkThenBind(LDAPInterface ldap, BindRequest bind, ThreadPool threadPool,
|
||||
AbstractRunnable runnable) {
|
||||
Runnable bindRunnable = new AbstractRunnable() {
|
||||
@Override
|
||||
@SuppressForbidden(reason = "Bind allowed if forking of the LDAP Connection Reader Thread.")
|
||||
protected void doRun() throws Exception {
|
||||
if (ldap instanceof LDAPConnectionPool) {
|
||||
privilegedConnect(() -> ((LDAPConnectionPool) ldap).bindAndRevertAuthentication(bind));
|
||||
} else if (ldap instanceof LDAPConnection) {
|
||||
((LDAPConnection) ldap).bind(bind);
|
||||
} else {
|
||||
throw new IllegalArgumentException("unsupported LDAPInterface implementation: " + ldap);
|
||||
}
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
runnable.onFailure(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfter() {
|
||||
runnable.onAfter();
|
||||
}
|
||||
};
|
||||
|
||||
if (isLdapConnectionThread(Thread.currentThread())) {
|
||||
// only fork if binding on the LDAPConnectionReader thread
|
||||
threadPool.executor(ThreadPool.Names.GENERIC).execute(bindRunnable);
|
||||
} else {
|
||||
// avoids repeated forking
|
||||
bindRunnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method performs an asynchronous ldap search operation that could have multiple results
|
||||
*/
|
||||
@ -146,11 +213,13 @@ public final class LdapUtils {
|
||||
final LDAPConnection finalConnection = ldapConnection;
|
||||
searchForEntry(finalConnection, baseDN, scope, filter, timeLimitSeconds,
|
||||
ignoreReferralErrors, ActionListener.wrap(
|
||||
(entry) -> {
|
||||
entry -> {
|
||||
assert isLdapConnectionThread(Thread.currentThread()) : "Expected current thread [" + Thread.currentThread()
|
||||
+ "] to be an LDAPConnectionReader Thread. Probably the new library has changed the thread's name.";
|
||||
IOUtils.close(() -> ldap.releaseConnection(finalConnection));
|
||||
listener.onResponse(entry);
|
||||
},
|
||||
(e) -> {
|
||||
e -> {
|
||||
IOUtils.closeWhileHandlingException(
|
||||
() -> ldap.releaseConnection(finalConnection)
|
||||
);
|
||||
@ -198,9 +267,11 @@ public final class LdapUtils {
|
||||
ldap,
|
||||
ignoreReferralErrors,
|
||||
ActionListener.wrap(
|
||||
searchResult -> listener.onResponse(
|
||||
Collections.unmodifiableList(searchResult.getSearchEntries())
|
||||
),
|
||||
searchResult -> {
|
||||
assert isLdapConnectionThread(Thread.currentThread()) : "Expected current thread [" + Thread.currentThread()
|
||||
+ "] to be an LDAPConnectionReader Thread. Probably the new library has changed the thread's name.";
|
||||
listener.onResponse(Collections.unmodifiableList(searchResult.getSearchEntries()));
|
||||
},
|
||||
listener::onFailure),
|
||||
1);
|
||||
try {
|
||||
@ -226,27 +297,13 @@ public final class LdapUtils {
|
||||
try {
|
||||
ldapConnection = privilegedConnect(ldap::getConnection);
|
||||
final LDAPConnection finalConnection = ldapConnection;
|
||||
LdapSearchResultListener ldapSearchResultListener = new LdapSearchResultListener(
|
||||
finalConnection, ignoreReferralErrors,
|
||||
ActionListener.wrap(
|
||||
searchResult -> {
|
||||
IOUtils.closeWhileHandlingException(
|
||||
() -> ldap.releaseConnection(finalConnection)
|
||||
);
|
||||
listener.onResponse(Collections.unmodifiableList(
|
||||
searchResult.getSearchEntries()
|
||||
));
|
||||
}, (e) -> {
|
||||
IOUtils.closeWhileHandlingException(
|
||||
() -> ldap.releaseConnection(finalConnection)
|
||||
);
|
||||
listener.onFailure(e);
|
||||
}),
|
||||
1);
|
||||
SearchRequest request = new SearchRequest(ldapSearchResultListener, baseDN, scope,
|
||||
DereferencePolicy.NEVER, 0, timeLimitSeconds, false, filter, attributes);
|
||||
ldapSearchResultListener.setSearchRequest(request);
|
||||
finalConnection.asyncSearch(request);
|
||||
search(finalConnection, baseDN, scope, filter, timeLimitSeconds, ignoreReferralErrors, ActionListener.wrap(searchResult -> {
|
||||
IOUtils.closeWhileHandlingException(() -> ldap.releaseConnection(finalConnection));
|
||||
listener.onResponse(searchResult);
|
||||
}, (e) -> {
|
||||
IOUtils.closeWhileHandlingException(() -> ldap.releaseConnection(finalConnection));
|
||||
listener.onFailure(e);
|
||||
}), attributes);
|
||||
searching = true;
|
||||
} catch (LDAPException e) {
|
||||
listener.onFailure(e);
|
||||
@ -258,6 +315,10 @@ public final class LdapUtils {
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isLdapConnectionThread(Thread thread) {
|
||||
return Thread.currentThread().getName().startsWith("Connection reader for connection ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the provide {@link SearchResult} was successfully completed
|
||||
* by the server.
|
||||
@ -529,10 +590,11 @@ public final class LdapUtils {
|
||||
referralConn, ignoreErrors,
|
||||
ActionListener.wrap(
|
||||
searchResult -> {
|
||||
IOUtils.closeWhileHandlingException(referralConn);
|
||||
IOUtils.close(referralConn);
|
||||
listener.onResponse(searchResult);
|
||||
},
|
||||
e -> {
|
||||
IOUtils.closeWhileHandlingException(referralConn);
|
||||
if (ignoreErrors) {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(new ParameterizedMessage(
|
||||
|
@ -12,12 +12,14 @@ import com.unboundid.ldap.sdk.ServerSet;
|
||||
import com.unboundid.util.ssl.HostNameSSLSocketVerifier;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.support.ThreadedActionListener;
|
||||
import org.elasticsearch.common.Strings;
|
||||
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.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.authc.RealmSettings;
|
||||
import org.elasticsearch.xpack.ssl.SSLConfigurationSettings;
|
||||
@ -67,12 +69,13 @@ public abstract class SessionFactory {
|
||||
protected final RealmConfig config;
|
||||
protected final TimeValue timeout;
|
||||
protected final SSLService sslService;
|
||||
protected final ThreadPool threadPool;
|
||||
|
||||
protected final ServerSet serverSet;
|
||||
protected final boolean sslUsed;
|
||||
protected final boolean ignoreReferralErrors;
|
||||
|
||||
protected SessionFactory(RealmConfig config, SSLService sslService) {
|
||||
protected SessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool) {
|
||||
this.config = config;
|
||||
this.logger = config.logger(getClass());
|
||||
final Settings settings = config.settings();
|
||||
@ -85,6 +88,7 @@ public abstract class SessionFactory {
|
||||
}
|
||||
this.timeout = searchTimeout;
|
||||
this.sslService = sslService;
|
||||
this.threadPool = threadPool;
|
||||
LDAPServers ldapServers = ldapServers(settings);
|
||||
this.serverSet = serverSet(config, sslService, ldapServers);
|
||||
this.sslUsed = ldapServers.ssl;
|
||||
|
@ -134,7 +134,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
||||
public void testAuthenticateUserPrincipleName() throws Exception {
|
||||
Settings settings = settings();
|
||||
RealmConfig config = new RealmConfig("testAuthenticateUserPrincipleName", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService);
|
||||
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
|
||||
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
|
||||
LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
|
||||
|
||||
@ -150,7 +150,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
||||
public void testAuthenticateSAMAccountName() throws Exception {
|
||||
Settings settings = settings();
|
||||
RealmConfig config = new RealmConfig("testAuthenticateSAMAccountName", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService);
|
||||
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
|
||||
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
|
||||
LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
|
||||
|
||||
@ -174,7 +174,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
||||
public void testAuthenticateCachesSuccessfulAuthentications() throws Exception {
|
||||
Settings settings = settings();
|
||||
RealmConfig config = new RealmConfig("testAuthenticateCachesSuccesfulAuthentications", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
ActiveDirectorySessionFactory sessionFactory = spy(new ActiveDirectorySessionFactory(config, sslService));
|
||||
ActiveDirectorySessionFactory sessionFactory = spy(new ActiveDirectorySessionFactory(config, sslService, threadPool));
|
||||
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
|
||||
LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
|
||||
|
||||
@ -192,7 +192,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
||||
public void testAuthenticateCachingCanBeDisabled() throws Exception {
|
||||
Settings settings = settings(Settings.builder().put(CachingUsernamePasswordRealm.CACHE_TTL_SETTING.getKey(), -1).build());
|
||||
RealmConfig config = new RealmConfig("testAuthenticateCachingCanBeDisabled", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
ActiveDirectorySessionFactory sessionFactory = spy(new ActiveDirectorySessionFactory(config, sslService));
|
||||
ActiveDirectorySessionFactory sessionFactory = spy(new ActiveDirectorySessionFactory(config, sslService, threadPool));
|
||||
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
|
||||
LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
|
||||
|
||||
@ -210,7 +210,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
||||
public void testAuthenticateCachingClearsCacheOnRoleMapperRefresh() throws Exception {
|
||||
Settings settings = settings();
|
||||
RealmConfig config = new RealmConfig("testAuthenticateCachingClearsCacheOnRoleMapperRefresh", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
ActiveDirectorySessionFactory sessionFactory = spy(new ActiveDirectorySessionFactory(config, sslService));
|
||||
ActiveDirectorySessionFactory sessionFactory = spy(new ActiveDirectorySessionFactory(config, sslService, threadPool));
|
||||
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
|
||||
LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
|
||||
|
||||
@ -252,7 +252,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
||||
.build());
|
||||
RealmConfig config = new RealmConfig("testUnauthenticatedLookupWithConnectionPool", settings, globalSettings,
|
||||
new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
try(ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService)) {
|
||||
try (ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool)) {
|
||||
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
|
||||
LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
|
||||
|
||||
@ -269,7 +269,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
||||
.put(ROLE_MAPPING_FILE_SETTING, getDataPath("role_mapping.yml"))
|
||||
.build());
|
||||
RealmConfig config = new RealmConfig("testRealmMapsGroupsToRoles", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService);
|
||||
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
|
||||
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
|
||||
LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
|
||||
|
||||
@ -285,7 +285,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
||||
.put(ROLE_MAPPING_FILE_SETTING, getDataPath("role_mapping.yml"))
|
||||
.build());
|
||||
RealmConfig config = new RealmConfig("testRealmMapsGroupsToRoles", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService);
|
||||
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
|
||||
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
|
||||
LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
|
||||
|
||||
@ -304,7 +304,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
||||
.build());
|
||||
RealmConfig config = new RealmConfig("testRealmUsageStats", settings, globalSettings, new Environment(globalSettings),
|
||||
new ThreadContext(globalSettings));
|
||||
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService);
|
||||
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
|
||||
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
|
||||
LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
|
||||
|
||||
@ -321,7 +321,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
||||
Settings settings = settings();
|
||||
RealmConfig config = new RealmConfig("testDefaultSearchFilters", settings, globalSettings, new Environment(globalSettings),
|
||||
new ThreadContext(globalSettings));
|
||||
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService);
|
||||
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
|
||||
assertEquals("(&(objectClass=user)(|(sAMAccountName={0})(userPrincipalName={0}@ad.test.elasticsearch.com)))",
|
||||
sessionFactory.defaultADAuthenticator.getUserSearchFilter());
|
||||
assertEquals(UpnADAuthenticator.UPN_USER_FILTER, sessionFactory.upnADAuthenticator.getUserSearchFilter());
|
||||
@ -336,7 +336,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
||||
.build());
|
||||
RealmConfig config = new RealmConfig("testDefaultSearchFilters", settings, globalSettings, new Environment(globalSettings),
|
||||
new ThreadContext(globalSettings));
|
||||
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService);
|
||||
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
|
||||
assertEquals("(objectClass=default)", sessionFactory.defaultADAuthenticator.getUserSearchFilter());
|
||||
assertEquals("(objectClass=upn)", sessionFactory.upnADAuthenticator.getUserSearchFilter());
|
||||
assertEquals("(objectClass=down level)", sessionFactory.downLevelADAuthenticator.getUserSearchFilter());
|
||||
|
@ -19,7 +19,12 @@ import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapTestCase;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
|
||||
import org.elasticsearch.test.junit.annotations.Network;
|
||||
import org.elasticsearch.threadpool.TestThreadPool;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.VerificationMode;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@ -36,6 +41,17 @@ import static org.hamcrest.Matchers.is;
|
||||
public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryIntegTests {
|
||||
|
||||
private final SecureString SECURED_PASSWORD = new SecureString(PASSWORD);
|
||||
private ThreadPool threadPool;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
threadPool = new TestThreadPool("ActiveDirectorySessionFactoryTests thread pool");
|
||||
}
|
||||
|
||||
@After
|
||||
public void shutdown() throws InterruptedException {
|
||||
terminate(threadPool);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enableWarningsCheck() {
|
||||
@ -47,7 +63,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
|
||||
RealmConfig config = new RealmConfig("ad-test",
|
||||
buildAdSettings(AD_LDAP_URL, AD_DOMAIN, false),
|
||||
globalSettings, new ThreadContext(Settings.EMPTY));
|
||||
try (ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService)) {
|
||||
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
|
||||
|
||||
String userName = "ironman";
|
||||
try (LdapSession ldap = session(sessionFactory, userName, SECURED_PASSWORD)) {
|
||||
@ -70,7 +86,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
|
||||
final String adUrl = randomFrom("ldap://54.213.145.20:3268", "ldaps://54.213.145.20:3269", AD_LDAP_URL);
|
||||
RealmConfig config = new RealmConfig("ad-test", buildAdSettings(adUrl, AD_DOMAIN, false), globalSettings,
|
||||
new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
try (ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService)) {
|
||||
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
|
||||
|
||||
String userName = "ades\\ironman";
|
||||
try (LdapSession ldap = session(sessionFactory, userName, SECURED_PASSWORD)) {
|
||||
@ -99,7 +115,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
|
||||
.build();
|
||||
RealmConfig config =
|
||||
new RealmConfig("ad-test", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
try (ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService)) {
|
||||
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
|
||||
|
||||
PlainActionFuture<List<String>> groups = new PlainActionFuture<>();
|
||||
session(sessionFactory, "ironman", SECURED_PASSWORD).groups(groups);
|
||||
@ -111,7 +127,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
|
||||
public void testAdAuthAvengers() throws Exception {
|
||||
RealmConfig config = new RealmConfig("ad-test", buildAdSettings(AD_LDAP_URL, AD_DOMAIN, false), globalSettings,
|
||||
new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
try (ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService)) {
|
||||
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
|
||||
|
||||
String[] users = new String[]{"cap", "hawkeye", "hulk", "ironman", "thor", "blackwidow"};
|
||||
for (String user : users) {
|
||||
@ -128,7 +144,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
|
||||
LdapSearchScope.ONE_LEVEL, false);
|
||||
RealmConfig config =
|
||||
new RealmConfig("ad-test", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
try (ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService)) {
|
||||
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
|
||||
|
||||
String userName = "hulk";
|
||||
try (LdapSession ldap = session(sessionFactory, userName, SECURED_PASSWORD)) {
|
||||
@ -152,7 +168,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
|
||||
LdapSearchScope.BASE, false);
|
||||
RealmConfig config = new RealmConfig("ad-test", settings, globalSettings, new Environment(globalSettings),
|
||||
new ThreadContext(globalSettings));
|
||||
try (ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService)) {
|
||||
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
|
||||
|
||||
String userName = "hulk";
|
||||
try (LdapSession ldap = session(sessionFactory, userName, SECURED_PASSWORD)) {
|
||||
@ -180,7 +196,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
|
||||
.build();
|
||||
RealmConfig config =
|
||||
new RealmConfig("ad-test", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
try (ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService)) {
|
||||
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
|
||||
|
||||
String userName = "hulk";
|
||||
try (LdapSession ldap = session(sessionFactory, userName, SECURED_PASSWORD)) {
|
||||
@ -197,7 +213,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
|
||||
LdapSearchScope.ONE_LEVEL, false);
|
||||
RealmConfig config =
|
||||
new RealmConfig("ad-test", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
try (ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService)) {
|
||||
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
|
||||
|
||||
//Login with the UserPrincipalName
|
||||
String userDN = "CN=Erik Selvig,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com";
|
||||
@ -217,7 +233,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
|
||||
LdapSearchScope.ONE_LEVEL, false);
|
||||
RealmConfig config =
|
||||
new RealmConfig("ad-test", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
try (ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService)) {
|
||||
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
|
||||
|
||||
//login with sAMAccountName
|
||||
String userDN = "CN=Erik Selvig,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com";
|
||||
@ -243,7 +259,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
|
||||
.build();
|
||||
RealmConfig config =
|
||||
new RealmConfig("ad-test", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
try (ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService)) {
|
||||
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
|
||||
|
||||
//Login with the UserPrincipalName
|
||||
try (LdapSession ldap = session(sessionFactory, "erik.selvig", SECURED_PASSWORD)) {
|
||||
@ -277,7 +293,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
|
||||
}
|
||||
RealmConfig config = new RealmConfig("ad-as-ldap-test", settings, globalSettings, new Environment(globalSettings),
|
||||
new ThreadContext(globalSettings));
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String user = "Bruce Banner";
|
||||
try (LdapSession ldap = session(sessionFactory, user, SECURED_PASSWORD)) {
|
||||
@ -312,7 +328,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
|
||||
}
|
||||
RealmConfig config = new RealmConfig("ad-as-ldap-test", settings, globalSettings, new Environment(globalSettings),
|
||||
new ThreadContext(globalSettings));
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String user = "Bruce Banner";
|
||||
try (LdapSession ldap = session(sessionFactory, user, SECURED_PASSWORD)) {
|
||||
@ -341,7 +357,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
|
||||
}
|
||||
RealmConfig config = new RealmConfig("ad-as-ldap-test", settings, globalSettings, new Environment(globalSettings),
|
||||
new ThreadContext(globalSettings));
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String user = "Bruce Banner";
|
||||
try (LdapSession ldap = session(sessionFactory, user, SECURED_PASSWORD)) {
|
||||
@ -358,7 +374,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
|
||||
public void testAdAuthWithHostnameVerification() throws Exception {
|
||||
RealmConfig config = new RealmConfig("ad-test", buildAdSettings(AD_LDAP_URL, AD_DOMAIN, true), globalSettings,
|
||||
new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
try (ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService)) {
|
||||
try (ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool)) {
|
||||
|
||||
String userName = "ironman";
|
||||
UncategorizedExecutionException e = expectThrows(UncategorizedExecutionException.class,
|
||||
@ -380,7 +396,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
|
||||
.build();
|
||||
RealmConfig config =
|
||||
new RealmConfig("ad-test", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String user = "Bruce Banner";
|
||||
UncategorizedExecutionException e = expectThrows(UncategorizedExecutionException.class,
|
||||
@ -395,7 +411,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
|
||||
RealmConfig config = new RealmConfig("ad-test",
|
||||
buildAdSettings(AD_LDAP_URL, AD_DOMAIN, false, true),
|
||||
globalSettings, new ThreadContext(Settings.EMPTY));
|
||||
try (ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService)) {
|
||||
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
|
||||
|
||||
List<String> users = randomSubsetOf(Arrays.asList("cap", "hawkeye", "hulk", "ironman", "thor", "blackwidow",
|
||||
"cap@ad.test.elasticsearch.com", "hawkeye@ad.test.elasticsearch.com", "hulk@ad.test.elasticsearch.com",
|
||||
@ -460,4 +476,15 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
|
||||
ldapSession.groups(future);
|
||||
return future.actionGet();
|
||||
}
|
||||
|
||||
static ActiveDirectorySessionFactory getActiveDirectorySessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool)
|
||||
throws LDAPException {
|
||||
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
|
||||
if (sessionFactory.getConnectionPool() != null) {
|
||||
// don't use this in production
|
||||
// used here to catch bugs that might get masked by an automatic retry
|
||||
sessionFactory.getConnectionPool().setRetryFailedOperationsDueToInvalidConnections(false);
|
||||
}
|
||||
return sessionFactory;
|
||||
}
|
||||
}
|
||||
|
@ -81,8 +81,8 @@ public class LdapRealmTests extends LdapTestCase {
|
||||
String userTemplate = VALID_USER_TEMPLATE;
|
||||
Settings settings = buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE);
|
||||
RealmConfig config = new RealmConfig("test-ldap-realm", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapRealm ldap = new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService),
|
||||
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
LdapRealm ldap = new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService),
|
||||
threadPool);
|
||||
|
||||
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
|
||||
@ -106,7 +106,7 @@ public class LdapRealmTests extends LdapTestCase {
|
||||
.build();
|
||||
RealmConfig config = new RealmConfig("test-ldap-realm", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
|
||||
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
LdapRealm ldap =
|
||||
new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), threadPool);
|
||||
|
||||
@ -131,7 +131,7 @@ public class LdapRealmTests extends LdapTestCase {
|
||||
.build();
|
||||
RealmConfig config = new RealmConfig("test-ldap-realm", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
|
||||
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
ldapFactory = spy(ldapFactory);
|
||||
LdapRealm ldap =
|
||||
new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), threadPool);
|
||||
@ -156,7 +156,7 @@ public class LdapRealmTests extends LdapTestCase {
|
||||
.build();
|
||||
RealmConfig config = new RealmConfig("test-ldap-realm", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
|
||||
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
DnRoleMapper roleMapper = buildGroupAsRoleMapper(resourceWatcherService);
|
||||
ldapFactory = spy(ldapFactory);
|
||||
LdapRealm ldap = new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory, roleMapper, threadPool);
|
||||
@ -189,7 +189,7 @@ public class LdapRealmTests extends LdapTestCase {
|
||||
.build();
|
||||
RealmConfig config = new RealmConfig("test-ldap-realm", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
|
||||
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
ldapFactory = spy(ldapFactory);
|
||||
LdapRealm ldap =
|
||||
new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), threadPool);
|
||||
@ -215,7 +215,7 @@ public class LdapRealmTests extends LdapTestCase {
|
||||
.put("ssl.verification_mode", VerificationMode.CERTIFICATE)
|
||||
.build();
|
||||
RealmConfig config = new RealmConfig("test-ldap-realm", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
SessionFactory sessionFactory = LdapRealm.sessionFactory(config, sslService, LdapRealm.LDAP_TYPE);
|
||||
SessionFactory sessionFactory = LdapRealm.sessionFactory(config, sslService, threadPool, LdapRealm.LDAP_TYPE);
|
||||
assertThat(sessionFactory, is(instanceOf(LdapSessionFactory.class)));
|
||||
}
|
||||
|
||||
@ -231,7 +231,7 @@ public class LdapRealmTests extends LdapTestCase {
|
||||
.put("ssl.verification_mode", VerificationMode.CERTIFICATE)
|
||||
.build();
|
||||
RealmConfig config = new RealmConfig("test-ldap-realm-user-search", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
SessionFactory sessionFactory = LdapRealm.sessionFactory(config, sslService, LdapRealm.LDAP_TYPE);
|
||||
SessionFactory sessionFactory = LdapRealm.sessionFactory(config, sslService, threadPool, LdapRealm.LDAP_TYPE);
|
||||
try {
|
||||
assertThat(sessionFactory, is(instanceOf(LdapUserSearchSessionFactory.class)));
|
||||
} finally {
|
||||
@ -250,7 +250,7 @@ public class LdapRealmTests extends LdapTestCase {
|
||||
.build();
|
||||
RealmConfig config = new RealmConfig("test-ldap-realm-user-search", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
|
||||
() -> LdapRealm.sessionFactory(config, null, LdapRealm.LDAP_TYPE));
|
||||
() -> LdapRealm.sessionFactory(config, null, threadPool, LdapRealm.LDAP_TYPE));
|
||||
assertThat(e.getMessage(),
|
||||
containsString("settings were found for both" +
|
||||
" user search [xpack.security.authc.realms.test-ldap-realm-user-search.user_search.] and" +
|
||||
@ -266,7 +266,7 @@ public class LdapRealmTests extends LdapTestCase {
|
||||
.build();
|
||||
RealmConfig config = new RealmConfig("test-ldap-realm-user-search", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
|
||||
() -> LdapRealm.sessionFactory(config, null, LdapRealm.LDAP_TYPE));
|
||||
() -> LdapRealm.sessionFactory(config, null, threadPool, LdapRealm.LDAP_TYPE));
|
||||
assertThat(e.getMessage(),
|
||||
containsString("settings were not found for either" +
|
||||
" user search [xpack.security.authc.realms.test-ldap-realm-user-search.user_search.] or" +
|
||||
@ -283,7 +283,7 @@ public class LdapRealmTests extends LdapTestCase {
|
||||
.build();
|
||||
RealmConfig config = new RealmConfig("test-ldap-realm-userdn", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
|
||||
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
LdapRealm ldap = new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory,
|
||||
new DnRoleMapper(config, resourceWatcherService), threadPool);
|
||||
|
||||
@ -309,7 +309,7 @@ public class LdapRealmTests extends LdapTestCase {
|
||||
String userTemplate = VALID_USER_TEMPLATE;
|
||||
Settings settings = buildLdapSettings(new String[] { url.toString() }, userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE);
|
||||
RealmConfig config = new RealmConfig("test-ldap-realm", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
LdapRealm ldap = new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService),
|
||||
threadPool);
|
||||
|
||||
@ -344,7 +344,7 @@ public class LdapRealmTests extends LdapTestCase {
|
||||
|
||||
RealmConfig config = new RealmConfig("ldap-realm", settings.build(), globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
|
||||
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
LdapRealm realm = new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory,
|
||||
new DnRoleMapper(config, resourceWatcherService), threadPool);
|
||||
|
||||
|
@ -19,7 +19,10 @@ import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapTestCase;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
|
||||
import org.elasticsearch.test.junit.annotations.Network;
|
||||
import org.elasticsearch.threadpool.TestThreadPool;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.util.List;
|
||||
@ -35,11 +38,18 @@ import static org.hamcrest.Matchers.lessThan;
|
||||
public class LdapSessionFactoryTests extends LdapTestCase {
|
||||
private Settings globalSettings;
|
||||
private SSLService sslService;
|
||||
private ThreadPool threadPool;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
globalSettings = Settings.builder().put("path.home", createTempDir()).build();
|
||||
sslService = new SSLService(globalSettings, new Environment(globalSettings));
|
||||
threadPool = new TestThreadPool("LdapSessionFactoryTests thread pool");
|
||||
}
|
||||
|
||||
@After
|
||||
public void shutdown() throws InterruptedException {
|
||||
terminate(threadPool);
|
||||
}
|
||||
|
||||
public void testBindWithReadTimeout() throws Exception {
|
||||
@ -55,7 +65,7 @@ public class LdapSessionFactoryTests extends LdapTestCase {
|
||||
.build();
|
||||
|
||||
RealmConfig config = new RealmConfig("ldap_realm", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
String user = "Horatio Hornblower";
|
||||
SecureString userPass = new SecureString("pass");
|
||||
|
||||
@ -85,7 +95,7 @@ public class LdapSessionFactoryTests extends LdapTestCase {
|
||||
.build();
|
||||
|
||||
RealmConfig config = new RealmConfig("ldap_realm", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
String user = "Horatio Hornblower";
|
||||
SecureString userPass = new SecureString("pass");
|
||||
|
||||
@ -108,7 +118,7 @@ public class LdapSessionFactoryTests extends LdapTestCase {
|
||||
RealmConfig config = new RealmConfig("ldap_realm", buildLdapSettings(ldapUrls(), userTemplates, groupSearchBase,
|
||||
LdapSearchScope.SUB_TREE), globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String user = "Horatio Hornblower";
|
||||
SecureString userPass = new SecureString("pass");
|
||||
@ -129,7 +139,7 @@ public class LdapSessionFactoryTests extends LdapTestCase {
|
||||
RealmConfig config = new RealmConfig("ldap_realm", buildLdapSettings(ldapUrls(), userTemplates, groupSearchBase,
|
||||
LdapSearchScope.SUB_TREE), globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
|
||||
LdapSessionFactory ldapFac = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory ldapFac = new LdapSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String user = "Horatio Hornblower";
|
||||
SecureString userPass = new SecureString("pass");
|
||||
@ -147,7 +157,7 @@ public class LdapSessionFactoryTests extends LdapTestCase {
|
||||
RealmConfig config = new RealmConfig("ldap_realm", buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase,
|
||||
LdapSearchScope.SUB_TREE), globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
|
||||
LdapSessionFactory ldapFac = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory ldapFac = new LdapSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String user = "Horatio Hornblower";
|
||||
SecureString userPass = new SecureString("pass");
|
||||
@ -164,7 +174,7 @@ public class LdapSessionFactoryTests extends LdapTestCase {
|
||||
RealmConfig config = new RealmConfig("ldap_realm", buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase,
|
||||
LdapSearchScope.ONE_LEVEL), globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
|
||||
LdapSessionFactory ldapFac = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory ldapFac = new LdapSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String user = "Horatio Hornblower";
|
||||
try (LdapSession ldap = session(ldapFac, user, new SecureString("pass"))) {
|
||||
@ -179,7 +189,7 @@ public class LdapSessionFactoryTests extends LdapTestCase {
|
||||
RealmConfig config = new RealmConfig("ldap_realm", buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase,
|
||||
LdapSearchScope.BASE), globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
|
||||
LdapSessionFactory ldapFac = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory ldapFac = new LdapSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String user = "Horatio Hornblower";
|
||||
SecureString userPass = new SecureString("pass");
|
||||
|
@ -10,6 +10,7 @@ import com.unboundid.ldap.sdk.BindRequest;
|
||||
import com.unboundid.ldap.sdk.GetEntryLDAPConnectionPoolHealthCheck;
|
||||
import com.unboundid.ldap.sdk.LDAPConnectionPool;
|
||||
import com.unboundid.ldap.sdk.LDAPConnectionPoolHealthCheck;
|
||||
import com.unboundid.ldap.sdk.LDAPException;
|
||||
import com.unboundid.ldap.sdk.LDAPURL;
|
||||
import com.unboundid.ldap.sdk.SimpleBindRequest;
|
||||
import com.unboundid.ldap.sdk.SingleServerSet;
|
||||
@ -29,6 +30,9 @@ import org.elasticsearch.xpack.security.authc.ldap.support.LdapTestCase;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.support.NoOpLogger;
|
||||
import org.elasticsearch.test.junit.annotations.Network;
|
||||
import org.elasticsearch.threadpool.TestThreadPool;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.nio.file.Path;
|
||||
@ -45,9 +49,10 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
||||
|
||||
private SSLService sslService;
|
||||
private Settings globalSettings;
|
||||
private ThreadPool threadPool;
|
||||
|
||||
@Before
|
||||
public void initializeSslSocketFactory() throws Exception {
|
||||
public void init() throws Exception {
|
||||
Path keystore = getDataPath("support/ldaptrust.jks");
|
||||
Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
/*
|
||||
@ -62,6 +67,12 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
||||
.setSecureSettings(newSecureSettings("xpack.ssl.truststore.secure_password", "changeit"))
|
||||
.build();
|
||||
sslService = new SSLService(globalSettings, env);
|
||||
threadPool = new TestThreadPool("LdapUserSearchSessionFactoryTests");
|
||||
}
|
||||
|
||||
@After
|
||||
public void shutdown() throws InterruptedException {
|
||||
terminate(threadPool);
|
||||
}
|
||||
|
||||
private MockSecureSettings newSecureSettings(String key, String value) {
|
||||
@ -87,7 +98,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
||||
RealmConfig config = new RealmConfig("ldap_realm", builder.build(), globalSettings, new Environment(globalSettings),
|
||||
new ThreadContext(globalSettings));
|
||||
|
||||
LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService);
|
||||
LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
|
||||
try {
|
||||
assertThat(sessionFactory.supportsUnauthenticatedSession(), is(true));
|
||||
} finally {
|
||||
@ -99,6 +110,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void testUserSearchSubTree() throws Exception {
|
||||
String groupSearchBase = "o=sevenSeas";
|
||||
String userSearchBase = "o=sevenSeas";
|
||||
@ -118,7 +130,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
||||
RealmConfig config = new RealmConfig("ldap_realm", builder.build(), globalSettings, new Environment(globalSettings),
|
||||
new ThreadContext(globalSettings));
|
||||
|
||||
LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService);
|
||||
LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String user = "William Bush";
|
||||
SecureString userPass = new SecureString("pass");
|
||||
@ -164,7 +176,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
||||
RealmConfig config = new RealmConfig("ldap_realm", builder.build(), globalSettings, new Environment(globalSettings),
|
||||
new ThreadContext(globalSettings));
|
||||
|
||||
LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService);
|
||||
LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String user = "William Bush";
|
||||
SecureString userPass = new SecureString("pass");
|
||||
@ -201,7 +213,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
||||
RealmConfig config = new RealmConfig("ldap_realm", builder.build(), globalSettings, new Environment(globalSettings),
|
||||
new ThreadContext(globalSettings));
|
||||
|
||||
LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService);
|
||||
LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String user = "William Bush";
|
||||
SecureString userPass = new SecureString("pass");
|
||||
@ -247,7 +259,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
||||
RealmConfig config = new RealmConfig("ldap_realm", builder.build(), globalSettings, new Environment(globalSettings),
|
||||
new ThreadContext(globalSettings));
|
||||
|
||||
LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService);
|
||||
LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String user = "William Bush";
|
||||
SecureString userPass = new SecureString("pass");
|
||||
@ -284,7 +296,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
||||
RealmConfig config = new RealmConfig("ldap_realm", builder.build(), globalSettings, new Environment(globalSettings),
|
||||
new ThreadContext(globalSettings));
|
||||
|
||||
LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService);
|
||||
LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String user = "William Bush";
|
||||
SecureString userPass = new SecureString("pass");
|
||||
@ -329,7 +341,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
||||
RealmConfig config = new RealmConfig("ldap_realm", builder.build(), globalSettings, new Environment(globalSettings),
|
||||
new ThreadContext(globalSettings));
|
||||
|
||||
LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService);
|
||||
LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String user = "William Bush";
|
||||
SecureString userPass = new SecureString("pass");
|
||||
@ -358,7 +370,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
||||
.put("user_search.pool.enabled", randomBoolean())
|
||||
.build(), globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
|
||||
LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService);
|
||||
LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String user = "wbush";
|
||||
SecureString userPass = new SecureString("pass");
|
||||
@ -404,7 +416,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
||||
Settings fullSettings = builder.build();
|
||||
sslService = new SSLService(fullSettings, new Environment(fullSettings));
|
||||
RealmConfig config = new RealmConfig("ad-as-ldap-test", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService);
|
||||
LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String user = "Bruce Banner";
|
||||
try {
|
||||
@ -500,7 +512,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
||||
|
||||
LdapUserSearchSessionFactory searchSessionFactory = null;
|
||||
try {
|
||||
searchSessionFactory = new LdapUserSearchSessionFactory(config, sslService);
|
||||
searchSessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
|
||||
} finally {
|
||||
if (searchSessionFactory != null) {
|
||||
searchSessionFactory.close();
|
||||
@ -520,7 +532,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
||||
|
||||
LdapUserSearchSessionFactory searchSessionFactory = null;
|
||||
try {
|
||||
searchSessionFactory = new LdapUserSearchSessionFactory(config, sslService);
|
||||
searchSessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
|
||||
final PlainActionFuture<LdapSession> future = new PlainActionFuture<>();
|
||||
searchSessionFactory.session("cn=ironman", new SecureString("password".toCharArray()), future);
|
||||
future.get();
|
||||
@ -572,7 +584,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
||||
RealmConfig config = new RealmConfig("ldap_realm", ldapSettings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
LdapUserSearchSessionFactory searchSessionFactory = null;
|
||||
try {
|
||||
searchSessionFactory = new LdapUserSearchSessionFactory(config, sslService);
|
||||
searchSessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
|
||||
} finally {
|
||||
if (searchSessionFactory != null) {
|
||||
searchSessionFactory.close();
|
||||
@ -581,4 +593,15 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
||||
|
||||
assertSettingDeprecationsAndWarnings(new Setting[] { LdapUserSearchSessionFactory.SEARCH_ATTRIBUTE });
|
||||
}
|
||||
|
||||
static LdapUserSearchSessionFactory getLdapUserSearchSessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool)
|
||||
throws LDAPException {
|
||||
LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService, threadPool);
|
||||
if (sessionFactory.getConnectionPool() != null) {
|
||||
// don't use this in production
|
||||
// used here to catch bugs that might get masked by an automatic retry
|
||||
sessionFactory.getConnectionPool().setRetryFailedOperationsDueToInvalidConnections(false);
|
||||
}
|
||||
return sessionFactory;
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,12 @@ import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.mocksocket.MockServerSocket;
|
||||
import org.elasticsearch.mocksocket.MockSocket;
|
||||
import org.elasticsearch.test.junit.annotations.TestLogging;
|
||||
import org.elasticsearch.threadpool.TestThreadPool;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
@ -36,6 +40,18 @@ import static org.hamcrest.Matchers.not;
|
||||
@TestLogging("org.elasticsearch.xpack.security.authc.ldap.support:DEBUG")
|
||||
public class SessionFactoryLoadBalancingTests extends LdapTestCase {
|
||||
|
||||
private ThreadPool threadPool;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
threadPool = new TestThreadPool("SessionFactoryLoadBalancingTests thread pool");
|
||||
}
|
||||
|
||||
@After
|
||||
public void shutdown() throws InterruptedException {
|
||||
terminate(threadPool);
|
||||
}
|
||||
|
||||
public void testRoundRobin() throws Exception {
|
||||
TestSessionFactory testSessionFactory = createSessionFactory(LdapLoadBalancing.ROUND_ROBIN);
|
||||
|
||||
@ -208,13 +224,13 @@ public class SessionFactoryLoadBalancingTests extends LdapTestCase {
|
||||
LdapSearchScope.SUB_TREE, loadBalancing);
|
||||
RealmConfig config = new RealmConfig("test-session-factory", settings, Settings.builder().put("path.home",
|
||||
createTempDir()).build(), new ThreadContext(Settings.EMPTY));
|
||||
return new TestSessionFactory(config, new SSLService(Settings.EMPTY, new Environment(config.globalSettings())));
|
||||
return new TestSessionFactory(config, new SSLService(Settings.EMPTY, new Environment(config.globalSettings())), threadPool);
|
||||
}
|
||||
|
||||
static class TestSessionFactory extends SessionFactory {
|
||||
|
||||
protected TestSessionFactory(RealmConfig config, SSLService sslService) {
|
||||
super(config, sslService);
|
||||
protected TestSessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool) {
|
||||
super(config, sslService, threadPool);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -16,8 +16,12 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.threadpool.TestThreadPool;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.VerificationMode;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
@ -26,6 +30,18 @@ import static org.hamcrest.Matchers.is;
|
||||
|
||||
public class SessionFactoryTests extends ESTestCase {
|
||||
|
||||
private ThreadPool threadPool;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
threadPool = new TestThreadPool("SessionFactoryTests thread pool");
|
||||
}
|
||||
|
||||
@After
|
||||
public void shutdown() throws InterruptedException {
|
||||
terminate(threadPool);
|
||||
}
|
||||
|
||||
public void testConnectionFactoryReturnsCorrectLDAPConnectionOptionsWithDefaultSettings() throws Exception {
|
||||
final Environment environment = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
RealmConfig realmConfig = new RealmConfig("conn settings", Settings.EMPTY, environment.settings(), environment,
|
||||
@ -92,7 +108,7 @@ public class SessionFactoryTests extends ESTestCase {
|
||||
Settings global = Settings.builder().put("path.home", createTempDir()).build();
|
||||
final RealmConfig realmConfig = new RealmConfig("_name", Settings.builder().put("url", "ldap://localhost:389").build(),
|
||||
global, new ThreadContext(Settings.EMPTY));
|
||||
return new SessionFactory(realmConfig, null) {
|
||||
return new SessionFactory(realmConfig, null, threadPool) {
|
||||
|
||||
@Override
|
||||
public void session(String user, SecureString password, ActionListener<LdapSession> listener) {
|
||||
|
@ -15,6 +15,8 @@ import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.common.util.concurrent.UncategorizedExecutionException;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.threadpool.TestThreadPool;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.LdapSessionFactory;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.LdapTestUtils;
|
||||
@ -25,6 +27,7 @@ import org.elasticsearch.xpack.security.authc.ldap.support.LdapTestCase;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.VerificationMode;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.nio.file.Path;
|
||||
@ -49,8 +52,19 @@ public class OpenLdapTests extends ESTestCase {
|
||||
|
||||
private boolean useGlobalSSL;
|
||||
private SSLService sslService;
|
||||
private ThreadPool threadPool;
|
||||
private Settings globalSettings;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
threadPool = new TestThreadPool("OpenLdapTests thread pool");
|
||||
}
|
||||
|
||||
@After
|
||||
public void shutdown() throws InterruptedException {
|
||||
terminate(threadPool);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enableWarningsCheck() {
|
||||
return false;
|
||||
@ -95,7 +109,7 @@ public class OpenLdapTests extends ESTestCase {
|
||||
String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
|
||||
RealmConfig config = new RealmConfig("oldap-test", buildLdapSettings(OPEN_LDAP_URL, userTemplate, groupSearchBase,
|
||||
LdapSearchScope.ONE_LEVEL), globalSettings, new ThreadContext(Settings.EMPTY));
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String[] users = new String[] { "blackwidow", "cap", "hawkeye", "hulk", "ironman", "thor" };
|
||||
for (String user : users) {
|
||||
@ -113,7 +127,7 @@ public class OpenLdapTests extends ESTestCase {
|
||||
String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
|
||||
RealmConfig config = new RealmConfig("oldap-test", buildLdapSettings(OPEN_LDAP_URL, userTemplate, groupSearchBase,
|
||||
LdapSearchScope.BASE), globalSettings, new ThreadContext(Settings.EMPTY));
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String[] users = new String[] { "blackwidow", "cap", "hawkeye", "hulk", "ironman", "thor" };
|
||||
for (String user : users) {
|
||||
@ -132,7 +146,7 @@ public class OpenLdapTests extends ESTestCase {
|
||||
.put("group_search.user_attribute", "uid")
|
||||
.build();
|
||||
RealmConfig config = new RealmConfig("oldap-test", settings, globalSettings, new ThreadContext(Settings.EMPTY));
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
|
||||
try (LdapSession ldap = session(sessionFactory, "selvig", PASSWORD_SECURE_STRING)){
|
||||
assertThat(groups(ldap), hasItem(containsString("Geniuses")));
|
||||
@ -150,7 +164,7 @@ public class OpenLdapTests extends ESTestCase {
|
||||
.put(SessionFactory.TIMEOUT_TCP_READ_SETTING, "1ms") //1 millisecond
|
||||
.build();
|
||||
RealmConfig config = new RealmConfig("oldap-test", settings, globalSettings, new ThreadContext(Settings.EMPTY));
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
|
||||
LDAPException expected = expectThrows(LDAPException.class,
|
||||
() -> session(sessionFactory, "thor", PASSWORD_SECURE_STRING).groups(new PlainActionFuture<>()));
|
||||
@ -167,7 +181,7 @@ public class OpenLdapTests extends ESTestCase {
|
||||
.build();
|
||||
|
||||
RealmConfig config = new RealmConfig("oldap-test", settings, globalSettings, new ThreadContext(Settings.EMPTY));
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService);
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String user = "blackwidow";
|
||||
UncategorizedExecutionException e = expectThrows(UncategorizedExecutionException.class,
|
||||
|
@ -14,12 +14,15 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.test.OpenLdapTests;
|
||||
import org.elasticsearch.threadpool.TestThreadPool;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSearchScope;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapTestCase;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.nio.file.Path;
|
||||
@ -38,11 +41,11 @@ import static org.hamcrest.Matchers.is;
|
||||
public class OpenLdapUserSearchSessionFactoryTests extends ESTestCase {
|
||||
|
||||
private Settings globalSettings;
|
||||
private ThreadPool threadPool;
|
||||
|
||||
@Before
|
||||
public void initializeSslSocketFactory() throws Exception {
|
||||
public void init() throws Exception {
|
||||
Path keystore = getDataPath(LDAPTRUST_PATH);
|
||||
|
||||
/*
|
||||
* Prior to each test we reinitialize the socket factory with a new SSLService so that we get a new SSLContext.
|
||||
* If we re-use a SSLContext, previously connected sessions can get re-established which breaks hostname
|
||||
@ -53,6 +56,12 @@ public class OpenLdapUserSearchSessionFactoryTests extends ESTestCase {
|
||||
.put("xpack.ssl.truststore.path", keystore)
|
||||
.setSecureSettings(newSecureSettings("xpack.ssl.truststore.secure_password", "changeit"))
|
||||
.build();
|
||||
threadPool = new TestThreadPool("LdapUserSearchSessionFactoryTests");
|
||||
}
|
||||
|
||||
@After
|
||||
public void shutdown() throws InterruptedException {
|
||||
terminate(threadPool);
|
||||
}
|
||||
|
||||
public void testUserSearchwithBindUserOpenLDAP() throws Exception {
|
||||
@ -75,7 +84,7 @@ public class OpenLdapUserSearchSessionFactoryTests extends ESTestCase {
|
||||
|
||||
|
||||
String[] users = new String[] { "cap", "hawkeye", "hulk", "ironman", "thor" };
|
||||
try (LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService)) {
|
||||
try (LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService, threadPool)) {
|
||||
for (String user : users) {
|
||||
//auth
|
||||
try (LdapSession ldap = session(sessionFactory, user, new SecureString(OpenLdapTests.PASSWORD))) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user