From 39263d83d2c59aac57e50256a5379cd35fe9818a Mon Sep 17 00:00:00 2001 From: Jay Modi Date: Fri, 30 Dec 2016 10:04:56 -0500 Subject: [PATCH] ldap and ad realms should obey the verification_mode setting (elastic/elasticsearch#4486) When migrating realms to use the new settings for SSL, the removal of the hostname_verification setting was missed in addition to actually using the ssl.verification_mode setting. This change deprecates the hostname_verification and enables the use of the ssl.verification_mode setting. Original commit: elastic/x-pack-elasticsearch@ea24e83fd375378fac958fbf04494a87583a2a4b --- .../ldap/ActiveDirectorySessionFactory.java | 15 ++++--- .../authc/ldap/support/SessionFactory.java | 40 +++++++++++++++---- .../AbstractActiveDirectoryIntegTests.java | 20 ++++++++-- .../authc/ldap/ActiveDirectoryRealmTests.java | 39 ++++++++++++------ .../ActiveDirectorySessionFactoryTests.java | 18 +++++++-- .../authc/ldap/GroupsResolverTestCase.java | 12 +++++- .../security/authc/ldap/LdapRealmTests.java | 34 +++++++++------- .../authc/ldap/LdapSessionFactoryTests.java | 18 +++++---- .../LdapUserSearchSessionFactoryTests.java | 35 +++++++++++----- .../security/authc/ldap/OpenLdapTests.java | 16 ++++++-- .../authc/ldap/support/LdapTestCase.java | 15 ++++--- .../SessionFactoryLoadBalancingTests.java | 3 +- .../ldap/support/SessionFactoryTests.java | 39 ++++++++++++++++-- 13 files changed, 226 insertions(+), 78 deletions(-) diff --git a/elasticsearch/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactory.java b/elasticsearch/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactory.java index 62617f73a08..8e49363bf56 100644 --- a/elasticsearch/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactory.java +++ b/elasticsearch/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactory.java @@ -69,7 +69,7 @@ class ActiveDirectorySessionFactory extends SessionFactory { String domainDN = buildDnFromDomain(domainName); GroupsResolver groupResolver = new ActiveDirectoryGroupsResolver(settings.getAsSettings("group_search"), domainDN); defaultADAuthenticator = new DefaultADAuthenticator(settings, timeout, logger, groupResolver, domainDN); - downLevelADAuthenticator = new DownLevelADAuthenticator(settings, timeout, logger, groupResolver, domainDN); + downLevelADAuthenticator = new DownLevelADAuthenticator(config, timeout, logger, groupResolver, domainDN, sslService); upnADAuthenticator = new UpnADAuthenticator(settings, timeout, logger, groupResolver, domainDN); } @@ -227,11 +227,16 @@ class ActiveDirectorySessionFactory extends SessionFactory { final String domainDN; final Settings settings; + final SSLService sslService; + final RealmConfig config; - DownLevelADAuthenticator(Settings settings, TimeValue timeout, Logger logger, GroupsResolver groupsResolver, String domainDN) { - super(settings, timeout, logger, groupsResolver, domainDN); + DownLevelADAuthenticator(RealmConfig config, TimeValue timeout, Logger logger, GroupsResolver groupsResolver, String domainDN, + SSLService sslService) { + super(config.settings(), timeout, logger, groupsResolver, domainDN); this.domainDN = domainDN; - this.settings = settings; + this.settings = config.settings(); + this.sslService = sslService; + this.config = config; } @Override @@ -271,7 +276,7 @@ class ActiveDirectorySessionFactory extends SessionFactory { // 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(settings); + final LDAPConnectionOptions options = connectionOptions(config, sslService, logger); boolean startedSearching = false; LDAPConnection searchConnection = null; try { diff --git a/elasticsearch/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactory.java b/elasticsearch/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactory.java index 557c2d2c7f2..4360063499d 100644 --- a/elasticsearch/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactory.java +++ b/elasticsearch/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactory.java @@ -13,13 +13,16 @@ import com.unboundid.util.ssl.HostNameSSLSocketVerifier; import org.apache.logging.log4j.Logger; import org.elasticsearch.action.ActionListener; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.xpack.security.authc.RealmConfig; +import org.elasticsearch.xpack.security.authc.RealmSettings; import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.ssl.SSLConfigurationSettings; import org.elasticsearch.xpack.ssl.SSLService; +import org.elasticsearch.xpack.ssl.VerificationMode; import javax.net.SocketFactory; import java.util.Arrays; @@ -73,7 +76,7 @@ public abstract class SessionFactory { this.timeout = searchTimeout; this.sslService = sslService; LDAPServers ldapServers = ldapServers(config.settings()); - this.serverSet = serverSet(config.settings(), sslService, ldapServers); + this.serverSet = serverSet(config, sslService, ldapServers); this.sslUsed = ldapServers.ssl; } @@ -107,13 +110,33 @@ public abstract class SessionFactory { throw new UnsupportedOperationException("unauthenticated sessions are not supported"); } - protected static LDAPConnectionOptions connectionOptions(Settings settings) { + protected static LDAPConnectionOptions connectionOptions(RealmConfig config, SSLService sslService, Logger logger) { + Settings realmSettings = config.settings(); LDAPConnectionOptions options = new LDAPConnectionOptions(); - options.setConnectTimeoutMillis(Math.toIntExact(settings.getAsTime(TIMEOUT_TCP_CONNECTION_SETTING, TIMEOUT_DEFAULT).millis())); - options.setFollowReferrals(settings.getAsBoolean(FOLLOW_REFERRALS_SETTING, true)); - options.setResponseTimeoutMillis(settings.getAsTime(TIMEOUT_TCP_READ_SETTING, TIMEOUT_DEFAULT).millis()); + options.setConnectTimeoutMillis(Math.toIntExact(realmSettings.getAsTime(TIMEOUT_TCP_CONNECTION_SETTING, TIMEOUT_DEFAULT).millis())); + options.setFollowReferrals(realmSettings.getAsBoolean(FOLLOW_REFERRALS_SETTING, true)); + options.setResponseTimeoutMillis(realmSettings.getAsTime(TIMEOUT_TCP_READ_SETTING, TIMEOUT_DEFAULT).millis()); options.setAllowConcurrentSocketFactoryUse(true); - if (settings.getAsBoolean(HOSTNAME_VERIFICATION_SETTING, true)) { + SSLConfigurationSettings sslConfigurationSettings = SSLConfigurationSettings.withoutPrefix(); + final Settings realmSSLSettings = realmSettings.getByPrefix("ssl."); + final boolean verificationModeExists = sslConfigurationSettings.verificationMode.exists(realmSSLSettings); + final boolean hostnameVerficationExists = realmSettings.get(HOSTNAME_VERIFICATION_SETTING, null) != null; + if (verificationModeExists && hostnameVerficationExists) { + throw new IllegalArgumentException("[" + HOSTNAME_VERIFICATION_SETTING + "] and [" + + sslConfigurationSettings.verificationMode.getKey() + "] may not be used at the same time"); + } else if (verificationModeExists) { + VerificationMode verificationMode = sslService.getVerificationMode(realmSSLSettings, Settings.EMPTY); + if (verificationMode == VerificationMode.FULL) { + options.setSSLSocketVerifier(new HostNameSSLSocketVerifier(true)); + } + } else if (hostnameVerficationExists) { + new DeprecationLogger(logger).deprecated("the setting [{}] has been deprecated and will be removed in a future version. use " + + "[{}] instead", RealmSettings.getFullSettingKey(config, HOSTNAME_VERIFICATION_SETTING), + RealmSettings.getFullSettingKey(config, "ssl." + sslConfigurationSettings.verificationMode.getKey())); + if (realmSettings.getAsBoolean(HOSTNAME_VERIFICATION_SETTING, true)) { + options.setSSLSocketVerifier(new HostNameSSLSocketVerifier(true)); + } + } else { options.setSSLSocketVerifier(new HostNameSSLSocketVerifier(true)); } return options; @@ -132,7 +155,8 @@ public abstract class SessionFactory { return null; } - private ServerSet serverSet(Settings settings, SSLService clientSSLService, LDAPServers ldapServers) { + private ServerSet serverSet(RealmConfig realmConfig, SSLService clientSSLService, LDAPServers ldapServers) { + Settings settings = realmConfig.settings(); SocketFactory socketFactory = null; if (ldapServers.ssl()) { socketFactory = clientSSLService.sslSocketFactory(settings.getByPrefix("ssl.")); @@ -143,7 +167,7 @@ public abstract class SessionFactory { } } return LdapLoadBalancing.serverSet(ldapServers.addresses(), ldapServers.ports(), settings, socketFactory, - connectionOptions(settings)); + connectionOptions(realmConfig, sslService, logger)); } // package private to use for testing diff --git a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/AbstractActiveDirectoryIntegTests.java b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/AbstractActiveDirectoryIntegTests.java index 9b4a668f092..33608d1b27f 100644 --- a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/AbstractActiveDirectoryIntegTests.java +++ b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/AbstractActiveDirectoryIntegTests.java @@ -11,6 +11,7 @@ import org.elasticsearch.xpack.security.authc.ldap.support.LdapSearchScope; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.junit.annotations.Network; import org.elasticsearch.xpack.ssl.SSLService; +import org.elasticsearch.xpack.ssl.VerificationMode; import org.junit.Before; import java.nio.file.Path; @@ -39,10 +40,19 @@ public class AbstractActiveDirectoryIntegTests extends ESTestCase { if (useGlobalSSL) { builder.put("xpack.ssl.keystore.path", keystore) .put("xpack.ssl.keystore.password", "changeit"); + + // fake realm to load config with certificate verification mode + builder.put("xpack.security.authc.realms.bar.ssl.keystore.path", keystore); + builder.put("xpack.security.authc.realms.bar.ssl.keystore.password", "changeit"); + builder.put("xpack.security.authc.realms.bar.ssl.verification_mode", VerificationMode.CERTIFICATE); } else { - // fake a realm so ssl will get loaded + // fake realms so ssl will get loaded builder.put("xpack.security.authc.realms.foo.ssl.truststore.path", keystore); builder.put("xpack.security.authc.realms.foo.ssl.truststore.password", "changeit"); + builder.put("xpack.security.authc.realms.foo.ssl.verification_mode", VerificationMode.FULL); + builder.put("xpack.security.authc.realms.bar.ssl.truststore.path", keystore); + builder.put("xpack.security.authc.realms.bar.ssl.truststore.password", "changeit"); + builder.put("xpack.security.authc.realms.bar.ssl.verification_mode", VerificationMode.CERTIFICATE); } globalSettings = builder.build(); Environment environment = new Environment(globalSettings); @@ -55,8 +65,12 @@ public class AbstractActiveDirectoryIntegTests extends ESTestCase { .putArray(ActiveDirectorySessionFactory.URLS_SETTING, ldapUrl) .put(ActiveDirectorySessionFactory.AD_DOMAIN_NAME_SETTING, adDomainName) .put(ActiveDirectorySessionFactory.AD_USER_SEARCH_BASEDN_SETTING, userSearchDN) - .put(ActiveDirectorySessionFactory.AD_USER_SEARCH_SCOPE_SETTING, scope) - .put(ActiveDirectorySessionFactory.HOSTNAME_VERIFICATION_SETTING, hostnameVerification); + .put(ActiveDirectorySessionFactory.AD_USER_SEARCH_SCOPE_SETTING, scope); + if (randomBoolean()) { + builder.put("ssl.verification_mode", hostnameVerification ? VerificationMode.FULL : VerificationMode.CERTIFICATE); + } else { + builder.put(ActiveDirectorySessionFactory.HOSTNAME_VERIFICATION_SETTING, hostnameVerification); + } if (useGlobalSSL == false) { builder.put("ssl.truststore.path", getDataPath("../ldap/support/ldaptrust.jks")) .put("ssl.truststore.password", "changeit"); diff --git a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryRealmTests.java b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryRealmTests.java index 4414269700b..8e4313c09ff 100644 --- a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryRealmTests.java +++ b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryRealmTests.java @@ -16,6 +16,7 @@ import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.common.Strings; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.env.Environment; import org.elasticsearch.xpack.security.user.User; import org.elasticsearch.xpack.security.authc.RealmConfig; import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm; @@ -27,6 +28,8 @@ import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.TestThreadPool; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.watcher.ResourceWatcherService; +import org.elasticsearch.xpack.ssl.SSLService; +import org.elasticsearch.xpack.ssl.VerificationMode; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; @@ -72,6 +75,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase { private ResourceWatcherService resourceWatcherService; private ThreadPool threadPool; private Settings globalSettings; + private SSLService sslService; @BeforeClass public static void setNumberOfLdapServers() { @@ -101,6 +105,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase { threadPool = new TestThreadPool("active directory realm tests"); resourceWatcherService = new ResourceWatcherService(Settings.EMPTY, threadPool); globalSettings = Settings.builder().put("path.home", createTempDir()).build(); + sslService = new SSLService(globalSettings, new Environment(globalSettings)); } @After @@ -112,10 +117,15 @@ public class ActiveDirectoryRealmTests extends ESTestCase { } } + @Override + public boolean enableWarningsCheck() { + return false; + } + public void testAuthenticateUserPrincipleName() throws Exception { Settings settings = settings(); RealmConfig config = new RealmConfig("testAuthenticateUserPrincipleName", settings, globalSettings); - ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, null); + ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService); DnRoleMapper roleMapper = new DnRoleMapper(LdapRealm.AD_TYPE, config, resourceWatcherService, () -> {}); LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool); @@ -129,7 +139,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase { public void testAuthenticateSAMAccountName() throws Exception { Settings settings = settings(); RealmConfig config = new RealmConfig("testAuthenticateSAMAccountName", settings, globalSettings); - ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, null); + ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService); DnRoleMapper roleMapper = new DnRoleMapper(LdapRealm.AD_TYPE, config, resourceWatcherService, () -> {}); LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool); @@ -153,7 +163,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase { public void testAuthenticateCachesSuccesfulAuthentications() throws Exception { Settings settings = settings(); RealmConfig config = new RealmConfig("testAuthenticateCachesSuccesfulAuthentications", settings, globalSettings); - ActiveDirectorySessionFactory sessionFactory = spy(new ActiveDirectorySessionFactory(config, null)); + ActiveDirectorySessionFactory sessionFactory = spy(new ActiveDirectorySessionFactory(config, sslService)); DnRoleMapper roleMapper = new DnRoleMapper(LdapRealm.AD_TYPE, config, resourceWatcherService, () -> {}); LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool); @@ -171,7 +181,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); - ActiveDirectorySessionFactory sessionFactory = spy(new ActiveDirectorySessionFactory(config, null)); + ActiveDirectorySessionFactory sessionFactory = spy(new ActiveDirectorySessionFactory(config, sslService)); DnRoleMapper roleMapper = new DnRoleMapper(LdapRealm.AD_TYPE, config, resourceWatcherService, () -> {}); LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool); @@ -189,7 +199,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase { public void testAuthenticateCachingClearsCacheOnRoleMapperRefresh() throws Exception { Settings settings = settings(); RealmConfig config = new RealmConfig("testAuthenticateCachingClearsCacheOnRoleMapperRefresh", settings, globalSettings); - ActiveDirectorySessionFactory sessionFactory = spy(new ActiveDirectorySessionFactory(config, null)); + ActiveDirectorySessionFactory sessionFactory = spy(new ActiveDirectorySessionFactory(config, sslService)); DnRoleMapper roleMapper = new DnRoleMapper(LdapRealm.AD_TYPE, config, resourceWatcherService, () -> {}); LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool); @@ -220,7 +230,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase { .put(ROLE_MAPPING_FILE_SETTING, getDataPath("role_mapping.yml")) .build()); RealmConfig config = new RealmConfig("testRealmMapsGroupsToRoles", settings, globalSettings); - ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, null); + ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService); DnRoleMapper roleMapper = new DnRoleMapper(LdapRealm.AD_TYPE, config, resourceWatcherService, () -> {}); LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool); @@ -236,7 +246,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase { .put(ROLE_MAPPING_FILE_SETTING, getDataPath("role_mapping.yml")) .build()); RealmConfig config = new RealmConfig("testRealmMapsGroupsToRoles", settings, globalSettings); - ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, null); + ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService); DnRoleMapper roleMapper = new DnRoleMapper(LdapRealm.AD_TYPE, config, resourceWatcherService, () -> {}); LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool); @@ -254,7 +264,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase { .put("load_balance.type", loadBalanceType) .build()); RealmConfig config = new RealmConfig("testRealmUsageStats", settings, globalSettings); - ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, null); + ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService); DnRoleMapper roleMapper = new DnRoleMapper(LdapRealm.AD_TYPE, config, resourceWatcherService, () -> {}); LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool); @@ -272,12 +282,15 @@ public class ActiveDirectoryRealmTests extends ESTestCase { } private Settings settings(Settings extraSettings) throws Exception { - return Settings.builder() + Settings.Builder builder = Settings.builder() .putArray(URLS_SETTING, ldapUrls()) .put(ActiveDirectorySessionFactory.AD_DOMAIN_NAME_SETTING, "ad.test.elasticsearch.com") - .put(DnRoleMapper.USE_UNMAPPED_GROUPS_AS_ROLES_SETTING.getKey(), true) - .put(HOSTNAME_VERIFICATION_SETTING, false) - .put(extraSettings) - .build(); + .put(DnRoleMapper.USE_UNMAPPED_GROUPS_AS_ROLES_SETTING.getKey(), true); + if (randomBoolean()) { + builder.put("ssl.verification_mode", VerificationMode.CERTIFICATE); + } else { + builder.put(HOSTNAME_VERIFICATION_SETTING, false); + } + return builder.put(extraSettings).build(); } } diff --git a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactoryTests.java b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactoryTests.java index ae0c71eb96f..fc7bcf3058e 100644 --- a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactoryTests.java +++ b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactoryTests.java @@ -17,6 +17,7 @@ import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory; import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.SecuredStringTests; import org.elasticsearch.test.junit.annotations.Network; +import org.elasticsearch.xpack.ssl.VerificationMode; import java.util.List; import java.util.concurrent.ExecutionException; @@ -31,6 +32,11 @@ import static org.hamcrest.Matchers.is; @Network public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryIntegTests { + @Override + public boolean enableWarningsCheck() { + return false; + } + @SuppressWarnings("unchecked") public void testAdAuth() throws Exception { RealmConfig config = new RealmConfig("ad-test", buildAdSettings(AD_LDAP_URL, AD_DOMAIN, false), globalSettings); @@ -78,7 +84,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI Settings settings = Settings.builder() .put(buildAdSettings(AD_LDAP_URL, AD_DOMAIN, false)) .put("group_search.filter", "(objectClass=*)") - .put(SessionFactory.HOSTNAME_VERIFICATION_SETTING, false) + .put("ssl.verification_mode", VerificationMode.CERTIFICATE) .put(SessionFactory.TIMEOUT_TCP_READ_SETTING, "1ms") .build(); RealmConfig config = new RealmConfig("ad-test", settings, globalSettings); @@ -296,7 +302,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI String userTemplate = "CN={0},CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com"; Settings settings = Settings.builder() .put(LdapTestCase.buildLdapSettings(AD_LDAP_URL, userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE)) - .put(LdapSessionFactory.HOSTNAME_VERIFICATION_SETTING, true) + .put("ssl.verification_mode", VerificationMode.FULL) .build(); RealmConfig config = new RealmConfig("ad-test", settings, globalSettings); LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService); @@ -313,8 +319,12 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI Settings buildAdSettings(String ldapUrl, String adDomainName, boolean hostnameVerification) { Settings.Builder builder = Settings.builder() .put(ActiveDirectorySessionFactory.URLS_SETTING, ldapUrl) - .put(ActiveDirectorySessionFactory.AD_DOMAIN_NAME_SETTING, adDomainName) - .put(ActiveDirectorySessionFactory.HOSTNAME_VERIFICATION_SETTING, hostnameVerification); + .put(ActiveDirectorySessionFactory.AD_DOMAIN_NAME_SETTING, adDomainName); + if (randomBoolean()) { + builder.put("ssl.verification_mode", hostnameVerification ? VerificationMode.FULL : VerificationMode.CERTIFICATE); + } else { + builder.put(ActiveDirectorySessionFactory.HOSTNAME_VERIFICATION_SETTING, hostnameVerification); + } if (useGlobalSSL == false) { builder.put("ssl.truststore.path", getDataPath("../ldap/support/ldaptrust.jks")) .put("ssl.truststore.password", "changeit"); diff --git a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/GroupsResolverTestCase.java b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/GroupsResolverTestCase.java index b28a2ea8c4f..8197a5f4650 100644 --- a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/GroupsResolverTestCase.java +++ b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/GroupsResolverTestCase.java @@ -19,6 +19,7 @@ import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession.GroupsRes import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.ssl.SSLService; +import org.elasticsearch.xpack.ssl.VerificationMode; import org.junit.After; import org.junit.Before; @@ -44,10 +45,19 @@ public abstract class GroupsResolverTestCase extends ESTestCase { if (useGlobalSSL) { builder.put("xpack.ssl.keystore.path", keystore) .put("xpack.ssl.keystore.password", "changeit"); + + // fake realm to load config with certificate verification mode + builder.put("xpack.security.authc.realms.bar.ssl.keystore.path", keystore); + builder.put("xpack.security.authc.realms.bar.ssl.keystore.password", "changeit"); + builder.put("xpack.security.authc.realms.bar.ssl.verification_mode", VerificationMode.CERTIFICATE); } else { - // fake a realm so ssl will get loaded + // fake realms so ssl will get loaded builder.put("xpack.security.authc.realms.foo.ssl.keystore.path", keystore); builder.put("xpack.security.authc.realms.foo.ssl.keystore.password", "changeit"); + builder.put("xpack.security.authc.realms.foo.ssl.verification_mode", VerificationMode.FULL); + builder.put("xpack.security.authc.realms.bar.ssl.keystore.path", keystore); + builder.put("xpack.security.authc.realms.bar.ssl.keystore.password", "changeit"); + builder.put("xpack.security.authc.realms.bar.ssl.verification_mode", VerificationMode.CERTIFICATE); } Settings settings = builder.build(); Environment env = new Environment(settings); diff --git a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapRealmTests.java b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapRealmTests.java index dc0f4d3cdd9..16de13fa0b2 100644 --- a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapRealmTests.java +++ b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapRealmTests.java @@ -8,6 +8,7 @@ package org.elasticsearch.xpack.security.authc.ldap; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.env.Environment; import org.elasticsearch.xpack.security.authc.RealmConfig; import org.elasticsearch.xpack.security.authc.ldap.support.LdapSearchScope; import org.elasticsearch.xpack.security.authc.ldap.support.LdapTestCase; @@ -21,13 +22,14 @@ import org.elasticsearch.xpack.security.user.User; import org.elasticsearch.threadpool.TestThreadPool; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.watcher.ResourceWatcherService; +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.Map; -import static org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory.HOSTNAME_VERIFICATION_SETTING; import static org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory.URLS_SETTING; import static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.containsString; @@ -52,12 +54,14 @@ public class LdapRealmTests extends LdapTestCase { private ThreadPool threadPool; private ResourceWatcherService resourceWatcherService; private Settings globalSettings; + private SSLService sslService; @Before public void init() throws Exception { threadPool = new TestThreadPool("ldap realm tests"); resourceWatcherService = new ResourceWatcherService(Settings.EMPTY, threadPool); globalSettings = Settings.builder().put("path.home", createTempDir()).build(); + sslService = new SSLService(globalSettings, new Environment(globalSettings)); } @After @@ -71,7 +75,7 @@ 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); - LdapSessionFactory ldapFactory = new LdapSessionFactory(config, null); + LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService); LdapRealm ldap = new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), threadPool); @@ -90,7 +94,7 @@ public class LdapRealmTests extends LdapTestCase { .build(); RealmConfig config = new RealmConfig("test-ldap-realm", settings, globalSettings); - LdapSessionFactory ldapFactory = new LdapSessionFactory(config, null); + LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService); LdapRealm ldap = new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), threadPool); @@ -109,7 +113,7 @@ public class LdapRealmTests extends LdapTestCase { .build(); RealmConfig config = new RealmConfig("test-ldap-realm", settings, globalSettings); - LdapSessionFactory ldapFactory = new LdapSessionFactory(config, null); + LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService); ldapFactory = spy(ldapFactory); LdapRealm ldap = new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), threadPool); @@ -132,7 +136,7 @@ public class LdapRealmTests extends LdapTestCase { .build(); RealmConfig config = new RealmConfig("test-ldap-realm", settings, globalSettings); - LdapSessionFactory ldapFactory = new LdapSessionFactory(config, null); + LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService); DnRoleMapper roleMapper = buildGroupAsRoleMapper(resourceWatcherService); ldapFactory = spy(ldapFactory); LdapRealm ldap = new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory, roleMapper, threadPool); @@ -165,7 +169,7 @@ public class LdapRealmTests extends LdapTestCase { .build(); RealmConfig config = new RealmConfig("test-ldap-realm", settings, globalSettings); - LdapSessionFactory ldapFactory = new LdapSessionFactory(config, null); + LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService); ldapFactory = spy(ldapFactory); LdapRealm ldap = new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), threadPool); @@ -188,10 +192,10 @@ public class LdapRealmTests extends LdapTestCase { .putArray(USER_DN_TEMPLATES_SETTING_KEY, userTemplate) .put("group_search.base_dn", groupSearchBase) .put("group_search.scope", LdapSearchScope.SUB_TREE) - .put(HOSTNAME_VERIFICATION_SETTING, false) + .put("ssl.verification_mode", VerificationMode.CERTIFICATE) .build(); RealmConfig config = new RealmConfig("test-ldap-realm", settings, globalSettings); - SessionFactory sessionFactory = LdapRealm.sessionFactory(config, null, LdapRealm.LDAP_TYPE); + SessionFactory sessionFactory = LdapRealm.sessionFactory(config, sslService, LdapRealm.LDAP_TYPE); assertThat(sessionFactory, is(instanceOf(LdapSessionFactory.class))); } @@ -204,10 +208,10 @@ public class LdapRealmTests extends LdapTestCase { .put("bind_password", PASSWORD) .put("group_search.base_dn", groupSearchBase) .put("group_search.scope", LdapSearchScope.SUB_TREE) - .put(HOSTNAME_VERIFICATION_SETTING, false) + .put("ssl.verification_mode", VerificationMode.CERTIFICATE) .build(); RealmConfig config = new RealmConfig("test-ldap-realm-user-search", settings, globalSettings); - SessionFactory sessionFactory = LdapRealm.sessionFactory(config, null, LdapRealm.LDAP_TYPE); + SessionFactory sessionFactory = LdapRealm.sessionFactory(config, sslService, LdapRealm.LDAP_TYPE); try { assertThat(sessionFactory, is(instanceOf(LdapUserSearchSessionFactory.class))); } finally { @@ -222,7 +226,7 @@ public class LdapRealmTests extends LdapTestCase { .put("user_search.base_dn", "cn=bar") .put("group_search.base_dn", "") .put("group_search.scope", LdapSearchScope.SUB_TREE) - .put(HOSTNAME_VERIFICATION_SETTING, false) + .put("ssl.verification_mode", VerificationMode.CERTIFICATE) .build(); RealmConfig config = new RealmConfig("test-ldap-realm-user-search", settings, globalSettings); IllegalArgumentException e = expectThrows(IllegalArgumentException.class, @@ -238,7 +242,7 @@ public class LdapRealmTests extends LdapTestCase { .putArray(URLS_SETTING, ldapUrls()) .put("group_search.base_dn", "") .put("group_search.scope", LdapSearchScope.SUB_TREE) - .put(HOSTNAME_VERIFICATION_SETTING, false) + .put("ssl.verification_mode", VerificationMode.CERTIFICATE) .build(); RealmConfig config = new RealmConfig("test-ldap-realm-user-search", settings, globalSettings); IllegalArgumentException e = expectThrows(IllegalArgumentException.class, @@ -259,7 +263,7 @@ public class LdapRealmTests extends LdapTestCase { .build(); RealmConfig config = new RealmConfig("test-ldap-realm-userdn", settings, globalSettings); - LdapSessionFactory ldapFactory = new LdapSessionFactory(config, null); + LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService); LdapRealm ldap = new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory, new DnRoleMapper(LdapRealm.LDAP_TYPE, config, resourceWatcherService, null), threadPool); @@ -279,7 +283,7 @@ public class LdapRealmTests extends LdapTestCase { .put("group_search.base_dn", groupSearchBase) .put("group_search.scope", LdapSearchScope.SUB_TREE) .put(LdapSessionFactory.USER_DN_TEMPLATES_SETTING.getKey(), "--") - .put(HOSTNAME_VERIFICATION_SETTING, false); + .put("ssl.verification_mode", VerificationMode.CERTIFICATE); int order = randomIntBetween(0, 10); settings.put("order", order); @@ -291,7 +295,7 @@ public class LdapRealmTests extends LdapTestCase { RealmConfig config = new RealmConfig("ldap-realm", settings.build(), globalSettings); - LdapSessionFactory ldapFactory = new LdapSessionFactory(config, null); + LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService); LdapRealm realm = new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory, new DnRoleMapper(LdapRealm.LDAP_TYPE, config, resourceWatcherService, null), threadPool); diff --git a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapSessionFactoryTests.java b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapSessionFactoryTests.java index 76a22c40b19..c3e6900805a 100644 --- a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapSessionFactoryTests.java +++ b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapSessionFactoryTests.java @@ -10,6 +10,7 @@ import com.unboundid.ldap.sdk.LDAPException; import com.unboundid.ldap.sdk.LDAPURL; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.UncategorizedExecutionException; +import org.elasticsearch.env.Environment; 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; @@ -18,6 +19,7 @@ import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory; import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.SecuredStringTests; import org.elasticsearch.test.junit.annotations.Network; +import org.elasticsearch.xpack.ssl.SSLService; import org.junit.Before; import java.util.List; @@ -32,10 +34,12 @@ import static org.hamcrest.Matchers.lessThan; public class LdapSessionFactoryTests extends LdapTestCase { private Settings globalSettings; + private SSLService sslService; @Before public void setup() { globalSettings = Settings.builder().put("path.home", createTempDir()).build(); + sslService = new SSLService(globalSettings, new Environment(globalSettings)); } public void testBindWithReadTimeout() throws Exception { @@ -51,7 +55,7 @@ public class LdapSessionFactoryTests extends LdapTestCase { .build(); RealmConfig config = new RealmConfig("ldap_realm", settings, globalSettings); - LdapSessionFactory sessionFactory = new LdapSessionFactory(config, null); + LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService); String user = "Horatio Hornblower"; SecuredString userPass = SecuredStringTests.build("pass"); @@ -81,7 +85,7 @@ public class LdapSessionFactoryTests extends LdapTestCase { .build(); RealmConfig config = new RealmConfig("ldap_realm", settings, globalSettings); - LdapSessionFactory sessionFactory = new LdapSessionFactory(config, null); + LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService); String user = "Horatio Hornblower"; SecuredString userPass = SecuredStringTests.build("pass"); @@ -104,7 +108,7 @@ public class LdapSessionFactoryTests extends LdapTestCase { RealmConfig config = new RealmConfig("ldap_realm", buildLdapSettings(ldapUrls(), userTemplates, groupSearchBase, LdapSearchScope.SUB_TREE), globalSettings); - LdapSessionFactory sessionFactory = new LdapSessionFactory(config, null); + LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService); String user = "Horatio Hornblower"; SecuredString userPass = SecuredStringTests.build("pass"); @@ -125,7 +129,7 @@ public class LdapSessionFactoryTests extends LdapTestCase { RealmConfig config = new RealmConfig("ldap_realm", buildLdapSettings(ldapUrls(), userTemplates, groupSearchBase, LdapSearchScope.SUB_TREE), globalSettings); - LdapSessionFactory ldapFac = new LdapSessionFactory(config, null); + LdapSessionFactory ldapFac = new LdapSessionFactory(config, sslService); String user = "Horatio Hornblower"; SecuredString userPass = SecuredStringTests.build("pass"); @@ -143,7 +147,7 @@ public class LdapSessionFactoryTests extends LdapTestCase { RealmConfig config = new RealmConfig("ldap_realm", buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE), globalSettings); - LdapSessionFactory ldapFac = new LdapSessionFactory(config, null); + LdapSessionFactory ldapFac = new LdapSessionFactory(config, sslService); String user = "Horatio Hornblower"; SecuredString userPass = SecuredStringTests.build("pass"); @@ -160,7 +164,7 @@ public class LdapSessionFactoryTests extends LdapTestCase { RealmConfig config = new RealmConfig("ldap_realm", buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL), globalSettings); - LdapSessionFactory ldapFac = new LdapSessionFactory(config, null); + LdapSessionFactory ldapFac = new LdapSessionFactory(config, sslService); String user = "Horatio Hornblower"; try (LdapSession ldap = session(ldapFac, user, SecuredStringTests.build("pass"))) { @@ -175,7 +179,7 @@ public class LdapSessionFactoryTests extends LdapTestCase { RealmConfig config = new RealmConfig("ldap_realm", buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.BASE), globalSettings); - LdapSessionFactory ldapFac = new LdapSessionFactory(config, null); + LdapSessionFactory ldapFac = new LdapSessionFactory(config, sslService); String user = "Horatio Hornblower"; SecuredString userPass = SecuredStringTests.build("pass"); diff --git a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactoryTests.java b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactoryTests.java index 1eb07cd895b..6096762cf7e 100644 --- a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactoryTests.java +++ b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactoryTests.java @@ -32,6 +32,7 @@ import java.nio.file.Path; import java.text.MessageFormat; import java.util.List; import java.util.Locale; +import java.util.Map; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; @@ -72,7 +73,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase { .put("user_search.pool.enabled", randomBoolean()) .build(), globalSettings); - LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, null); + LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService); try { assertThat(sessionFactory.supportsUnauthenticatedSession(), is(true)); } finally { @@ -93,7 +94,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase { .put("user_search.pool.enabled", randomBoolean()) .build(), globalSettings); - LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, null); + LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService); String user = "William Bush"; SecuredString userPass = SecuredStringTests.build("pass"); @@ -129,7 +130,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase { .put("user_search.pool.enabled", randomBoolean()) .build(), globalSettings); - LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, null); + LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService); String user = "William Bush"; SecuredString userPass = SecuredStringTests.build("pass"); @@ -156,7 +157,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase { .put("user_search.pool.enabled", randomBoolean()) .build(), globalSettings); - LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, null); + LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService); String user = "William Bush"; SecuredString userPass = SecuredStringTests.build("pass"); @@ -192,7 +193,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase { .put("user_search.pool.enabled", randomBoolean()) .build(), globalSettings); - LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, null); + LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService); String user = "William Bush"; SecuredString userPass = SecuredStringTests.build("pass"); @@ -219,7 +220,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase { .put("user_search.pool.enabled", randomBoolean()) .build(), globalSettings); - LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, null); + LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService); String user = "William Bush"; SecuredString userPass = SecuredStringTests.build("pass"); @@ -254,7 +255,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase { .put("user_search.pool.enabled", randomBoolean()) .build(), globalSettings); - LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, null); + LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService); String user = "William Bush"; SecuredString userPass = SecuredStringTests.build("pass"); @@ -279,7 +280,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase { .put("user_search.pool.enabled", randomBoolean()) .build(), globalSettings); - LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, null); + LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService); String user = "wbush"; SecuredString userPass = SecuredStringTests.build("pass"); @@ -314,6 +315,13 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase { .put("user_search.attribute", "cn") .put("user_search.pool.enabled", randomBoolean()) .build(); + Settings.Builder builder = Settings.builder() + .put(globalSettings); + for (Map.Entry entry : settings.getAsMap().entrySet()) { + builder.put("xpack.security.authc.realms.ldap." + entry.getKey(), entry.getValue()); + } + Settings fullSettings = builder.build(); + sslService = new SSLService(fullSettings, new Environment(fullSettings)); RealmConfig config = new RealmConfig("ad-as-ldap-test", settings, globalSettings); LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService); @@ -357,6 +365,13 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase { .put("bind_password", OpenLdapTests.PASSWORD) .put("user_search.pool.enabled", randomBoolean()) .build(), globalSettings); + Settings.Builder builder = Settings.builder() + .put(globalSettings); + for (Map.Entry entry : config.settings().getAsMap().entrySet()) { + builder.put("xpack.security.authc.realms.ldap." + entry.getKey(), entry.getValue()); + } + Settings settings = builder.build(); + sslService = new SSLService(settings, new Environment(settings)); LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService); String[] users = new String[] { "cap", "hawkeye", "hulk", "ironman", "thor" }; @@ -443,7 +458,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase { LdapUserSearchSessionFactory searchSessionFactory = null; try { - searchSessionFactory = new LdapUserSearchSessionFactory(config, null); + searchSessionFactory = new LdapUserSearchSessionFactory(config, sslService); } finally { if (searchSessionFactory != null) { searchSessionFactory.shutdown(); @@ -491,7 +506,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase { RealmConfig config = new RealmConfig("ldap_realm", ldapSettings, globalSettings); LdapUserSearchSessionFactory searchSessionFactory = null; try { - searchSessionFactory = new LdapUserSearchSessionFactory(config, null); + searchSessionFactory = new LdapUserSearchSessionFactory(config, sslService); } finally { if (searchSessionFactory != null) { searchSessionFactory.shutdown(); diff --git a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/OpenLdapTests.java b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/OpenLdapTests.java index 056c44c89ca..24a49d9c01a 100644 --- a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/OpenLdapTests.java +++ b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/OpenLdapTests.java @@ -20,6 +20,7 @@ import org.elasticsearch.xpack.security.authc.support.SecuredStringTests; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.junit.annotations.Network; import org.elasticsearch.xpack.ssl.SSLService; +import org.elasticsearch.xpack.ssl.VerificationMode; import org.junit.Before; import java.nio.file.Path; @@ -54,10 +55,19 @@ public class OpenLdapTests extends ESTestCase { if (useGlobalSSL) { builder.put("xpack.ssl.keystore.path", keystore) .put("xpack.ssl.keystore.password", "changeit"); + + // fake realm to load config with certificate verification mode + builder.put("xpack.security.authc.realms.bar.ssl.keystore.path", keystore); + builder.put("xpack.security.authc.realms.bar.ssl.keystore.password", "changeit"); + builder.put("xpack.security.authc.realms.bar.ssl.verification_mode", VerificationMode.CERTIFICATE); } else { - // fake a realm so ssl will get loaded + // fake realms so ssl will get loaded builder.put("xpack.security.authc.realms.foo.ssl.truststore.path", keystore); builder.put("xpack.security.authc.realms.foo.ssl.truststore.password", "changeit"); + builder.put("xpack.security.authc.realms.foo.ssl.verification_mode", VerificationMode.FULL); + builder.put("xpack.security.authc.realms.bar.ssl.truststore.path", keystore); + builder.put("xpack.security.authc.realms.bar.ssl.truststore.password", "changeit"); + builder.put("xpack.security.authc.realms.bar.ssl.verification_mode", VerificationMode.CERTIFICATE); } globalSettings = builder.build(); Environment environment = new Environment(globalSettings); @@ -120,7 +130,7 @@ public class OpenLdapTests extends ESTestCase { Settings settings = Settings.builder() .put(buildLdapSettings(OPEN_LDAP_URL, userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE)) .put("group_search.filter", "(objectClass=*)") - .put(SessionFactory.HOSTNAME_VERIFICATION_SETTING, false) + .put("ssl.verification_mode", VerificationMode.CERTIFICATE) .put(SessionFactory.TIMEOUT_TCP_READ_SETTING, "1ms") //1 millisecond .build(); RealmConfig config = new RealmConfig("oldap-test", settings, globalSettings); @@ -137,7 +147,7 @@ public class OpenLdapTests extends ESTestCase { String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; Settings settings = Settings.builder() .put(buildLdapSettings(OPEN_LDAP_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL)) - .put(LdapSessionFactory.HOSTNAME_VERIFICATION_SETTING, true) + .put("ssl.verification_mode", VerificationMode.FULL) .build(); RealmConfig config = new RealmConfig("oldap-test", settings, globalSettings); diff --git a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapTestCase.java b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapTestCase.java index 30c5bfaf40d..319e3a990de 100644 --- a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapTestCase.java +++ b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapTestCase.java @@ -19,6 +19,7 @@ import org.elasticsearch.xpack.security.authc.support.DnRoleMapper; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.xpack.security.authc.support.SecuredString; +import org.elasticsearch.xpack.ssl.VerificationMode; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; @@ -91,7 +92,7 @@ public abstract class LdapTestCase extends ESTestCase { .putArray(USER_DN_TEMPLATES_SETTING_KEY, userTemplate) .put("group_search.base_dn", groupSearchBase) .put("group_search.scope", scope) - .put(HOSTNAME_VERIFICATION_SETTING, false); + .put("ssl.verification_mode", VerificationMode.CERTIFICATE); if (serverSetType != null) { builder.put(LdapLoadBalancing.LOAD_BALANCE_SETTINGS + "." + LdapLoadBalancing.LOAD_BALANCE_TYPE_SETTING, serverSetType.toString()); @@ -100,11 +101,15 @@ public abstract class LdapTestCase extends ESTestCase { } public static Settings buildLdapSettings(String[] ldapUrl, String userTemplate, boolean hostnameVerification) { - return Settings.builder() + Settings.Builder builder = Settings.builder() .putArray(URLS_SETTING, ldapUrl) - .putArray(USER_DN_TEMPLATES_SETTING_KEY, userTemplate) - .put(HOSTNAME_VERIFICATION_SETTING, hostnameVerification) - .build(); + .putArray(USER_DN_TEMPLATES_SETTING_KEY, userTemplate); + if (randomBoolean()) { + builder.put("ssl.verification_mode", hostnameVerification ? VerificationMode.FULL : VerificationMode.CERTIFICATE); + } else { + builder.put(HOSTNAME_VERIFICATION_SETTING, hostnameVerification); + } + return builder.build(); } protected DnRoleMapper buildGroupAsRoleMapper(ResourceWatcherService resourceWatcherService) { diff --git a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryLoadBalancingTests.java b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryLoadBalancingTests.java index fef0466460f..c223045320e 100644 --- a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryLoadBalancingTests.java +++ b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryLoadBalancingTests.java @@ -9,6 +9,7 @@ import com.unboundid.ldap.listener.InMemoryDirectoryServer; import com.unboundid.ldap.sdk.LDAPConnection; import org.elasticsearch.action.ActionListener; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.env.Environment; import org.elasticsearch.xpack.security.authc.RealmConfig; import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.ssl.SSLService; @@ -167,7 +168,7 @@ public class SessionFactoryLoadBalancingTests extends LdapTestCase { LdapSearchScope.SUB_TREE, loadBalancing); RealmConfig config = new RealmConfig("test-session-factory", settings, Settings.builder().put("path.home", createTempDir()).build()); - return new TestSessionFactory(config, null); + return new TestSessionFactory(config, new SSLService(Settings.EMPTY, new Environment(config.globalSettings()))); } static class TestSessionFactory extends SessionFactory { diff --git a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryTests.java b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryTests.java index 28781eb23bf..e88e34ccf5c 100644 --- a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryTests.java +++ b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryTests.java @@ -11,9 +11,14 @@ import com.unboundid.util.ssl.TrustAllSSLSocketVerifier; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.env.Environment; import org.elasticsearch.xpack.security.authc.RealmConfig; import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.ssl.SSLService; +import org.elasticsearch.xpack.ssl.VerificationMode; + +import java.io.IOException; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; @@ -21,8 +26,12 @@ import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; public class SessionFactoryTests extends ESTestCase { + public void testConnectionFactoryReturnsCorrectLDAPConnectionOptionsWithDefaultSettings() { - LDAPConnectionOptions options = SessionFactory.connectionOptions(Settings.EMPTY); + final Environment environment = new Environment(Settings.builder().put("path.home", createTempDir()).build()); + RealmConfig realmConfig = new RealmConfig("conn settings", Settings.EMPTY, environment.settings(), environment); + LDAPConnectionOptions options = SessionFactory.connectionOptions(realmConfig, new SSLService(environment.settings(), environment), + logger); assertThat(options.followReferrals(), is(equalTo(true))); assertThat(options.allowConcurrentSocketFactoryUse(), is(equalTo(true))); assertThat(options.getConnectTimeoutMillis(), is(equalTo(5000))); @@ -30,19 +39,43 @@ public class SessionFactoryTests extends ESTestCase { assertThat(options.getSSLSocketVerifier(), is(instanceOf(HostNameSSLSocketVerifier.class))); } - public void testConnectionFactoryReturnsCorrectLDAPConnectionOptions() { + public void testConnectionFactoryReturnsCorrectLDAPConnectionOptions() throws IOException { Settings settings = Settings.builder() .put(SessionFactory.TIMEOUT_TCP_CONNECTION_SETTING, "10ms") .put(SessionFactory.HOSTNAME_VERIFICATION_SETTING, "false") .put(SessionFactory.TIMEOUT_TCP_READ_SETTING, "20ms") .put(SessionFactory.FOLLOW_REFERRALS_SETTING, "false") .build(); - LDAPConnectionOptions options = SessionFactory.connectionOptions(settings); + + final Environment environment = new Environment(Settings.builder().put("path.home", createTempDir()).build()); + RealmConfig realmConfig = new RealmConfig("conn settings", settings, environment.settings(), environment); + LDAPConnectionOptions options = SessionFactory.connectionOptions(realmConfig, new SSLService(environment.settings(), environment), + logger); assertThat(options.followReferrals(), is(equalTo(false))); assertThat(options.allowConcurrentSocketFactoryUse(), is(equalTo(true))); assertThat(options.getConnectTimeoutMillis(), is(equalTo(10))); assertThat(options.getResponseTimeoutMillis(), is(equalTo(20L))); assertThat(options.getSSLSocketVerifier(), is(instanceOf(TrustAllSSLSocketVerifier.class))); + assertWarnings("the setting [xpack.security.authc.realms.conn settings.hostname_verification] has been deprecated and will be " + + "removed in a future version. use [xpack.security.authc.realms.conn settings.ssl.verification_mode] instead"); + + settings = Settings.builder().put("ssl.verification_mode", VerificationMode.CERTIFICATE).build(); + realmConfig = new RealmConfig("conn settings", settings, environment.settings(), environment); + options = SessionFactory.connectionOptions(realmConfig, new SSLService(environment.settings(), environment), + logger); + assertThat(options.getSSLSocketVerifier(), is(instanceOf(TrustAllSSLSocketVerifier.class))); + + settings = Settings.builder().put("ssl.verification_mode", VerificationMode.NONE).build(); + realmConfig = new RealmConfig("conn settings", settings, environment.settings(), environment); + options = SessionFactory.connectionOptions(realmConfig, new SSLService(environment.settings(), environment), + logger); + assertThat(options.getSSLSocketVerifier(), is(instanceOf(TrustAllSSLSocketVerifier.class))); + + settings = Settings.builder().put("ssl.verification_mode", VerificationMode.FULL).build(); + realmConfig = new RealmConfig("conn settings", settings, environment.settings(), environment); + options = SessionFactory.connectionOptions(realmConfig, new SSLService(environment.settings(), environment), + logger); + assertThat(options.getSSLSocketVerifier(), is(instanceOf(HostNameSSLSocketVerifier.class))); } public void testSessionFactoryDoesNotSupportUnauthenticated() {