Add secure_bind_password to LDAP realm (elastic/x-pack-elasticsearch#4192)
Adds a SecureSetting option for the "bind_password" in LDAP/AD realms and deprecates the non-secure version. LDAP bind passwords should now be configured with the setting `xpack.security.authc.realms.REALM_NAME.secure_bind_password` in the elasticsearch keystore. Original commit: elastic/x-pack-elasticsearch@1a0cebd77e
This commit is contained in:
parent
01ab4782a1
commit
e69c5d4d48
|
@ -93,7 +93,7 @@ connections to Active Directory. These pooled connection reduce the number of
|
|||
resources that must be created and destroyed with every user authentication.
|
||||
|
||||
The following example shows the configuration of a bind user through the user of the
|
||||
`bind_dn` and `bind_password` settings.
|
||||
`bind_dn` and `secure_bind_password` settings.
|
||||
|
||||
[source, yaml]
|
||||
------------------------------------------------------------
|
||||
|
@ -107,12 +107,20 @@ xpack:
|
|||
domain_name: ad.example.com
|
||||
url: ldaps://ad.example.com:636
|
||||
bind_dn: es_svc_user@ad.example.com <1>
|
||||
bind_password: es_svc_user_password
|
||||
------------------------------------------------------------
|
||||
<1> This is the user that all Active Directory search requests are executed as.
|
||||
Without a bind user configured, all requests run as the user that is authenticating
|
||||
with Elasticsearch.
|
||||
|
||||
The password for the `bind_dn` user should be configured by adding the appropriate
|
||||
`secure_bind_password` setting to the {es} keystore.
|
||||
For example, the following command adds the password for the example realm above:
|
||||
|
||||
[source, shell]
|
||||
------------------------------------------------------------
|
||||
bin/elasticsearch-keystore add xpack.security.authc.realms.active_directory.secure_bind_password
|
||||
------------------------------------------------------------
|
||||
|
||||
When a bind user is configured, connection pooling is enabled by default.
|
||||
Connection pooling can be disabled using the `user_search.pool.enabled` setting.
|
||||
|
||||
|
@ -223,6 +231,9 @@ operation are supported: failover and load balancing
|
|||
Active Directory. Due to its potential security impact,
|
||||
`bind_password` is not exposed via the
|
||||
{ref}/cluster-nodes-info.html#cluster-nodes-info[nodes info API].
|
||||
*Deprecated.* Use `secure_bind_password` instead.
|
||||
| `secure_bind_password` | no | ({ref}/secure-settings.html[Secure])
|
||||
The password for the user that is used to bind to Active Directory.
|
||||
| `load_balance.type` | no | The behavior to use when there are multiple LDAP URLs defined.
|
||||
For supported values see <<ad-load-balancing>>.
|
||||
| `load_balance.cache_ttl` | no | When using `dns_failover` or `dns_round_robin` as the load
|
||||
|
|
|
@ -61,7 +61,6 @@ xpack:
|
|||
order: 0
|
||||
url: "ldaps://ldap.example.com:636"
|
||||
bind_dn: "cn=ldapuser, ou=users, o=services, dc=example, dc=com"
|
||||
bind_password: x-pack-test-password
|
||||
user_search:
|
||||
base_dn: "dc=example,dc=com"
|
||||
attribute: cn
|
||||
|
@ -72,6 +71,15 @@ xpack:
|
|||
unmapped_groups_as_roles: false
|
||||
------------------------------------------------------------
|
||||
+
|
||||
The password for the `bind_dn` user should be configured by adding the appropriate
|
||||
`secure_bind_password` setting to the {es} keystore.
|
||||
For example, the following command adds the password for the example realm above:
|
||||
+
|
||||
[source, shell]
|
||||
------------------------------------------------------------
|
||||
bin/elasticsearch-keystore add xpack.security.authc.realms.ldap1.secure_bind_password
|
||||
------------------------------------------------------------
|
||||
+
|
||||
IMPORTANT: When you configure realms in `elasticsearch.yml`, only the
|
||||
realms you specify are used for authentication. If you also want to use the
|
||||
`native` or `file` realms, you must include them in the realm chain.
|
||||
|
@ -281,9 +289,12 @@ failover and load balancing modes of operation.
|
|||
impact, `bind_dn` is not exposed via the
|
||||
{ref}/cluster-nodes-info.html#cluster-nodes-info[nodes info API].
|
||||
| `bind_password` | no | The password for the user that is used to bind to the
|
||||
LDAP. Due to its potential security impact,
|
||||
LDAP directory. Due to its potential security impact,
|
||||
`bind_password` is not exposed via the
|
||||
{ref}/cluster-nodes-info.html#cluster-nodes-info[nodes info API].
|
||||
*Deprecated.* Use `secure_bind_password` instead.
|
||||
| `secure_bind_password` | no | ({ref}/secure-settings.html[Secure])
|
||||
The password for the user that is used to bind to LDAP directory.
|
||||
| `user_search.base_dn` | yes | Specifies a container DN to search for users.
|
||||
| `user_search.scope` | no | The scope of the user search. Valid values are `sub_tree`,
|
||||
`one_level` or `base`. `one_level` only searches objects
|
||||
|
|
|
@ -10,8 +10,8 @@ To "run as" (impersonate) another user, you must be able to retrieve the user fr
|
|||
the realm you use to authenticate. Both the internal `native` and `file` realms
|
||||
support this out of the box. The LDAP realm must be configured to run in
|
||||
<<ldap-user-search, _user search_ mode>>. The Active Directory realm must be
|
||||
<<ad-settings,configured with a `bind_dn` and `bind_password`>> to support _run as_.
|
||||
The PKI realm does not support _run as_.
|
||||
<<ad-settings,configured with a `bind_dn` and `secure_bind_password`>> to support
|
||||
_run as_. The PKI realm does not support _run as_.
|
||||
|
||||
To submit requests on behalf of other users, you need to have the `run_as`
|
||||
permission. For example, the following role grants permission to submit request
|
||||
|
|
|
@ -182,7 +182,12 @@ If this is not specified, an anonymous bind will be attempted.
|
|||
Defaults to Empty.
|
||||
|
||||
`bind_password`::
|
||||
The password for the user that will be used to bind to the LDAP.
|
||||
The password for the user that will be used to bind to the LDAP directory.
|
||||
Defaults to Empty.
|
||||
*Deprecated.* Use `secure_bind_password` instead.
|
||||
|
||||
`secure_bind_password` (<<secure-settings,Secure>>)::
|
||||
The password for the user that will be used to bind to the LDAP directory.
|
||||
Defaults to Empty.
|
||||
|
||||
`user_dn_templates`::
|
||||
|
@ -410,6 +415,11 @@ Defaults to Empty.
|
|||
`bind_password`::
|
||||
The password for the user that will be used to bind to Active Directory.
|
||||
Defaults to Empty.
|
||||
*Deprecated.* Use `secure_bind_password` instead.
|
||||
|
||||
`secure_bind_password` (<<secure-settings,Secure>>)::
|
||||
The password for the user that will be used to bind to Active Directory.
|
||||
Defaults to Empty.
|
||||
|
||||
`unmapped_groups_as_roles`::
|
||||
Takes a boolean variable. When this element is set to `true`, the names of any
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.core.security.authc.ldap;
|
||||
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.util.set.Sets;
|
||||
|
@ -12,11 +13,15 @@ import org.elasticsearch.common.util.set.Sets;
|
|||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.elasticsearch.common.settings.SecureSetting.secureString;
|
||||
|
||||
public final class PoolingSessionFactorySettings {
|
||||
public static final TimeValue DEFAULT_HEALTH_CHECK_INTERVAL = TimeValue.timeValueSeconds(60L);
|
||||
public static final Setting<String> BIND_DN = Setting.simpleString("bind_dn", Setting.Property.NodeScope, Setting.Property.Filtered);
|
||||
public static final Setting<String> BIND_PASSWORD = Setting.simpleString("bind_password", Setting.Property.NodeScope,
|
||||
Setting.Property.Filtered);
|
||||
public static final Setting<SecureString> LEGACY_BIND_PASSWORD = new Setting<>("bind_password", "", SecureString::new,
|
||||
Setting.Property.NodeScope, Setting.Property.Filtered, Setting.Property.Deprecated);
|
||||
public static final Setting<SecureString> SECURE_BIND_PASSWORD = secureString("secure_bind_password", LEGACY_BIND_PASSWORD);
|
||||
|
||||
public static final int DEFAULT_CONNECTION_POOL_INITIAL_SIZE = 0;
|
||||
public static final Setting<Integer> POOL_INITIAL_SIZE = Setting.intSetting("user_search.pool.initial_size",
|
||||
DEFAULT_CONNECTION_POOL_INITIAL_SIZE, 0, Setting.Property.NodeScope);
|
||||
|
@ -34,6 +39,6 @@ public final class PoolingSessionFactorySettings {
|
|||
|
||||
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);
|
||||
SECURE_BIND_PASSWORD, LEGACY_BIND_PASSWORD);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ import com.unboundid.ldap.sdk.SearchResultEntry;
|
|||
import com.unboundid.ldap.sdk.SimpleBindRequest;
|
||||
import com.unboundid.ldap.sdk.controls.AuthorizationIdentityRequestControl;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.core.internal.io.IOUtils;
|
||||
import org.elasticsearch.ElasticsearchSecurityException;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.ActionRunnable;
|
||||
|
@ -25,6 +24,7 @@ import org.elasticsearch.common.settings.SecureString;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
|
||||
import org.elasticsearch.core.internal.io.IOUtils;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
|
||||
|
@ -66,23 +66,18 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
|
|||
|
||||
ActiveDirectorySessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool) throws LDAPException {
|
||||
super(config, sslService, new ActiveDirectoryGroupsResolver(config.settings()),
|
||||
ActiveDirectorySessionFactorySettings.POOL_ENABLED, () -> {
|
||||
if (PoolingSessionFactorySettings.BIND_DN.exists(config.settings())) {
|
||||
return new SimpleBindRequest(getBindDN(config.settings()),
|
||||
PoolingSessionFactorySettings.BIND_PASSWORD.get(config.settings()));
|
||||
} else {
|
||||
return new SimpleBindRequest();
|
||||
}
|
||||
}, () -> {
|
||||
if (PoolingSessionFactorySettings.BIND_DN.exists(config.settings())) {
|
||||
final String healthCheckDn = PoolingSessionFactorySettings.BIND_DN.get(config.settings());
|
||||
if (healthCheckDn.isEmpty() && healthCheckDn.indexOf('=') > 0) {
|
||||
return healthCheckDn;
|
||||
}
|
||||
}
|
||||
return config.settings().get(ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_BASEDN_SETTING,
|
||||
config.settings().get(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING));
|
||||
}, threadPool);
|
||||
ActiveDirectorySessionFactorySettings.POOL_ENABLED,
|
||||
PoolingSessionFactorySettings.BIND_DN.exists(config.settings())? getBindDN(config.settings()) : null,
|
||||
() -> {
|
||||
if (PoolingSessionFactorySettings.BIND_DN.exists(config.settings())) {
|
||||
final String healthCheckDn = PoolingSessionFactorySettings.BIND_DN.get(config.settings());
|
||||
if (healthCheckDn.isEmpty() && healthCheckDn.indexOf('=') > 0) {
|
||||
return healthCheckDn;
|
||||
}
|
||||
}
|
||||
return config.settings().get(ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_BASEDN_SETTING,
|
||||
config.settings().get(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING));
|
||||
}, threadPool);
|
||||
Settings settings = config.settings();
|
||||
String domainName = settings.get(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING);
|
||||
if (domainName == null) {
|
||||
|
@ -155,9 +150,7 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
|
|||
}
|
||||
try {
|
||||
final LDAPConnection connection = LdapUtils.privilegedConnect(serverSet::getConnection);
|
||||
final SimpleBindRequest bind = new SimpleBindRequest(getBindDN(config.settings()),
|
||||
PoolingSessionFactorySettings.BIND_PASSWORD.get(config.settings()));
|
||||
LdapUtils.maybeForkThenBind(connection, bind, threadPool, new AbstractRunnable() {
|
||||
LdapUtils.maybeForkThenBind(connection, bindCredentials, threadPool, new AbstractRunnable() {
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
|
@ -225,7 +218,7 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
|
|||
final LdapSearchScope userSearchScope;
|
||||
final String userSearchFilter;
|
||||
final String bindDN;
|
||||
final String bindPassword; // TODO this needs to be a setting in the secure settings store!
|
||||
final SecureString bindPassword;
|
||||
final ThreadPool threadPool;
|
||||
|
||||
ADAuthenticator(RealmConfig realm, TimeValue timeout, boolean ignoreReferralErrors, Logger logger, GroupsResolver groupsResolver,
|
||||
|
@ -239,7 +232,7 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
|
|||
this.metaDataResolver = metaDataResolver;
|
||||
final Settings settings = realm.settings();
|
||||
this.bindDN = getBindDN(settings);
|
||||
this.bindPassword = PoolingSessionFactorySettings.BIND_PASSWORD.get(settings);
|
||||
this.bindPassword = PoolingSessionFactorySettings.SECURE_BIND_PASSWORD.get(settings);
|
||||
this.threadPool = threadPool;
|
||||
userSearchDN = settings.get(ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_BASEDN_SETTING, domainDN);
|
||||
userSearchScope = LdapSearchScope.resolve(settings.get(ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_SCOPE_SETTING),
|
||||
|
@ -274,7 +267,7 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
|
|||
if (bindDN.isEmpty()) {
|
||||
searchRunnable.run();
|
||||
} else {
|
||||
final SimpleBindRequest bind = new SimpleBindRequest(bindDN, bindPassword);
|
||||
final SimpleBindRequest bind = new SimpleBindRequest(bindDN, CharArrays.toUtf8Bytes(bindPassword.getChars()));
|
||||
LdapUtils.maybeForkThenBind(connection, bind, threadPool, searchRunnable);
|
||||
}
|
||||
}
|
||||
|
@ -439,7 +432,7 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
|
|||
final byte[] passwordBytes = CharArrays.toUtf8Bytes(password.getChars());
|
||||
final SimpleBindRequest bind = bindDN.isEmpty()
|
||||
? new SimpleBindRequest(username, passwordBytes)
|
||||
: new SimpleBindRequest(bindDN, bindPassword);
|
||||
: new SimpleBindRequest(bindDN, CharArrays.toUtf8Bytes(bindPassword.getChars()));
|
||||
LdapUtils.maybeForkThenBind(searchConnection, bind, threadPool, new ActionRunnable<String>(listener) {
|
||||
@Override
|
||||
protected void doRun() throws Exception {
|
||||
|
|
|
@ -12,17 +12,16 @@ import com.unboundid.ldap.sdk.LDAPException;
|
|||
import com.unboundid.ldap.sdk.LDAPInterface;
|
||||
import com.unboundid.ldap.sdk.SearchResultEntry;
|
||||
import com.unboundid.ldap.sdk.SimpleBindRequest;
|
||||
import org.elasticsearch.core.internal.io.IOUtils;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.ActionRunnable;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
|
||||
import org.elasticsearch.core.internal.io.IOUtils;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
|
||||
import org.elasticsearch.xpack.core.security.authc.ldap.LdapUserSearchSessionFactorySettings;
|
||||
import org.elasticsearch.xpack.core.security.authc.ldap.PoolingSessionFactorySettings;
|
||||
import org.elasticsearch.xpack.core.security.authc.ldap.SearchGroupsResolverSettings;
|
||||
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope;
|
||||
import org.elasticsearch.xpack.core.security.authc.support.CharArrays;
|
||||
|
@ -31,6 +30,7 @@ import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession;
|
|||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession.GroupsResolver;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils;
|
||||
|
||||
import static org.elasticsearch.xpack.core.security.authc.ldap.PoolingSessionFactorySettings.BIND_DN;
|
||||
import static org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.attributesToSearchFor;
|
||||
import static org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.createFilter;
|
||||
import static org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.searchForEntry;
|
||||
|
@ -45,10 +45,10 @@ class LdapUserSearchSessionFactory extends PoolingSessionFactory {
|
|||
|
||||
LdapUserSearchSessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool) throws LDAPException {
|
||||
super(config, sslService, groupResolver(config.settings()), LdapUserSearchSessionFactorySettings.POOL_ENABLED,
|
||||
() -> LdapUserSearchSessionFactory.bindRequest(config.settings()),
|
||||
BIND_DN.exists(config.settings()) ? BIND_DN.get(config.settings()) : null,
|
||||
() -> {
|
||||
if (PoolingSessionFactorySettings.BIND_DN.exists(config.settings())) {
|
||||
return PoolingSessionFactorySettings.BIND_DN.get(config.settings());
|
||||
if (BIND_DN.exists(config.settings())) {
|
||||
return BIND_DN.get(config.settings());
|
||||
} else {
|
||||
return LdapUserSearchSessionFactorySettings.SEARCH_BASE_DN.get(config.settings());
|
||||
}
|
||||
|
@ -66,15 +66,6 @@ class LdapUserSearchSessionFactory extends PoolingSessionFactory {
|
|||
config.name(), userSearchBaseDn, searchFilter);
|
||||
}
|
||||
|
||||
static SimpleBindRequest bindRequest(Settings settings) {
|
||||
if (PoolingSessionFactorySettings.BIND_DN.exists(settings)) {
|
||||
return new SimpleBindRequest(PoolingSessionFactorySettings.BIND_DN.get(settings),
|
||||
PoolingSessionFactorySettings.BIND_PASSWORD.get(settings));
|
||||
} else {
|
||||
return new SimpleBindRequest();
|
||||
}
|
||||
}
|
||||
|
||||
static boolean hasUserSearchSettings(RealmConfig config) {
|
||||
return config.settings().getByPrefix("user_search.").isEmpty() == false;
|
||||
}
|
||||
|
@ -118,8 +109,7 @@ class LdapUserSearchSessionFactory extends PoolingSessionFactory {
|
|||
void getSessionWithoutPool(String user, SecureString password, ActionListener<LdapSession> listener) {
|
||||
try {
|
||||
final LDAPConnection connection = LdapUtils.privilegedConnect(serverSet::getConnection);
|
||||
final SimpleBindRequest bind = bindRequest(config.settings());
|
||||
LdapUtils.maybeForkThenBind(connection, bind, threadPool, new AbstractRunnable() {
|
||||
LdapUtils.maybeForkThenBind(connection, bindCredentials, threadPool, new AbstractRunnable() {
|
||||
@Override
|
||||
protected void doRun() throws Exception {
|
||||
findUser(user, connection, ActionListener.wrap((entry) -> {
|
||||
|
@ -133,7 +123,7 @@ class LdapUserSearchSessionFactory extends PoolingSessionFactory {
|
|||
LdapUtils.maybeForkThenBind(connection, userBind, threadPool, new AbstractRunnable() {
|
||||
@Override
|
||||
protected void doRun() throws Exception {
|
||||
LdapUtils.maybeForkThenBind(connection, bind, threadPool, new AbstractRunnable() {
|
||||
LdapUtils.maybeForkThenBind(connection, bindCredentials, threadPool, new AbstractRunnable() {
|
||||
|
||||
@Override
|
||||
protected void doRun() throws Exception {
|
||||
|
@ -195,8 +185,7 @@ class LdapUserSearchSessionFactory extends PoolingSessionFactory {
|
|||
void getUnauthenticatedSessionWithoutPool(String user, ActionListener<LdapSession> listener) {
|
||||
try {
|
||||
final LDAPConnection connection = LdapUtils.privilegedConnect(serverSet::getConnection);
|
||||
final SimpleBindRequest bind = bindRequest(config.settings());
|
||||
LdapUtils.maybeForkThenBind(connection, bind, threadPool, new AbstractRunnable() {
|
||||
LdapUtils.maybeForkThenBind(connection, bindCredentials, threadPool, new AbstractRunnable() {
|
||||
@Override
|
||||
protected void doRun() throws Exception {
|
||||
findUser(user, connection, ActionListener.wrap((entry) -> {
|
||||
|
|
|
@ -11,9 +11,11 @@ import com.unboundid.ldap.sdk.LDAPConnectionPool;
|
|||
import com.unboundid.ldap.sdk.LDAPConnectionPoolHealthCheck;
|
||||
import com.unboundid.ldap.sdk.LDAPException;
|
||||
import com.unboundid.ldap.sdk.ServerSet;
|
||||
import com.unboundid.ldap.sdk.SimpleBindRequest;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.message.ParameterizedMessage;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.lease.Releasable;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
|
@ -23,6 +25,7 @@ import org.elasticsearch.threadpool.ThreadPool;
|
|||
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
|
||||
import org.elasticsearch.xpack.core.security.authc.ldap.PoolingSessionFactorySettings;
|
||||
import org.elasticsearch.xpack.core.security.authc.support.CharArrays;
|
||||
import org.elasticsearch.xpack.core.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapMetaDataResolver;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession;
|
||||
|
@ -31,6 +34,9 @@ import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
|
|||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.elasticsearch.xpack.core.security.authc.ldap.PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD;
|
||||
import static org.elasticsearch.xpack.core.security.authc.ldap.PoolingSessionFactorySettings.SECURE_BIND_PASSWORD;
|
||||
|
||||
/**
|
||||
* Base class for LDAP session factories that can make use of a connection pool
|
||||
*/
|
||||
|
@ -39,6 +45,7 @@ abstract class PoolingSessionFactory extends SessionFactory implements Releasabl
|
|||
private final boolean useConnectionPool;
|
||||
private final LDAPConnectionPool connectionPool;
|
||||
|
||||
final SimpleBindRequest bindCredentials;
|
||||
final LdapMetaDataResolver metaDataResolver;
|
||||
final LdapSession.GroupsResolver groupResolver;
|
||||
|
||||
|
@ -48,19 +55,41 @@ abstract class PoolingSessionFactory extends SessionFactory implements Releasabl
|
|||
* @param sslService the ssl service to get a socket factory or context from
|
||||
* @param groupResolver the resolver to use to find groups belonging to a user
|
||||
* @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 bindDn the DN of the user to be used for pooled connections (or null to perform anonymous bind)
|
||||
* @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,
|
||||
ThreadPool threadPool) throws LDAPException {
|
||||
Setting<Boolean> poolingEnabled, @Nullable String bindDn, Supplier<String> healthCheckDNSupplier,
|
||||
ThreadPool threadPool) throws LDAPException {
|
||||
super(config, sslService, threadPool);
|
||||
this.groupResolver = groupResolver;
|
||||
this.metaDataResolver = new LdapMetaDataResolver(config.settings(), ignoreReferralErrors);
|
||||
|
||||
final byte[] bindPassword;
|
||||
if (LEGACY_BIND_PASSWORD.exists(config.settings())) {
|
||||
if (SECURE_BIND_PASSWORD.exists(config.settings())) {
|
||||
throw new IllegalArgumentException("You cannot specify both ["
|
||||
+ RealmSettings.getFullSettingKey(config, LEGACY_BIND_PASSWORD) + "] and ["
|
||||
+ RealmSettings.getFullSettingKey(config, SECURE_BIND_PASSWORD) + "]");
|
||||
} else {
|
||||
bindPassword = CharArrays.toUtf8Bytes(LEGACY_BIND_PASSWORD.get(config.settings()).getChars());
|
||||
}
|
||||
} else if (SECURE_BIND_PASSWORD.exists(config.settings())) {
|
||||
bindPassword = CharArrays.toUtf8Bytes(SECURE_BIND_PASSWORD.get(config.settings()).getChars());
|
||||
} else {
|
||||
bindPassword = null;
|
||||
}
|
||||
|
||||
if (bindDn == null) {
|
||||
bindCredentials = new SimpleBindRequest();
|
||||
} else {
|
||||
bindCredentials = new SimpleBindRequest(bindDn, bindPassword);
|
||||
}
|
||||
|
||||
this.useConnectionPool = poolingEnabled.get(config.settings());
|
||||
if (useConnectionPool) {
|
||||
this.connectionPool = createConnectionPool(config, serverSet, timeout, logger, bindRequestSupplier, healthCheckDNSupplier);
|
||||
this.connectionPool = createConnectionPool(config, serverSet, timeout, logger, bindCredentials, healthCheckDNSupplier);
|
||||
} else {
|
||||
this.connectionPool = null;
|
||||
}
|
||||
|
@ -111,10 +140,9 @@ abstract class PoolingSessionFactory extends SessionFactory implements Releasabl
|
|||
* Creates the connection pool that will be used by the session factory and initializes the health check support
|
||||
*/
|
||||
static LDAPConnectionPool createConnectionPool(RealmConfig config, ServerSet serverSet, TimeValue timeout, Logger logger,
|
||||
Supplier<BindRequest> bindRequestSupplier,
|
||||
BindRequest bindRequest,
|
||||
Supplier<String> healthCheckDnSupplier) throws LDAPException {
|
||||
Settings settings = config.settings();
|
||||
BindRequest bindRequest = bindRequestSupplier.get();
|
||||
final int initialSize = PoolingSessionFactorySettings.POOL_INITIAL_SIZE.get(settings);
|
||||
final int size = PoolingSessionFactorySettings.POOL_SIZE.get(settings);
|
||||
LDAPConnectionPool pool = null;
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
package org.elasticsearch.test;
|
||||
|
||||
import org.bouncycastle.operator.OperatorCreationException;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.inject.Guice;
|
||||
import org.elasticsearch.common.inject.Injector;
|
||||
|
@ -14,17 +13,13 @@ import org.elasticsearch.common.settings.Setting;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.settings.SettingsFilter;
|
||||
import org.elasticsearch.common.settings.SettingsModule;
|
||||
import org.elasticsearch.xpack.core.XPackPlugin;
|
||||
import org.elasticsearch.xpack.core.XPackSettings;
|
||||
import org.elasticsearch.xpack.core.security.authc.ldap.PoolingSessionFactorySettings;
|
||||
import org.elasticsearch.xpack.security.LocalStateSecurity;
|
||||
import org.elasticsearch.xpack.security.Security;
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.security.auth.DestroyFailedException;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -40,6 +35,8 @@ public class SettingsFilterTests extends ESTestCase {
|
|||
private MockSecureSettings mockSecureSettings = new MockSecureSettings();
|
||||
|
||||
public void testFiltering() throws Exception {
|
||||
final boolean useLegacyLdapBindPassword = randomBoolean();
|
||||
|
||||
configureUnfilteredSetting("xpack.security.authc.realms.file.type", "file");
|
||||
|
||||
// ldap realm filtering
|
||||
|
@ -48,7 +45,11 @@ public class SettingsFilterTests extends ESTestCase {
|
|||
configureUnfilteredSetting("xpack.security.authc.realms.ldap1.url", "ldap://host.domain");
|
||||
configureFilteredSetting("xpack.security.authc.realms.ldap1.hostname_verification", Boolean.toString(randomBoolean()));
|
||||
configureFilteredSetting("xpack.security.authc.realms.ldap1.bind_dn", randomAlphaOfLength(5));
|
||||
configureFilteredSetting("xpack.security.authc.realms.ldap1.bind_password", randomAlphaOfLength(5));
|
||||
if (useLegacyLdapBindPassword) {
|
||||
configureFilteredSetting("xpack.security.authc.realms.ldap1.bind_password", randomAlphaOfLength(5));
|
||||
} else {
|
||||
configureSecureSetting("xpack.security.authc.realms.ldap1.secure_bind_password", randomAlphaOfLengthBetween(3, 8));
|
||||
}
|
||||
|
||||
// active directory filtering
|
||||
configureUnfilteredSetting("xpack.security.authc.realms.ad1.type", "active_directory");
|
||||
|
@ -93,7 +94,7 @@ public class SettingsFilterTests extends ESTestCase {
|
|||
|
||||
// custom settings, potentially added by a plugin
|
||||
configureFilteredSetting("foo.bar", "_secret");
|
||||
configureFilteredSetting("foo.baz", "_secret");;
|
||||
configureFilteredSetting("foo.baz", "_secret");
|
||||
configureFilteredSetting("bar.baz", "_secret");
|
||||
configureUnfilteredSetting("baz.foo", "_not_a_secret");
|
||||
configureFilteredSetting("xpack.security.hide_settings", "foo.*,bar.baz");
|
||||
|
@ -124,6 +125,10 @@ public class SettingsFilterTests extends ESTestCase {
|
|||
for (Map.Entry<String, Matcher> entry : settingsMatcherMap.entrySet()) {
|
||||
assertThat(filteredSettings.get(entry.getKey()), entry.getValue());
|
||||
}
|
||||
|
||||
if (useLegacyLdapBindPassword) {
|
||||
assertSettingDeprecationsAndWarnings(new Setting<?>[]{PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD});
|
||||
}
|
||||
}
|
||||
|
||||
private void configureUnfilteredSetting(String settingName, String value) {
|
||||
|
|
|
@ -12,9 +12,9 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.test.SecuritySettingsSource;
|
||||
import org.elasticsearch.xpack.core.XPackSettings;
|
||||
import org.elasticsearch.xpack.core.security.SecurityExtension;
|
||||
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
|
||||
import org.elasticsearch.xpack.core.security.authc.support.Hasher;
|
||||
import org.elasticsearch.xpack.core.security.SecurityExtension;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -138,9 +138,12 @@ public class RealmSettingsTests extends ESTestCase {
|
|||
private Settings.Builder ldapSettings(boolean userSearch, boolean groupSearch) {
|
||||
final Settings.Builder builder = commonLdapSettings("ldap", true)
|
||||
.put("bind_dn", "elasticsearch")
|
||||
.put("bind_password", "t0p_s3cr3t")
|
||||
.put("follow_referrals", randomBoolean());
|
||||
|
||||
SecuritySettingsSource.addSecureSettings(builder, secureSettings -> {
|
||||
secureSettings.setString("bind_password", "t0p_s3cr3t");
|
||||
});
|
||||
|
||||
if (userSearch) {
|
||||
builder.put("user_search.base_dn", "o=people, dc=example, dc=com");
|
||||
builder.put("user_search.scope", "sub_tree");
|
||||
|
|
|
@ -14,7 +14,9 @@ import com.unboundid.ldap.sdk.schema.Schema;
|
|||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.support.PlainActionFuture;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.settings.MockSecureSettings;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.env.TestEnvironment;
|
||||
|
@ -63,12 +65,12 @@ import static org.mockito.Mockito.verify;
|
|||
|
||||
/**
|
||||
* Active Directory Realm tests that use the UnboundID In Memory Directory Server
|
||||
*
|
||||
* <p>
|
||||
* AD is not LDAPv3 compliant so a workaround is needed
|
||||
* AD realm binds with userPrincipalName but this is not a valid DN, so we have to add a second userPrincipalName to the
|
||||
* users in the ldif in the form of CN=user@domain.com or a set the sAMAccountName to CN=user when testing authentication
|
||||
* with the sAMAccountName field.
|
||||
*
|
||||
* <p>
|
||||
* The username used to authenticate then has to be in the form of CN=user. Finally the username needs to be added as an
|
||||
* additional bind DN with a password in the test setup since it really is not a DN in the ldif file
|
||||
*/
|
||||
|
@ -248,11 +250,18 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
|||
}
|
||||
|
||||
private void doUnauthenticatedLookup(boolean pooled) throws Exception {
|
||||
Settings settings = settings(Settings.builder()
|
||||
final Settings.Builder builder = Settings.builder()
|
||||
.put(ActiveDirectorySessionFactorySettings.POOL_ENABLED.getKey(), pooled)
|
||||
.put(PoolingSessionFactorySettings.BIND_DN.getKey(), "CN=ironman@ad.test.elasticsearch.com")
|
||||
.put(PoolingSessionFactorySettings.BIND_PASSWORD.getKey(), PASSWORD)
|
||||
.build());
|
||||
.put(PoolingSessionFactorySettings.BIND_DN.getKey(), "CN=ironman@ad.test.elasticsearch.com");
|
||||
final boolean useLegacyBindPassword = randomBoolean();
|
||||
if (useLegacyBindPassword) {
|
||||
builder.put(PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD.getKey(), PASSWORD);
|
||||
} else {
|
||||
final MockSecureSettings secureSettings = new MockSecureSettings();
|
||||
secureSettings.setString(PoolingSessionFactorySettings.SECURE_BIND_PASSWORD.getKey(), PASSWORD);
|
||||
builder.setSecureSettings(secureSettings);
|
||||
}
|
||||
Settings settings = settings(builder.build());
|
||||
RealmConfig config = new RealmConfig("testUnauthenticatedLookupWithConnectionPool", settings, globalSettings,
|
||||
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
|
||||
try (ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool)) {
|
||||
|
|
|
@ -8,6 +8,8 @@ package org.elasticsearch.xpack.security.authc.ldap;
|
|||
import com.unboundid.ldap.sdk.LDAPURL;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.support.PlainActionFuture;
|
||||
import org.elasticsearch.common.settings.MockSecureSettings;
|
||||
import org.elasticsearch.common.settings.SecureSettings;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
|
@ -229,7 +231,7 @@ public class LdapRealmTests extends LdapTestCase {
|
|||
.putList(URLS_SETTING, ldapUrls())
|
||||
.put("user_search.base_dn", "")
|
||||
.put("bind_dn", "cn=Thomas Masterman Hardy,ou=people,o=sevenSeas")
|
||||
.put("bind_password", PASSWORD)
|
||||
.setSecureSettings(secureSettings("secure_bind_password", PASSWORD))
|
||||
.put("group_search.base_dn", groupSearchBase)
|
||||
.put("group_search.scope", LdapSearchScope.SUB_TREE)
|
||||
.put("ssl.verification_mode", VerificationMode.CERTIFICATE)
|
||||
|
@ -243,6 +245,12 @@ public class LdapRealmTests extends LdapTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
private MockSecureSettings secureSettings(String key, String value) {
|
||||
final MockSecureSettings secureSettings = new MockSecureSettings();
|
||||
secureSettings.setString(key, value);
|
||||
return secureSettings;
|
||||
}
|
||||
|
||||
public void testLdapRealmThrowsExceptionForUserTemplateAndSearchSettings() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.putList(URLS_SETTING, ldapUrls())
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
package org.elasticsearch.xpack.security.authc.ldap;
|
||||
|
||||
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
|
||||
import com.unboundid.ldap.sdk.BindRequest;
|
||||
import com.unboundid.ldap.sdk.GetEntryLDAPConnectionPoolHealthCheck;
|
||||
import com.unboundid.ldap.sdk.LDAPConnectionPool;
|
||||
import com.unboundid.ldap.sdk.LDAPConnectionPoolHealthCheck;
|
||||
|
@ -39,6 +38,8 @@ import org.junit.After;
|
|||
import org.junit.Before;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
@ -87,8 +88,8 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, "", LdapSearchScope.SUB_TREE))
|
||||
.put("user_search.base_dn", "")
|
||||
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
|
||||
.put("bind_password", "pass")
|
||||
.put("user_search.pool.enabled", randomBoolean());
|
||||
final boolean useLegacyBindPassword = configureBindPassword(builder);
|
||||
if (useAttribute) {
|
||||
builder.put("user_search.attribute", "cn");
|
||||
} else {
|
||||
|
@ -105,12 +106,9 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
sessionFactory.close();
|
||||
}
|
||||
|
||||
if (useAttribute) {
|
||||
assertSettingDeprecationsAndWarnings(new Setting[] { LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE });
|
||||
}
|
||||
assertDeprecationWarnings(useAttribute, useLegacyBindPassword);
|
||||
}
|
||||
|
||||
|
||||
public void testUserSearchSubTree() throws Exception {
|
||||
String groupSearchBase = "o=sevenSeas";
|
||||
String userSearchBase = "o=sevenSeas";
|
||||
|
@ -120,8 +118,8 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
|
||||
.put("user_search.base_dn", userSearchBase)
|
||||
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
|
||||
.put("bind_password", "pass")
|
||||
.put("user_search.pool.enabled", randomBoolean());
|
||||
final boolean useLegacyBindPassword = configureBindPassword(builder);
|
||||
if (useAttribute) {
|
||||
builder.put("user_search.attribute", "cn");
|
||||
} else {
|
||||
|
@ -134,19 +132,18 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
|
||||
String user = "William Bush";
|
||||
SecureString userPass = new SecureString("pass");
|
||||
final SimpleBindRequest bindDNBindRequest = LdapUserSearchSessionFactory.bindRequest(config.settings());
|
||||
|
||||
try {
|
||||
// auth
|
||||
try (LdapSession ldap = session(sessionFactory, user, userPass)) {
|
||||
assertConnectionValid(ldap.getConnection(), bindDNBindRequest);
|
||||
assertConnectionValid(ldap.getConnection(), sessionFactory.bindCredentials);
|
||||
String dn = ldap.userDn();
|
||||
assertThat(dn, containsString(user));
|
||||
}
|
||||
|
||||
//lookup
|
||||
try (LdapSession ldap = unauthenticatedSession(sessionFactory, user)) {
|
||||
assertConnectionValid(ldap.getConnection(), bindDNBindRequest);
|
||||
assertConnectionValid(ldap.getConnection(), sessionFactory.bindCredentials);
|
||||
String dn = ldap.userDn();
|
||||
assertThat(dn, containsString(user));
|
||||
}
|
||||
|
@ -154,9 +151,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
sessionFactory.close();
|
||||
}
|
||||
|
||||
if (useAttribute) {
|
||||
assertSettingDeprecationsAndWarnings(new Setting[] { LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE });
|
||||
}
|
||||
assertDeprecationWarnings(useAttribute, useLegacyBindPassword);
|
||||
}
|
||||
|
||||
public void testUserSearchBaseScopeFailsWithWrongBaseDN() throws Exception {
|
||||
|
@ -168,9 +163,9 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
|
||||
.put("user_search.base_dn", userSearchBase)
|
||||
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
|
||||
.put("bind_password", "pass")
|
||||
.put("user_search.scope", LdapSearchScope.BASE)
|
||||
.put("user_search.pool.enabled", randomBoolean());
|
||||
final boolean useLegacyBindPassword = configureBindPassword(builder);
|
||||
if (useAttribute) {
|
||||
builder.put("user_search.attribute", "cn");
|
||||
} else {
|
||||
|
@ -191,9 +186,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
sessionFactory.close();
|
||||
}
|
||||
|
||||
if (useAttribute) {
|
||||
assertSettingDeprecationsAndWarnings(new Setting[] { LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE });
|
||||
}
|
||||
assertDeprecationWarnings(useAttribute, useLegacyBindPassword);
|
||||
}
|
||||
|
||||
public void testUserSearchBaseScopePassesWithCorrectBaseDN() throws Exception {
|
||||
|
@ -204,9 +197,9 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
|
||||
.put("user_search.base_dn", userSearchBase)
|
||||
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
|
||||
.put("bind_password", "pass")
|
||||
.put("user_search.scope", LdapSearchScope.BASE)
|
||||
.put("user_search.pool.enabled", randomBoolean());
|
||||
final boolean useLegacyBindPassword = configureBindPassword(builder);
|
||||
final boolean useAttribute = randomBoolean();
|
||||
if (useAttribute) {
|
||||
builder.put("user_search.attribute", "cn");
|
||||
|
@ -220,19 +213,18 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
|
||||
String user = "William Bush";
|
||||
SecureString userPass = new SecureString("pass");
|
||||
final SimpleBindRequest bindDNBindRequest = LdapUserSearchSessionFactory.bindRequest(config.settings());
|
||||
|
||||
try {
|
||||
// auth
|
||||
try (LdapSession ldap = session(sessionFactory, user, userPass)) {
|
||||
assertConnectionValid(ldap.getConnection(), bindDNBindRequest);
|
||||
assertConnectionValid(ldap.getConnection(), sessionFactory.bindCredentials);
|
||||
String dn = ldap.userDn();
|
||||
assertThat(dn, containsString(user));
|
||||
}
|
||||
|
||||
//lookup
|
||||
try (LdapSession ldap = unauthenticatedSession(sessionFactory, user)) {
|
||||
assertConnectionValid(ldap.getConnection(), bindDNBindRequest);
|
||||
assertConnectionValid(ldap.getConnection(), sessionFactory.bindCredentials);
|
||||
String dn = ldap.userDn();
|
||||
assertThat(dn, containsString(user));
|
||||
}
|
||||
|
@ -240,9 +232,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
sessionFactory.close();
|
||||
}
|
||||
|
||||
if (useAttribute) {
|
||||
assertSettingDeprecationsAndWarnings(new Setting[] { LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE });
|
||||
}
|
||||
assertDeprecationWarnings(useAttribute, useLegacyBindPassword);
|
||||
}
|
||||
|
||||
public void testUserSearchOneLevelScopeFailsWithWrongBaseDN() throws Exception {
|
||||
|
@ -253,9 +243,9 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
|
||||
.put("user_search.base_dn", userSearchBase)
|
||||
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
|
||||
.put("bind_password", "pass")
|
||||
.put("user_search.scope", LdapSearchScope.ONE_LEVEL)
|
||||
.put("user_search.pool.enabled", randomBoolean());
|
||||
final boolean useLegacyBindPassword = configureBindPassword(builder);
|
||||
final boolean useAttribute = randomBoolean();
|
||||
if (useAttribute) {
|
||||
builder.put("user_search.attribute", "cn");
|
||||
|
@ -277,9 +267,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
sessionFactory.close();
|
||||
}
|
||||
|
||||
if (useAttribute) {
|
||||
assertSettingDeprecationsAndWarnings(new Setting[] { LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE });
|
||||
}
|
||||
assertDeprecationWarnings(useAttribute, useLegacyBindPassword);
|
||||
}
|
||||
|
||||
public void testUserSearchOneLevelScopePassesWithCorrectBaseDN() throws Exception {
|
||||
|
@ -290,9 +278,9 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
|
||||
.put("user_search.base_dn", userSearchBase)
|
||||
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
|
||||
.put("bind_password", "pass")
|
||||
.put("user_search.scope", LdapSearchScope.ONE_LEVEL)
|
||||
.put("user_search.pool.enabled", randomBoolean());
|
||||
final boolean useLegacyBindPassword = configureBindPassword(builder);
|
||||
final boolean useAttribute = randomBoolean();
|
||||
if (useAttribute) {
|
||||
builder.put("user_search.attribute", "cn");
|
||||
|
@ -306,19 +294,18 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
|
||||
String user = "William Bush";
|
||||
SecureString userPass = new SecureString("pass");
|
||||
final SimpleBindRequest bindDNBindRequest = LdapUserSearchSessionFactory.bindRequest(config.settings());
|
||||
|
||||
try {
|
||||
//auth
|
||||
try (LdapSession ldap = session(sessionFactory, user, userPass)) {
|
||||
assertConnectionValid(ldap.getConnection(), bindDNBindRequest);
|
||||
assertConnectionValid(ldap.getConnection(), sessionFactory.bindCredentials);
|
||||
String dn = ldap.userDn();
|
||||
assertThat(dn, containsString(user));
|
||||
}
|
||||
|
||||
//lookup
|
||||
try (LdapSession ldap = unauthenticatedSession(sessionFactory, user)) {
|
||||
assertConnectionValid(ldap.getConnection(), bindDNBindRequest);
|
||||
assertConnectionValid(ldap.getConnection(), sessionFactory.bindCredentials);
|
||||
String dn = ldap.userDn();
|
||||
assertThat(dn, containsString(user));
|
||||
}
|
||||
|
@ -326,9 +313,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
sessionFactory.close();
|
||||
}
|
||||
|
||||
if (useAttribute) {
|
||||
assertSettingDeprecationsAndWarnings(new Setting[] { LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE });
|
||||
}
|
||||
assertDeprecationWarnings(useAttribute, useLegacyBindPassword);
|
||||
}
|
||||
|
||||
public void testUserSearchWithBadAttributeFails() throws Exception {
|
||||
|
@ -339,8 +324,8 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
|
||||
.put("user_search.base_dn", userSearchBase)
|
||||
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
|
||||
.put("bind_password", "pass")
|
||||
.put("user_search.pool.enabled", randomBoolean());
|
||||
final boolean useLegacyBindPassword = configureBindPassword(builder);
|
||||
final boolean useAttribute = randomBoolean();
|
||||
if (useAttribute) {
|
||||
builder.put("user_search.attribute", "uid1");
|
||||
|
@ -362,61 +347,62 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
sessionFactory.close();
|
||||
}
|
||||
|
||||
if (useAttribute) {
|
||||
assertSettingDeprecationsAndWarnings(new Setting[] { LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE });
|
||||
}
|
||||
assertDeprecationWarnings(useAttribute, useLegacyBindPassword);
|
||||
}
|
||||
|
||||
public void testUserSearchWithoutAttributePasses() throws Exception {
|
||||
String groupSearchBase = "o=sevenSeas";
|
||||
String userSearchBase = "o=sevenSeas";
|
||||
|
||||
RealmConfig config = new RealmConfig("ldap_realm", Settings.builder()
|
||||
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
|
||||
.put("user_search.base_dn", userSearchBase)
|
||||
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
|
||||
.put("bind_password", "pass")
|
||||
.put("user_search.pool.enabled", randomBoolean())
|
||||
.build(), globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
|
||||
final Settings.Builder realmSettings = Settings.builder()
|
||||
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
|
||||
.put("user_search.base_dn", userSearchBase)
|
||||
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
|
||||
.put("user_search.pool.enabled", randomBoolean());
|
||||
final boolean useLegacyBindPassword = configureBindPassword(realmSettings);
|
||||
RealmConfig config = new RealmConfig("ldap_realm", realmSettings.build(), globalSettings,
|
||||
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
|
||||
|
||||
LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
|
||||
|
||||
String user = "wbush";
|
||||
SecureString userPass = new SecureString("pass");
|
||||
final SimpleBindRequest bindDNBindRequest = LdapUserSearchSessionFactory.bindRequest(config.settings());
|
||||
|
||||
try {
|
||||
//auth
|
||||
try (LdapSession ldap = session(sessionFactory, user, userPass)) {
|
||||
assertConnectionValid(ldap.getConnection(), bindDNBindRequest);
|
||||
assertConnectionValid(ldap.getConnection(), sessionFactory.bindCredentials);
|
||||
String dn = ldap.userDn();
|
||||
assertThat(dn, containsString("William Bush"));
|
||||
}
|
||||
|
||||
//lookup
|
||||
try (LdapSession ldap = unauthenticatedSession(sessionFactory, user)) {
|
||||
assertConnectionValid(ldap.getConnection(), bindDNBindRequest);
|
||||
assertConnectionValid(ldap.getConnection(), sessionFactory.bindCredentials);
|
||||
String dn = ldap.userDn();
|
||||
assertThat(dn, containsString("William Bush"));
|
||||
}
|
||||
} finally {
|
||||
sessionFactory.close();
|
||||
}
|
||||
|
||||
assertDeprecationWarnings(false, useLegacyBindPassword);
|
||||
}
|
||||
|
||||
public void testConnectionPoolDefaultSettings() throws Exception {
|
||||
String groupSearchBase = "o=sevenSeas";
|
||||
String userSearchBase = "o=sevenSeas";
|
||||
RealmConfig config = new RealmConfig("ldap_realm", Settings.builder()
|
||||
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
|
||||
.put("user_search.base_dn", userSearchBase)
|
||||
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
|
||||
.put("bind_password", "pass")
|
||||
.build(), globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
|
||||
final Settings.Builder realmSettings = Settings.builder()
|
||||
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
|
||||
.put("user_search.base_dn", userSearchBase)
|
||||
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas");
|
||||
configureBindPassword(realmSettings);
|
||||
RealmConfig config = new RealmConfig("ldap_realm", realmSettings.build(), globalSettings,
|
||||
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
|
||||
|
||||
LDAPConnectionPool connectionPool = LdapUserSearchSessionFactory.createConnectionPool(config, new SingleServerSet("localhost",
|
||||
randomFrom(ldapServers).getListenPort()), TimeValue.timeValueSeconds(5), NoOpLogger.INSTANCE,
|
||||
() -> new SimpleBindRequest("cn=Horatio Hornblower,ou=people,o=sevenSeas", "pass"),
|
||||
randomFrom(ldapServers).getListenPort()), TimeValue.timeValueSeconds(5), NoOpLogger.INSTANCE,
|
||||
new SimpleBindRequest("cn=Horatio Hornblower,ou=people,o=sevenSeas", "pass"),
|
||||
() -> "cn=Horatio Hornblower,ou=people,o=sevenSeas");
|
||||
try {
|
||||
assertThat(connectionPool.getCurrentAvailableConnections(),
|
||||
|
@ -435,19 +421,20 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
public void testConnectionPoolSettings() throws Exception {
|
||||
String groupSearchBase = "o=sevenSeas";
|
||||
String userSearchBase = "o=sevenSeas";
|
||||
RealmConfig config = new RealmConfig("ldap_realm", Settings.builder()
|
||||
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
|
||||
.put("user_search.base_dn", userSearchBase)
|
||||
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
|
||||
.put("bind_password", "pass")
|
||||
.put("user_search.pool.initial_size", 10)
|
||||
.put("user_search.pool.size", 12)
|
||||
.put("user_search.pool.health_check.enabled", false)
|
||||
.build(), globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
|
||||
final Settings.Builder realmSettings = Settings.builder()
|
||||
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
|
||||
.put("user_search.base_dn", userSearchBase)
|
||||
.put("bind_dn", "cn=Horatio Hornblower,ou=people,o=sevenSeas")
|
||||
.put("user_search.pool.initial_size", 10)
|
||||
.put("user_search.pool.size", 12)
|
||||
.put("user_search.pool.health_check.enabled", false);
|
||||
configureBindPassword(realmSettings);
|
||||
RealmConfig config = new RealmConfig("ldap_realm", realmSettings.build(), globalSettings,
|
||||
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
|
||||
|
||||
LDAPConnectionPool connectionPool = LdapUserSearchSessionFactory.createConnectionPool(config, new SingleServerSet("localhost",
|
||||
randomFrom(ldapServers).getListenPort()), TimeValue.timeValueSeconds(5), NoOpLogger.INSTANCE,
|
||||
() -> new SimpleBindRequest("cn=Horatio Hornblower,ou=people,o=sevenSeas", "pass"),
|
||||
randomFrom(ldapServers).getListenPort()), TimeValue.timeValueSeconds(5), NoOpLogger.INSTANCE,
|
||||
new SimpleBindRequest("cn=Horatio Hornblower,ou=people,o=sevenSeas", "pass"),
|
||||
() -> "cn=Horatio Hornblower,ou=people,o=sevenSeas");
|
||||
try {
|
||||
assertThat(connectionPool.getCurrentAvailableConnections(), is(10));
|
||||
|
@ -463,10 +450,10 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
String groupSearchBase = "o=sevenSeas";
|
||||
String userSearchBase = "o=sevenSeas";
|
||||
RealmConfig config = new RealmConfig("ldap_realm", Settings.builder()
|
||||
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
|
||||
.put("user_search.base_dn", userSearchBase)
|
||||
.put("bind_password", "pass")
|
||||
.build(), globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
|
||||
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
|
||||
.put("user_search.base_dn", userSearchBase)
|
||||
.put("bind_password", "pass")
|
||||
.build(), globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
|
||||
|
||||
LdapUserSearchSessionFactory searchSessionFactory = null;
|
||||
try {
|
||||
|
@ -476,17 +463,19 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
searchSessionFactory.close();
|
||||
}
|
||||
}
|
||||
|
||||
assertDeprecationWarnings(false, true);
|
||||
}
|
||||
|
||||
public void testThatEmptyBindDNAndDisabledPoolingDoesNotThrow() throws Exception {
|
||||
String groupSearchBase = "o=sevenSeas";
|
||||
String userSearchBase = "o=sevenSeas";
|
||||
RealmConfig config = new RealmConfig("ldap_realm", Settings.builder()
|
||||
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
|
||||
.put("user_search.base_dn", userSearchBase)
|
||||
.put("user_search.pool.enabled", false)
|
||||
.put("bind_password", "pass")
|
||||
.build(), globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
|
||||
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
|
||||
.put("user_search.base_dn", userSearchBase)
|
||||
.put("user_search.pool.enabled", false)
|
||||
.put("bind_password", "pass")
|
||||
.build(), globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
|
||||
|
||||
LdapUserSearchSessionFactory searchSessionFactory = null;
|
||||
try {
|
||||
|
@ -499,22 +488,41 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
searchSessionFactory.close();
|
||||
}
|
||||
}
|
||||
|
||||
assertDeprecationWarnings(false, true);
|
||||
}
|
||||
|
||||
public void testEmptyBindDNReturnsAnonymousBindRequest() {
|
||||
SimpleBindRequest request = LdapUserSearchSessionFactory.bindRequest(Settings.builder().put("bind_password", "password").build());
|
||||
assertThat(request, is(notNullValue()));
|
||||
assertThat(request.getBindDN(), isEmptyString());
|
||||
public void testEmptyBindDNReturnsAnonymousBindRequest() throws LDAPException {
|
||||
String groupSearchBase = "o=sevenSeas";
|
||||
String userSearchBase = "o=sevenSeas";
|
||||
final Settings.Builder realmSettings = Settings.builder()
|
||||
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
|
||||
.put("user_search.base_dn", userSearchBase);
|
||||
final boolean useLegacyBindPassword = configureBindPassword(realmSettings);
|
||||
RealmConfig config = new RealmConfig("ldap_realm", realmSettings.build(), globalSettings,
|
||||
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
|
||||
try (LdapUserSearchSessionFactory searchSessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool)) {
|
||||
assertThat(searchSessionFactory.bindCredentials, notNullValue());
|
||||
assertThat(searchSessionFactory.bindCredentials.getBindDN(), isEmptyString());
|
||||
}
|
||||
assertDeprecationWarnings(false, useLegacyBindPassword);
|
||||
}
|
||||
|
||||
public void testThatBindRequestReturnsSimpleBindRequest() {
|
||||
BindRequest request = LdapUserSearchSessionFactory.bindRequest(Settings.builder()
|
||||
.put("bind_password", "password")
|
||||
public void testThatBindRequestReturnsSimpleBindRequest() throws LDAPException {
|
||||
String groupSearchBase = "o=sevenSeas";
|
||||
String userSearchBase = "o=sevenSeas";
|
||||
final Settings.Builder realmSettings = Settings.builder()
|
||||
.put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, groupSearchBase, LdapSearchScope.SUB_TREE))
|
||||
.put("bind_dn", "cn=ironman")
|
||||
.build());
|
||||
assertEquals(request.getClass(), SimpleBindRequest.class);
|
||||
SimpleBindRequest simpleBindRequest = (SimpleBindRequest) request;
|
||||
assertThat(simpleBindRequest.getBindDN(), is("cn=ironman"));
|
||||
.put("user_search.base_dn", userSearchBase);
|
||||
final boolean useLegacyBindPassword = configureBindPassword(realmSettings);
|
||||
RealmConfig config = new RealmConfig("ldap_realm", realmSettings.build(), globalSettings,
|
||||
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
|
||||
try (LdapUserSearchSessionFactory searchSessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool)) {
|
||||
assertThat(searchSessionFactory.bindCredentials, notNullValue());
|
||||
assertThat(searchSessionFactory.bindCredentials.getBindDN(), is("cn=ironman"));
|
||||
}
|
||||
assertDeprecationWarnings(false, useLegacyBindPassword);
|
||||
}
|
||||
|
||||
public void testThatConnectErrorIsNotThrownOnConstruction() throws Exception {
|
||||
|
@ -526,20 +534,20 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
String ldapUrl = new LDAPURL("ldap", "localhost", inMemoryDirectoryServer.getListenPort(), null, null, null, null).toString();
|
||||
inMemoryDirectoryServer.shutDown(true);
|
||||
|
||||
Settings ldapSettings = Settings.builder()
|
||||
.put(LdapTestCase.buildLdapSettings(new String[] { ldapUrl }, Strings.EMPTY_ARRAY,
|
||||
final Settings.Builder ldapSettingsBuilder = Settings.builder()
|
||||
.put(LdapTestCase.buildLdapSettings(new String[]{ldapUrl}, Strings.EMPTY_ARRAY,
|
||||
groupSearchBase, LdapSearchScope.SUB_TREE))
|
||||
.put("user_search.base_dn", userSearchBase)
|
||||
.put("bind_dn", "ironman@ad.test.elasticsearch.com")
|
||||
.put("bind_password", "password")
|
||||
.put("user_search.attribute", "cn")
|
||||
.put("timeout.tcp_connect", "500ms")
|
||||
.put("type", "ldap")
|
||||
.put("user_search.pool.health_check.enabled", false)
|
||||
.put("user_search.pool.enabled", randomBoolean())
|
||||
.build();
|
||||
.put("user_search.pool.enabled", randomBoolean());
|
||||
|
||||
RealmConfig config = new RealmConfig("ldap_realm", ldapSettings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
|
||||
final boolean useLegacyBindPassword = configureBindPassword(ldapSettingsBuilder);
|
||||
RealmConfig config = new RealmConfig("ldap_realm", ldapSettingsBuilder.build(), globalSettings,
|
||||
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
|
||||
LdapUserSearchSessionFactory searchSessionFactory = null;
|
||||
try {
|
||||
searchSessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
|
||||
|
@ -549,7 +557,30 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
assertSettingDeprecationsAndWarnings(new Setting[] { LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE });
|
||||
assertDeprecationWarnings(true, useLegacyBindPassword);
|
||||
}
|
||||
|
||||
private void assertDeprecationWarnings(boolean useAttribute, boolean legacyBindPassword) {
|
||||
List<Setting<?>> deprecatedSettings = new ArrayList<>();
|
||||
if (useAttribute) {
|
||||
deprecatedSettings.add(LdapUserSearchSessionFactorySettings.SEARCH_ATTRIBUTE);
|
||||
}
|
||||
if (legacyBindPassword) {
|
||||
deprecatedSettings.add(PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD);
|
||||
}
|
||||
if (deprecatedSettings.size() > 0) {
|
||||
assertSettingDeprecationsAndWarnings(deprecatedSettings.toArray(new Setting<?>[deprecatedSettings.size()]));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean configureBindPassword(Settings.Builder builder) {
|
||||
final boolean useLegacyBindPassword = randomBoolean();
|
||||
if (useLegacyBindPassword) {
|
||||
builder.put("bind_password", "pass");
|
||||
} else {
|
||||
builder.setSecureSettings(newSecureSettings("secure_bind_password", "pass"));
|
||||
}
|
||||
return useLegacyBindPassword;
|
||||
}
|
||||
|
||||
static LdapUserSearchSessionFactory getLdapUserSearchSessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool)
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.elasticsearch.action.support.PlainActionFuture;
|
|||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.settings.MockSecureSettings;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.env.TestEnvironment;
|
||||
|
@ -17,6 +18,7 @@ import org.elasticsearch.test.OpenLdapTests;
|
|||
import org.elasticsearch.threadpool.TestThreadPool;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.core.security.authc.ldap.PoolingSessionFactorySettings;
|
||||
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope;
|
||||
import org.elasticsearch.xpack.core.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession;
|
||||
|
@ -41,6 +43,7 @@ public class OpenLdapUserSearchSessionFactoryTests extends ESTestCase {
|
|||
|
||||
private Settings globalSettings;
|
||||
private ThreadPool threadPool;
|
||||
private MockSecureSettings globalSecureSettings;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
|
@ -50,10 +53,11 @@ public class OpenLdapUserSearchSessionFactoryTests extends ESTestCase {
|
|||
* If we re-use a SSLContext, previously connected sessions can get re-established which breaks hostname
|
||||
* verification tests since a re-established connection does not perform hostname verification.
|
||||
*/
|
||||
globalSecureSettings = newSecureSettings("xpack.ssl.truststore.secure_password", "changeit");
|
||||
globalSettings = Settings.builder()
|
||||
.put("path.home", createTempDir())
|
||||
.put("xpack.ssl.truststore.path", keystore)
|
||||
.setSecureSettings(newSecureSettings("xpack.ssl.truststore.secure_password", "changeit"))
|
||||
.setSecureSettings(globalSecureSettings)
|
||||
.build();
|
||||
threadPool = new TestThreadPool("LdapUserSearchSessionFactoryTests");
|
||||
}
|
||||
|
@ -63,26 +67,40 @@ public class OpenLdapUserSearchSessionFactoryTests extends ESTestCase {
|
|||
terminate(threadPool);
|
||||
}
|
||||
|
||||
public void testUserSearchwithBindUserOpenLDAP() throws Exception {
|
||||
public void testUserSearchWithBindUserOpenLDAP() throws Exception {
|
||||
final boolean useSecureBindPassword = randomBoolean();
|
||||
String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
|
||||
String userSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
|
||||
RealmConfig config = new RealmConfig("oldap-test", Settings.builder()
|
||||
.put(LdapTestCase.buildLdapSettings(new String[] { OpenLdapTests.OPEN_LDAP_DNS_URL }, Strings.EMPTY_ARRAY, groupSearchBase,
|
||||
final Settings.Builder realmSettings = Settings.builder()
|
||||
.put(LdapTestCase.buildLdapSettings(new String[]{OpenLdapTests.OPEN_LDAP_DNS_URL}, Strings.EMPTY_ARRAY, groupSearchBase,
|
||||
LdapSearchScope.ONE_LEVEL))
|
||||
.put("user_search.base_dn", userSearchBase)
|
||||
.put("group_search.user_attribute", "uid")
|
||||
.put("bind_dn", "uid=blackwidow,ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com")
|
||||
.put("bind_password", OpenLdapTests.PASSWORD)
|
||||
.put("user_search.pool.enabled", randomBoolean())
|
||||
.build(), globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
|
||||
.put("user_search.pool.enabled", randomBoolean());
|
||||
if (useSecureBindPassword) {
|
||||
final MockSecureSettings secureSettings = new MockSecureSettings();
|
||||
secureSettings.setString("secure_bind_password", OpenLdapTests.PASSWORD);
|
||||
realmSettings.setSecureSettings(secureSettings);
|
||||
} else {
|
||||
realmSettings.put("bind_password", OpenLdapTests.PASSWORD);
|
||||
}
|
||||
RealmConfig config = new RealmConfig("oldap-test", realmSettings.build(), globalSettings,
|
||||
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
|
||||
Settings.Builder builder = Settings.builder()
|
||||
.put(globalSettings);
|
||||
builder.put(Settings.builder().put(config.settings()).normalizePrefix("xpack.security.authc.realms.ldap.").build());
|
||||
.put(globalSettings, false);
|
||||
builder.put(Settings.builder().put(config.settings(), false).normalizePrefix("xpack.security.authc.realms.ldap.").build());
|
||||
final MockSecureSettings secureSettings = new MockSecureSettings();
|
||||
secureSettings.merge(globalSecureSettings);
|
||||
if (useSecureBindPassword) {
|
||||
secureSettings.setString("xpack.security.authc.realms.ldap.secure_bind_password", OpenLdapTests.PASSWORD);
|
||||
}
|
||||
builder.setSecureSettings(secureSettings);
|
||||
Settings settings = builder.build();
|
||||
SSLService sslService = new SSLService(settings, TestEnvironment.newEnvironment(settings));
|
||||
|
||||
|
||||
String[] users = new String[] { "cap", "hawkeye", "hulk", "ironman", "thor" };
|
||||
String[] users = new String[]{"cap", "hawkeye", "hulk", "ironman", "thor"};
|
||||
try (LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService, threadPool)) {
|
||||
for (String user : users) {
|
||||
//auth
|
||||
|
@ -100,6 +118,10 @@ public class OpenLdapUserSearchSessionFactoryTests extends ESTestCase {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (useSecureBindPassword == false) {
|
||||
assertSettingDeprecationsAndWarnings(new Setting<?>[]{PoolingSessionFactorySettings.LEGACY_BIND_PASSWORD});
|
||||
}
|
||||
}
|
||||
|
||||
private MockSecureSettings newSecureSettings(String key, String value) {
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.elasticsearch.action.ActionFuture;
|
|||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.collect.MapBuilder;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.test.SecuritySettingsSource;
|
||||
import org.elasticsearch.xpack.core.security.action.user.AuthenticateAction;
|
||||
import org.elasticsearch.xpack.core.security.action.user.AuthenticateRequest;
|
||||
import org.elasticsearch.xpack.core.security.action.user.AuthenticateResponse;
|
||||
|
@ -28,19 +29,30 @@ import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswo
|
|||
*/
|
||||
public class ActiveDirectoryRunAsIT extends AbstractAdLdapRealmTestCase {
|
||||
|
||||
private static boolean useLegacyBindPassword;
|
||||
|
||||
@BeforeClass
|
||||
public static void selectRealmConfig() {
|
||||
realmConfig = RealmConfig.AD;
|
||||
useLegacyBindPassword = randomBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Settings nodeSettings(int nodeOrdinal) {
|
||||
useLegacyBindPassword = randomBoolean();
|
||||
final Settings.Builder builder = Settings.builder().put(super.nodeSettings(nodeOrdinal));
|
||||
switch (realmConfig) {
|
||||
case AD:
|
||||
builder.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".bind_dn", "ironman@ad.test.elasticsearch.com")
|
||||
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".bind_password", ActiveDirectorySessionFactoryTests.PASSWORD)
|
||||
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".user_search.pool.enabled", false);
|
||||
if (useLegacyBindPassword) {
|
||||
builder.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".bind_password", ActiveDirectorySessionFactoryTests.PASSWORD);
|
||||
} else {
|
||||
SecuritySettingsSource.addSecureSettings(builder, secureSettings -> {
|
||||
secureSettings.setString(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".secure_bind_password",
|
||||
ActiveDirectorySessionFactoryTests.PASSWORD);
|
||||
});
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown realm config " + realmConfig);
|
||||
|
|
Loading…
Reference in New Issue