Run active directory tests against a samba4 fixture (elastic/x-pack-elasticsearch#4067)

This commit adds a Samba4 test fixture that acts as a domain controller
and has the same contents as the cloud active directory instance that
we previously used for tests.

The tests also support reading information from environment variables
so that they can be run against a real active directory instance in our
CI builds.

In addition, this commit also fixes a few issues that surfaced when
making this change. The first is a change in the base DN that is
searched when performing down-level authentication. The base DN is
now the configuration object instead of the domain DN. This change was
required due to the original producing unnecessary referrals, which we
cannot easily follow when running against this test figure. Referrals
cannot easily be followed as they are returned by the ldap server with
an unresolvable DNS name unless the host points to the samba4 instance
for DNS. The port returned in the referral url is the one samba is bound
to, which differs from the port that is forwarded to the host by the
test fixture.

The other issue that is resolved by this change is the addition of
settings that allow specifying non-standard ports for active directory.
This is needed for down-level authentication as we may need to query
the regular port of active directory instead of the global catalog
port as the configuration object is not replicated to the global
catalog.

relates elastic/x-pack-elasticsearch#185
Relates elastic/x-pack-elasticsearch#3800

Original commit: elastic/x-pack-elasticsearch@883c742fba
This commit is contained in:
Jay Modi 2018-03-16 10:44:23 -06:00 committed by GitHub
parent 4c78ede9c1
commit bccf988e9d
28 changed files with 478 additions and 191 deletions

View File

@ -20,6 +20,10 @@ public final class ActiveDirectorySessionFactorySettings {
public static final String AD_UPN_USER_SEARCH_FILTER_SETTING = "user_search.upn_filter"; public static final String AD_UPN_USER_SEARCH_FILTER_SETTING = "user_search.upn_filter";
public static final String AD_DOWN_LEVEL_USER_SEARCH_FILTER_SETTING = "user_search.down_level_filter"; public static final String AD_DOWN_LEVEL_USER_SEARCH_FILTER_SETTING = "user_search.down_level_filter";
public static final String AD_USER_SEARCH_SCOPE_SETTING = "user_search.scope"; public static final String AD_USER_SEARCH_SCOPE_SETTING = "user_search.scope";
public static final Setting<Integer> AD_LDAP_PORT_SETTING = Setting.intSetting("port.ldap", 389, Setting.Property.NodeScope);
public static final Setting<Integer> AD_LDAPS_PORT_SETTING = Setting.intSetting("port.ldaps", 636, Setting.Property.NodeScope);
public static final Setting<Integer> AD_GC_LDAP_PORT_SETTING = Setting.intSetting("port.gc_ldap", 3268, Setting.Property.NodeScope);
public static final Setting<Integer> AD_GC_LDAPS_PORT_SETTING = Setting.intSetting("port.gc_ldaps", 3269, Setting.Property.NodeScope);
public static final Setting<Boolean> POOL_ENABLED = Setting.boolSetting("user_search.pool.enabled", public static final Setting<Boolean> POOL_ENABLED = Setting.boolSetting("user_search.pool.enabled",
settings -> Boolean.toString(PoolingSessionFactorySettings.BIND_DN.exists(settings)), Setting.Property.NodeScope); settings -> Boolean.toString(PoolingSessionFactorySettings.BIND_DN.exists(settings)), Setting.Property.NodeScope);
@ -36,6 +40,10 @@ public final class ActiveDirectorySessionFactorySettings {
settings.add(Setting.simpleString(AD_UPN_USER_SEARCH_FILTER_SETTING, Setting.Property.NodeScope)); settings.add(Setting.simpleString(AD_UPN_USER_SEARCH_FILTER_SETTING, Setting.Property.NodeScope));
settings.add(Setting.simpleString(AD_DOWN_LEVEL_USER_SEARCH_FILTER_SETTING, Setting.Property.NodeScope)); settings.add(Setting.simpleString(AD_DOWN_LEVEL_USER_SEARCH_FILTER_SETTING, Setting.Property.NodeScope));
settings.add(Setting.simpleString(AD_USER_SEARCH_SCOPE_SETTING, Setting.Property.NodeScope)); settings.add(Setting.simpleString(AD_USER_SEARCH_SCOPE_SETTING, Setting.Property.NodeScope));
settings.add(AD_LDAP_PORT_SETTING);
settings.add(AD_LDAPS_PORT_SETTING);
settings.add(AD_GC_LDAP_PORT_SETTING);
settings.add(AD_GC_LDAPS_PORT_SETTING);
settings.add(POOL_ENABLED); settings.add(POOL_ENABLED);
settings.addAll(PoolingSessionFactorySettings.getSettings()); settings.addAll(PoolingSessionFactorySettings.getSettings());
return settings; return settings;

View File

@ -128,7 +128,7 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
assertThat(aliases[0], is("key")); assertThat(aliases[0], is("key"));
}; };
final BiConsumer<X509ExtendedTrustManager, SSLConfiguration> trustManagerPostChecks = (updatedTrustManager, config) -> { final BiConsumer<X509ExtendedTrustManager, SSLConfiguration> trustManagerPostChecks = (updatedTrustManager, config) -> {
assertThat(trustedCount.get() - updatedTrustManager.getAcceptedIssuers().length, is(4)); assertThat(trustedCount.get() - updatedTrustManager.getAcceptedIssuers().length, is(5));
}; };
validateSSLConfigurationIsReloaded(settings, env, keyManagerPreChecks, trustManagerPreChecks, modifier, keyManagerPostChecks, validateSSLConfigurationIsReloaded(settings, env, keyManagerPreChecks, trustManagerPreChecks, modifier, keyManagerPostChecks,
trustManagerPostChecks); trustManagerPostChecks);
@ -244,7 +244,7 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
}; };
final BiConsumer<X509ExtendedTrustManager, SSLConfiguration> trustManagerPostChecks = (updatedTrustManager, config) -> { final BiConsumer<X509ExtendedTrustManager, SSLConfiguration> trustManagerPostChecks = (updatedTrustManager, config) -> {
assertThat(trustedCount.get() - updatedTrustManager.getAcceptedIssuers().length, is(5)); assertThat(trustedCount.get() - updatedTrustManager.getAcceptedIssuers().length, is(6));
}; };
validateTrustConfigurationIsReloaded(settings, env, trustManagerPreChecks, modifier, trustManagerPostChecks); validateTrustConfigurationIsReloaded(settings, env, trustManagerPreChecks, modifier, trustManagerPostChecks);

View File

@ -485,7 +485,7 @@ public class SSLServiceTests extends ESTestCase {
final SSLService sslService = new SSLService(settings, env); final SSLService sslService = new SSLService(settings, env);
final List<CertificateInfo> certificates = new ArrayList<>(sslService.getLoadedCertificates()); final List<CertificateInfo> certificates = new ArrayList<>(sslService.getLoadedCertificates());
assertThat(certificates, iterableWithSize(7)); assertThat(certificates, iterableWithSize(8));
Collections.sort(certificates, Collections.sort(certificates,
Comparator.comparing((CertificateInfo c) -> c.alias() == null ? "" : c.alias()).thenComparing(CertificateInfo::path)); Comparator.comparing((CertificateInfo c) -> c.alias() == null ? "" : c.alias()).thenComparing(CertificateInfo::path));
@ -508,6 +508,15 @@ public class SSLServiceTests extends ESTestCase {
assertThat(cert.expiry(), equalTo(DateTime.parse("2029-08-27T16:32:42Z"))); assertThat(cert.expiry(), equalTo(DateTime.parse("2029-08-27T16:32:42Z")));
assertThat(cert.hasPrivateKey(), equalTo(false)); assertThat(cert.hasPrivateKey(), equalTo(false));
cert = iterator.next();
assertThat(cert.alias(), equalTo("mykey"));
assertThat(cert.path(), equalTo(jksPath.toString()));
assertThat(cert.format(), equalTo("jks"));
assertThat(cert.serialNumber(), equalTo("3151a81eec8d4e34c56a8466a8510bcfbe63cc31"));
assertThat(cert.subjectDn(), equalTo("CN=samba4"));
assertThat(cert.expiry(), equalTo(DateTime.parse("2021-02-14T17:49:11.000Z")));
assertThat(cert.hasPrivateKey(), equalTo(false));
cert = iterator.next(); cert = iterator.next();
assertThat(cert.alias(), equalTo("openldap")); assertThat(cert.alias(), equalTo("openldap"));
assertThat(cert.path(), equalTo(jksPath.toString())); assertThat(cert.path(), equalTo(jksPath.toString()));

View File

@ -62,6 +62,8 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
final DownLevelADAuthenticator downLevelADAuthenticator; final DownLevelADAuthenticator downLevelADAuthenticator;
final UpnADAuthenticator upnADAuthenticator; final UpnADAuthenticator upnADAuthenticator;
private final int ldapPort;
ActiveDirectorySessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool) throws LDAPException { ActiveDirectorySessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool) throws LDAPException {
super(config, sslService, new ActiveDirectoryGroupsResolver(config.settings()), super(config, sslService, new ActiveDirectoryGroupsResolver(config.settings()),
ActiveDirectorySessionFactorySettings.POOL_ENABLED, () -> { ActiveDirectorySessionFactorySettings.POOL_ENABLED, () -> {
@ -88,10 +90,15 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
+ "] setting for active directory"); + "] setting for active directory");
} }
String domainDN = buildDnFromDomain(domainName); String domainDN = buildDnFromDomain(domainName);
ldapPort = ActiveDirectorySessionFactorySettings.AD_LDAP_PORT_SETTING.get(settings);
final int ldapsPort = ActiveDirectorySessionFactorySettings.AD_LDAPS_PORT_SETTING.get(settings);
final int gcLdapPort = ActiveDirectorySessionFactorySettings.AD_GC_LDAP_PORT_SETTING.get(settings);
final int gcLdapsPort = ActiveDirectorySessionFactorySettings.AD_GC_LDAPS_PORT_SETTING.get(settings);
defaultADAuthenticator = new DefaultADAuthenticator(config, timeout, ignoreReferralErrors, logger, groupResolver, defaultADAuthenticator = new DefaultADAuthenticator(config, timeout, ignoreReferralErrors, logger, groupResolver,
metaDataResolver, domainDN, threadPool); metaDataResolver, domainDN, threadPool);
downLevelADAuthenticator = new DownLevelADAuthenticator(config, timeout, ignoreReferralErrors, logger, groupResolver, downLevelADAuthenticator = new DownLevelADAuthenticator(config, timeout, ignoreReferralErrors, logger, groupResolver,
metaDataResolver, domainDN, sslService, threadPool); metaDataResolver, domainDN, sslService, threadPool, ldapPort, ldapsPort, gcLdapPort, gcLdapsPort);
upnADAuthenticator = new UpnADAuthenticator(config, timeout, ignoreReferralErrors, logger, groupResolver, upnADAuthenticator = new UpnADAuthenticator(config, timeout, ignoreReferralErrors, logger, groupResolver,
metaDataResolver, domainDN, threadPool); metaDataResolver, domainDN, threadPool);
@ -99,7 +106,8 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
@Override @Override
protected List<String> getDefaultLdapUrls(Settings settings) { protected List<String> getDefaultLdapUrls(Settings settings) {
return Collections.singletonList("ldap://" + settings.get(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING) + ":389"); return Collections.singletonList("ldap://" + settings.get(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING) +
":" + ldapPort);
} }
@Override @Override
@ -361,16 +369,24 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
final Settings settings; final Settings settings;
final SSLService sslService; final SSLService sslService;
final RealmConfig config; final RealmConfig config;
private final int ldapPort;
private final int ldapsPort;
private final int gcLdapPort;
private final int gcLdapsPort;
DownLevelADAuthenticator(RealmConfig config, TimeValue timeout, boolean ignoreReferralErrors, Logger logger, DownLevelADAuthenticator(RealmConfig config, TimeValue timeout, boolean ignoreReferralErrors, Logger logger,
GroupsResolver groupsResolver, LdapMetaDataResolver metaDataResolver, String domainDN, SSLService sslService, GroupsResolver groupsResolver, LdapMetaDataResolver metaDataResolver, String domainDN, SSLService sslService,
ThreadPool threadPool) { ThreadPool threadPool, int ldapPort, int ldapsPort, int gcLdapPort, int gcLdapsPort) {
super(config, timeout, ignoreReferralErrors, logger, groupsResolver, metaDataResolver, domainDN, super(config, timeout, ignoreReferralErrors, logger, groupsResolver, metaDataResolver, domainDN,
ActiveDirectorySessionFactorySettings.AD_DOWN_LEVEL_USER_SEARCH_FILTER_SETTING, DOWN_LEVEL_FILTER, threadPool); ActiveDirectorySessionFactorySettings.AD_DOWN_LEVEL_USER_SEARCH_FILTER_SETTING, DOWN_LEVEL_FILTER, threadPool);
this.domainDN = domainDN; this.domainDN = domainDN;
this.settings = config.settings(); this.settings = config.settings();
this.sslService = sslService; this.sslService = sslService;
this.config = config; this.config = config;
this.ldapPort = ldapPort;
this.ldapsPort = ldapsPort;
this.gcLdapPort = gcLdapPort;
this.gcLdapsPort = gcLdapsPort;
} }
@Override @Override
@ -400,7 +416,8 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
if (cachedName != null) { if (cachedName != null) {
listener.onResponse(cachedName); listener.onResponse(cachedName);
} else if (usingGlobalCatalog(ldapInterface) == false) { } else if (usingGlobalCatalog(ldapInterface) == false) {
search(ldapInterface, domainDN, LdapSearchScope.SUB_TREE.scope(), filter, timeLimitSeconds, ignoreReferralErrors, search(ldapInterface, "CN=Configuration," + domainDN, LdapSearchScope.SUB_TREE.scope(), filter, timeLimitSeconds,
ignoreReferralErrors,
ActionListener.wrap((results) -> handleSearchResults(results, netBiosDomainName, domainNameCache, listener), ActionListener.wrap((results) -> handleSearchResults(results, netBiosDomainName, domainNameCache, listener),
listener::onFailure), listener::onFailure),
"ncname"); "ncname");
@ -417,7 +434,8 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
final LDAPConnection finalLdapConnection = ldapConnection; final LDAPConnection finalLdapConnection = ldapConnection;
final LDAPConnection searchConnection = LdapUtils.privilegedConnect( final LDAPConnection searchConnection = LdapUtils.privilegedConnect(
() -> new LDAPConnection(finalLdapConnection.getSocketFactory(), connectionOptions(config, sslService, logger), () -> new LDAPConnection(finalLdapConnection.getSocketFactory(), connectionOptions(config, sslService, logger),
finalLdapConnection.getConnectedAddress(), finalLdapConnection.getSSLSession() != null ? 636 : 389)); finalLdapConnection.getConnectedAddress(),
finalLdapConnection.getSSLSession() != null ? ldapsPort : ldapPort));
final byte[] passwordBytes = CharArrays.toUtf8Bytes(password.getChars()); final byte[] passwordBytes = CharArrays.toUtf8Bytes(password.getChars());
final SimpleBindRequest bind = bindDN.isEmpty() final SimpleBindRequest bind = bindDN.isEmpty()
? new SimpleBindRequest(username, passwordBytes) ? new SimpleBindRequest(username, passwordBytes)
@ -425,8 +443,8 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
LdapUtils.maybeForkThenBind(searchConnection, bind, threadPool, new ActionRunnable<String>(listener) { LdapUtils.maybeForkThenBind(searchConnection, bind, threadPool, new ActionRunnable<String>(listener) {
@Override @Override
protected void doRun() throws Exception { protected void doRun() throws Exception {
search(searchConnection, domainDN, LdapSearchScope.SUB_TREE.scope(), filter, timeLimitSeconds, search(searchConnection, "CN=Configuration," + domainDN, LdapSearchScope.SUB_TREE.scope(), filter,
ignoreReferralErrors, timeLimitSeconds, ignoreReferralErrors,
ActionListener.wrap( ActionListener.wrap(
results -> { results -> {
IOUtils.close(searchConnection); IOUtils.close(searchConnection);
@ -473,7 +491,7 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
} }
} }
static boolean usingGlobalCatalog(LDAPInterface ldap) throws LDAPException { boolean usingGlobalCatalog(LDAPInterface ldap) throws LDAPException {
if (ldap instanceof LDAPConnection) { if (ldap instanceof LDAPConnection) {
return usingGlobalCatalog((LDAPConnection) ldap); return usingGlobalCatalog((LDAPConnection) ldap);
} else { } else {
@ -490,8 +508,8 @@ class ActiveDirectorySessionFactory extends PoolingSessionFactory {
} }
} }
private static boolean usingGlobalCatalog(LDAPConnection ldapConnection) { private boolean usingGlobalCatalog(LDAPConnection ldapConnection) {
return ldapConnection.getConnectedPort() == 3268 || ldapConnection.getConnectedPort() == 3269; return ldapConnection.getConnectedPort() == gcLdapPort || ldapConnection.getConnectedPort() == gcLdapsPort;
} }
} }

View File

@ -13,7 +13,6 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.util.concurrent.UncategorizedExecutionException; import org.elasticsearch.common.util.concurrent.UncategorizedExecutionException;
import org.elasticsearch.env.TestEnvironment; import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.test.junit.annotations.Network;
import org.elasticsearch.threadpool.TestThreadPool; import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.core.security.authc.RealmConfig; import org.elasticsearch.xpack.core.security.authc.RealmConfig;
@ -28,12 +27,10 @@ import org.junit.Before;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.lessThan;
public class LdapSessionFactoryTests extends LdapTestCase { public class LdapSessionFactoryTests extends LdapTestCase {
private Settings globalSettings; private Settings globalSettings;

View File

@ -44,7 +44,7 @@ import java.util.Objects;
import static org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING; import static org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING;
import static org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings.URLS_SETTING; import static org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings.URLS_SETTING;
//
public abstract class LdapTestCase extends ESTestCase { public abstract class LdapTestCase extends ESTestCase {
private static final String USER_DN_TEMPLATES_SETTING_KEY = LdapSessionFactorySettings.USER_DN_TEMPLATES_SETTING.getKey(); private static final String USER_DN_TEMPLATES_SETTING_KEY = LdapSessionFactorySettings.USER_DN_TEMPLATES_SETTING.getKey();
@ -120,8 +120,7 @@ public abstract class LdapTestCase extends ESTestCase {
.put(SessionFactorySettings.TIMEOUT_TCP_CONNECTION_SETTING, TimeValue.timeValueSeconds(1L)) .put(SessionFactorySettings.TIMEOUT_TCP_CONNECTION_SETTING, TimeValue.timeValueSeconds(1L))
.put(SessionFactorySettings.IGNORE_REFERRAL_ERRORS_SETTING.getKey(), ignoreReferralErrors) .put(SessionFactorySettings.IGNORE_REFERRAL_ERRORS_SETTING.getKey(), ignoreReferralErrors)
.put("group_search.base_dn", groupSearchBase) .put("group_search.base_dn", groupSearchBase)
.put("group_search.scope", scope) .put("group_search.scope", scope);
.put("ssl.verification_mode", VerificationMode.CERTIFICATE);
if (serverSetType != null) { if (serverSetType != null) {
builder.put(LdapLoadBalancingSettings.LOAD_BALANCE_SETTINGS + "." + builder.put(LdapLoadBalancingSettings.LOAD_BALANCE_SETTINGS + "." +
LdapLoadBalancingSettings.LOAD_BALANCE_TYPE_SETTING, serverSetType.toString()); LdapLoadBalancingSettings.LOAD_BALANCE_TYPE_SETTING, serverSetType.toString());

View File

@ -21,7 +21,7 @@ import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class SearchGroupsResolverTests extends GroupsResolverTestCase { public class SearchGroupsResolverTests extends GroupsResolverTestCase {
private static final String BRUCE_BANNER_DN = "uid=hulk,ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; private static final String BRUCE_BANNER_DN = "uid=hulk,ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";

View File

@ -1,3 +1,7 @@
Project smbFixtureProject = xpackProject("test:smb-fixture")
evaluationDependsOn(smbFixtureProject.path)
apply plugin: 'elasticsearch.vagrantsupport'
apply plugin: 'elasticsearch.standalone-test' apply plugin: 'elasticsearch.standalone-test'
dependencies { dependencies {
@ -5,10 +9,11 @@ dependencies {
testCompile project(path: xpackModule('security'), configuration: 'testArtifacts') testCompile project(path: xpackModule('security'), configuration: 'testArtifacts')
} }
// add test resources from security, so certificate tool tests can use example certs // add test resources from security, so tests can use example certs
sourceSets.test.resources.srcDirs(project(xpackModule('security')).sourceSets.test.resources.srcDirs) sourceSets.test.resources.srcDirs(project(xpackModule('security')).sourceSets.test.resources.srcDirs)
compileTestJava.options.compilerArgs << "-Xlint:-deprecation,-rawtypes,-serial,-try,-unchecked"
// we have to repeate these patterns because the security test resources are effectively in the src of this project // we have to repeat these patterns because the security test resources are effectively in the src of this project
forbiddenPatterns { forbiddenPatterns {
exclude '**/*.key' exclude '**/*.key'
exclude '**/*.p12' exclude '**/*.p12'
@ -21,7 +26,22 @@ test {
* other if we allow them to set the number of available processors as it's set-once in Netty. * other if we allow them to set the number of available processors as it's set-once in Netty.
*/ */
systemProperty 'es.set.netty.runtime.available.processors', 'false' systemProperty 'es.set.netty.runtime.available.processors', 'false'
include '**/*IT.class'
include '**/*Tests.class'
} }
// these are just tests, no need to audit // these are just tests, no need to audit
thirdPartyAudit.enabled = false thirdPartyAudit.enabled = false
task smbFixture {
dependsOn "vagrantCheckVersion", "virtualboxCheckVersion", smbFixtureProject.up
}
if (project.rootProject.vagrantSupported) {
if (project.hasProperty('useExternalAD') == false) {
test.dependsOn smbFixture
test.finalizedBy smbFixtureProject.halt
}
} else {
test.enabled = false
}

View File

@ -5,7 +5,7 @@
*/ */
package org.elasticsearch.xpack.security.authc.ldap; package org.elasticsearch.xpack.security.authc.ldap;
import com.unboundid.ldap.sdk.LDAPException; import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.MockSecureSettings;
import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.SecureString;
@ -13,7 +13,6 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.env.TestEnvironment; import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.test.junit.annotations.Network;
import org.elasticsearch.threadpool.TestThreadPool; import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.core.security.authc.RealmConfig; import org.elasticsearch.xpack.core.security.authc.RealmConfig;
@ -21,17 +20,19 @@ import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope;
import org.elasticsearch.xpack.core.ssl.SSLService; import org.elasticsearch.xpack.core.ssl.SSLService;
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession; import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession;
import org.elasticsearch.xpack.security.authc.ldap.support.LdapTestCase; import org.elasticsearch.xpack.security.authc.ldap.support.LdapTestCase;
import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.Objects;
import static org.elasticsearch.xpack.security.authc.ldap.LdapUserSearchSessionFactoryTests.getLdapUserSearchSessionFactory;
import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasItems;
public class ActiveDirectoryUserSearchSessionFactoryTests extends LdapTestCase { public class ADLdapUserSearchSessionFactoryTests extends AbstractActiveDirectoryTestCase {
private SSLService sslService; private SSLService sslService;
private Settings globalSettings; private Settings globalSettings;
@ -53,7 +54,7 @@ public class ActiveDirectoryUserSearchSessionFactoryTests extends LdapTestCase {
.setSecureSettings(newSecureSettings("xpack.ssl.truststore.secure_password", "changeit")) .setSecureSettings(newSecureSettings("xpack.ssl.truststore.secure_password", "changeit"))
.build(); .build();
sslService = new SSLService(globalSettings, env); sslService = new SSLService(globalSettings, env);
threadPool = new TestThreadPool("LdapUserSearchSessionFactoryTests"); threadPool = new TestThreadPool("ADLdapUserSearchSessionFactoryTests");
} }
@After @After
@ -61,8 +62,12 @@ public class ActiveDirectoryUserSearchSessionFactoryTests extends LdapTestCase {
terminate(threadPool); terminate(threadPool);
} }
@Network private MockSecureSettings newSecureSettings(String key, String value) {
@SuppressWarnings("unchecked") MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString(key, value);
return secureSettings;
}
public void testUserSearchWithActiveDirectory() throws Exception { public void testUserSearchWithActiveDirectory() throws Exception {
String groupSearchBase = "DC=ad,DC=test,DC=elasticsearch,DC=com"; String groupSearchBase = "DC=ad,DC=test,DC=elasticsearch,DC=com";
String userSearchBase = "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com"; String userSearchBase = "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com";
@ -76,6 +81,7 @@ public class ActiveDirectoryUserSearchSessionFactoryTests extends LdapTestCase {
.put("bind_password", ActiveDirectorySessionFactoryTests.PASSWORD) .put("bind_password", ActiveDirectorySessionFactoryTests.PASSWORD)
.put("user_search.filter", "(cn={0})") .put("user_search.filter", "(cn={0})")
.put("user_search.pool.enabled", randomBoolean()) .put("user_search.pool.enabled", randomBoolean())
.put("follow_referrals", ActiveDirectorySessionFactoryTests.FOLLOW_REFERRALS)
.build(); .build();
Settings.Builder builder = Settings.builder() Settings.Builder builder = Settings.builder()
.put(globalSettings); .put(globalSettings);
@ -85,8 +91,8 @@ public class ActiveDirectoryUserSearchSessionFactoryTests extends LdapTestCase {
}); });
Settings fullSettings = builder.build(); Settings fullSettings = builder.build();
sslService = new SSLService(fullSettings, TestEnvironment.newEnvironment(fullSettings)); sslService = new SSLService(fullSettings, TestEnvironment.newEnvironment(fullSettings));
RealmConfig config = new RealmConfig("ad-as-ldap-test", settings, globalSettings, RealmConfig config = new RealmConfig("ad-as-ldap-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings)); new ThreadContext(globalSettings));
LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool); LdapUserSearchSessionFactory sessionFactory = getLdapUserSearchSessionFactory(config, sslService, threadPool);
String user = "Bruce Banner"; String user = "Bruce Banner";
@ -119,20 +125,27 @@ public class ActiveDirectoryUserSearchSessionFactoryTests extends LdapTestCase {
} }
} }
static LdapUserSearchSessionFactory getLdapUserSearchSessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool) @Override
throws LDAPException { protected boolean enableWarningsCheck() {
LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService, threadPool); return false;
if (sessionFactory.getConnectionPool() != null) {
// don't use this in production
// used here to catch bugs that might get masked by an automatic retry
sessionFactory.getConnectionPool().setRetryFailedOperationsDueToInvalidConnections(false);
}
return sessionFactory;
} }
private MockSecureSettings newSecureSettings(String key, String value) { private LdapSession session(SessionFactory factory, String username, SecureString password) {
MockSecureSettings secureSettings = new MockSecureSettings(); PlainActionFuture<LdapSession> future = new PlainActionFuture<>();
secureSettings.setString(key, value); factory.session(username, password, future);
return secureSettings; return future.actionGet();
}
private List<String> groups(LdapSession ldapSession) {
Objects.requireNonNull(ldapSession);
PlainActionFuture<List<String>> future = new PlainActionFuture<>();
ldapSession.groups(future);
return future.actionGet();
}
private LdapSession unauthenticatedSession(SessionFactory factory, String username) {
PlainActionFuture<LdapSession> future = new PlainActionFuture<>();
factory.unauthenticatedSession(username, future);
return future.actionGet();
} }
} }

View File

@ -11,11 +11,11 @@ import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPInterface; import com.unboundid.ldap.sdk.LDAPInterface;
import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.common.Booleans;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.env.TestEnvironment; import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.junit.annotations.Network;
import org.elasticsearch.xpack.core.security.authc.ldap.ActiveDirectorySessionFactorySettings; import org.elasticsearch.xpack.core.security.authc.ldap.ActiveDirectorySessionFactorySettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope; import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope;
import org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings; import org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings;
@ -27,11 +27,22 @@ import java.nio.file.Path;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
@Network public abstract class AbstractActiveDirectoryTestCase extends ESTestCase {
public class AbstractActiveDirectoryIntegTests extends ESTestCase {
public static final String AD_LDAP_URL = "ldaps://54.213.145.20:636"; // follow referrals defaults to false here which differs from the default value of the setting
public static final String PASSWORD = "NickFuryHeartsES"; // this is needed to prevent test logs being filled by errors as the default configuration of
// the tests run against a vagrant samba4 instance configured as a domain controller with the
// ports mapped into the ephemeral port range and there is the possibility of incorrect results
// as we cannot control the URL of the referral which may contain a non-resolvable DNS name as
// this name would be served by the samba4 instance
public static final Boolean FOLLOW_REFERRALS = Booleans.parseBoolean(getFromEnv("TESTS_AD_FOLLOW_REFERRALS", "false"));
public static final String AD_LDAP_URL = getFromEnv("TESTS_AD_LDAP_URL", "ldaps://localhost:61636");
public static final String AD_LDAP_GC_URL = getFromEnv("TESTS_AD_LDAP_GC_URL", "ldaps://localhost:63269");
public static final String PASSWORD = getFromEnv("TESTS_AD_USER_PASSWORD", "Passw0rd");
public static final String AD_LDAP_PORT = getFromEnv("TESTS_AD_LDAP_PORT", "61389");
public static final String AD_LDAPS_PORT = getFromEnv("TESTS_AD_LDAPS_PORT", "61636");
public static final String AD_GC_LDAP_PORT = getFromEnv("TESTS_AD_GC_LDAP_PORT", "63268");
public static final String AD_GC_LDAPS_PORT = getFromEnv("TESTS_AD_GC_LDAPS_PORT", "63269");
public static final String AD_DOMAIN = "ad.test.elasticsearch.com"; public static final String AD_DOMAIN = "ad.test.elasticsearch.com";
protected SSLService sslService; protected SSLService sslService;
@ -76,7 +87,12 @@ public class AbstractActiveDirectoryIntegTests extends ESTestCase {
.putList(SessionFactorySettings.URLS_SETTING, ldapUrl) .putList(SessionFactorySettings.URLS_SETTING, ldapUrl)
.put(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING, adDomainName) .put(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING, adDomainName)
.put(ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_BASEDN_SETTING, userSearchDN) .put(ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_BASEDN_SETTING, userSearchDN)
.put(ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_SCOPE_SETTING, scope); .put(ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_SCOPE_SETTING, scope)
.put(ActiveDirectorySessionFactorySettings.AD_LDAP_PORT_SETTING.getKey(), AD_LDAP_PORT)
.put(ActiveDirectorySessionFactorySettings.AD_LDAPS_PORT_SETTING.getKey(), AD_LDAPS_PORT)
.put(ActiveDirectorySessionFactorySettings.AD_GC_LDAP_PORT_SETTING.getKey(), AD_GC_LDAP_PORT)
.put(ActiveDirectorySessionFactorySettings.AD_GC_LDAPS_PORT_SETTING.getKey(), AD_GC_LDAPS_PORT)
.put("follow_referrals", FOLLOW_REFERRALS);
if (randomBoolean()) { if (randomBoolean()) {
builder.put("ssl.verification_mode", hostnameVerification ? VerificationMode.FULL : VerificationMode.CERTIFICATE); builder.put("ssl.verification_mode", hostnameVerification ? VerificationMode.FULL : VerificationMode.CERTIFICATE);
} else { } else {
@ -109,4 +125,9 @@ public class AbstractActiveDirectoryIntegTests extends ESTestCase {
} }
}); });
} }
private static String getFromEnv(String envVar, String defaultValue) {
final String value = System.getenv(envVar);
return value == null ? defaultValue : value;
}
} }

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.integration.ldap; package org.elasticsearch.xpack.security.authc.ldap;
import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.ActionFuture; import org.elasticsearch.action.ActionFuture;
@ -25,6 +25,7 @@ import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.xpack.core.security.SecurityLifecycleServiceField; import org.elasticsearch.xpack.core.security.SecurityLifecycleServiceField;
import org.elasticsearch.xpack.core.security.action.rolemapping.PutRoleMappingRequestBuilder; import org.elasticsearch.xpack.core.security.action.rolemapping.PutRoleMappingRequestBuilder;
import org.elasticsearch.xpack.core.security.action.rolemapping.PutRoleMappingResponse; import org.elasticsearch.xpack.core.security.action.rolemapping.PutRoleMappingResponse;
import org.elasticsearch.xpack.core.security.authc.ldap.ActiveDirectorySessionFactorySettings;
import org.elasticsearch.xpack.core.security.authc.ldap.LdapRealmSettings; import org.elasticsearch.xpack.core.security.authc.ldap.LdapRealmSettings;
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken; import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.core.security.client.SecurityClient; import org.elasticsearch.xpack.core.security.client.SecurityClient;
@ -53,6 +54,10 @@ import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope.ONE_LEVEL; import static org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope.ONE_LEVEL;
import static org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope.SUB_TREE; import static org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope.SUB_TREE;
import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.BASIC_AUTH_HEADER; import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.BASIC_AUTH_HEADER;
import static org.elasticsearch.xpack.security.authc.ldap.AbstractActiveDirectoryTestCase.AD_GC_LDAPS_PORT;
import static org.elasticsearch.xpack.security.authc.ldap.AbstractActiveDirectoryTestCase.AD_GC_LDAP_PORT;
import static org.elasticsearch.xpack.security.authc.ldap.AbstractActiveDirectoryTestCase.AD_LDAPS_PORT;
import static org.elasticsearch.xpack.security.authc.ldap.AbstractActiveDirectoryTestCase.AD_LDAP_PORT;
import static org.elasticsearch.xpack.security.test.SecurityTestUtils.writeFile; import static org.elasticsearch.xpack.security.test.SecurityTestUtils.writeFile;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
@ -63,7 +68,7 @@ import static org.hamcrest.Matchers.equalTo;
public abstract class AbstractAdLdapRealmTestCase extends SecurityIntegTestCase { public abstract class AbstractAdLdapRealmTestCase extends SecurityIntegTestCase {
public static final String XPACK_SECURITY_AUTHC_REALMS_EXTERNAL = "xpack.security.authc.realms.external"; public static final String XPACK_SECURITY_AUTHC_REALMS_EXTERNAL = "xpack.security.authc.realms.external";
public static final String PASSWORD = "NickFuryHeartsES"; public static final String PASSWORD = AbstractActiveDirectoryTestCase.PASSWORD;
public static final String ASGARDIAN_INDEX = "gods"; public static final String ASGARDIAN_INDEX = "gods";
public static final String PHILANTHROPISTS_INDEX = "philanthropists"; public static final String PHILANTHROPISTS_INDEX = "philanthropists";
public static final String SECURITY_INDEX = "security"; public static final String SECURITY_INDEX = "security";
@ -119,43 +124,39 @@ public abstract class AbstractAdLdapRealmTestCase extends SecurityIntegTestCase
final RealmConfig realm = AbstractAdLdapRealmTestCase.realmConfig; final RealmConfig realm = AbstractAdLdapRealmTestCase.realmConfig;
Path store = getDataPath(TESTNODE_KEYSTORE); Path store = getDataPath(TESTNODE_KEYSTORE);
Settings.Builder builder = Settings.builder(); Settings.Builder builder = Settings.builder();
if (useGlobalSSL) { // don't use filter since it returns a prefixed secure setting instead of mock!
// don't use filter since it returns a prefixed secure setting instead of mock! Settings settingsToAdd = super.nodeSettings(nodeOrdinal);
Settings settingsToAdd = super.nodeSettings(nodeOrdinal); builder.put(settingsToAdd.filter(k -> k.startsWith("xpack.ssl.") == false), false);
builder.put(settingsToAdd.filter(k -> k.startsWith("xpack.ssl.") == false), false); MockSecureSettings mockSecureSettings = (MockSecureSettings) Settings.builder().put(settingsToAdd).getSecureSettings();
MockSecureSettings mockSecureSettings = (MockSecureSettings) Settings.builder().put(settingsToAdd).getSecureSettings(); if (mockSecureSettings != null) {
if (mockSecureSettings != null) { MockSecureSettings filteredSecureSettings = new MockSecureSettings();
MockSecureSettings filteredSecureSettings = new MockSecureSettings(); builder.setSecureSettings(filteredSecureSettings);
builder.setSecureSettings(filteredSecureSettings); for (String secureSetting : mockSecureSettings.getSettingNames()) {
for (String secureSetting : mockSecureSettings.getSettingNames()) { if (secureSetting.startsWith("xpack.ssl.") == false) {
if (secureSetting.startsWith("xpack.ssl.") == false) { SecureString secureString = mockSecureSettings.getString(secureSetting);
SecureString secureString = mockSecureSettings.getString(secureSetting); if (secureString == null) {
if (secureString == null) { final byte[] fileBytes;
final byte[] fileBytes; try (InputStream in = mockSecureSettings.getFile(secureSetting);
try (InputStream in = mockSecureSettings.getFile(secureSetting); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) { int numRead;
int numRead; byte[] bytes = new byte[1024];
byte[] bytes = new byte[1024]; while ((numRead = in.read(bytes)) != -1) {
while ((numRead = in.read(bytes)) != -1) { byteArrayOutputStream.write(bytes, 0, numRead);
byteArrayOutputStream.write(bytes, 0, numRead);
}
byteArrayOutputStream.flush();
fileBytes = byteArrayOutputStream.toByteArray();
} catch (IOException e) {
throw new UncheckedIOException(e);
} }
byteArrayOutputStream.flush();
filteredSecureSettings.setFile(secureSetting, fileBytes); fileBytes = byteArrayOutputStream.toByteArray();
} else { } catch (IOException e) {
filteredSecureSettings.setString(secureSetting, new String(secureString.getChars())); throw new UncheckedIOException(e);
} }
filteredSecureSettings.setFile(secureSetting, fileBytes);
} else {
filteredSecureSettings.setString(secureSetting, new String(secureString.getChars()));
} }
} }
} }
addSslSettingsForStore(builder, store, "testnode");
} else {
builder.put(super.nodeSettings(nodeOrdinal));
} }
addSslSettingsForStore(builder, store, "testnode");
builder.put(buildRealmSettings(realm, roleMappings, store)); builder.put(buildRealmSettings(realm, roleMappings, store));
return builder.build(); return builder.build();
} }
@ -376,39 +377,44 @@ public abstract class AbstractAdLdapRealmTestCase extends SecurityIntegTestCase
AD(false, AD_ROLE_MAPPING, AD(false, AD_ROLE_MAPPING,
Settings.builder() Settings.builder()
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".type", LdapRealmSettings.AD_TYPE) .put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".type", LdapRealmSettings.AD_TYPE)
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".domain_name", "ad.test.elasticsearch.com") .put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".domain_name", ActiveDirectorySessionFactoryTests.AD_DOMAIN)
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL .put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL
+ ".group_search.base_dn", "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com") + ".group_search.base_dn", "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com")
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".group_search.scope", randomBoolean() ? SUB_TREE : ONE_LEVEL) .put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".group_search.scope", randomBoolean() ? SUB_TREE : ONE_LEVEL)
.build()), .put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".url", ActiveDirectorySessionFactoryTests.AD_LDAP_URL)
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".follow_referrals",
AD_SSL(false, AD_ROLE_MAPPING, ActiveDirectorySessionFactoryTests.FOLLOW_REFERRALS)
Settings.builder() .put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + "." +
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".type", LdapRealmSettings.AD_TYPE) ActiveDirectorySessionFactorySettings.AD_LDAP_PORT_SETTING.getKey(), AD_LDAP_PORT)
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".domain_name", "ad.test.elasticsearch.com") .put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + "." +
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL ActiveDirectorySessionFactorySettings.AD_LDAPS_PORT_SETTING.getKey(), AD_LDAPS_PORT)
+ ".group_search.base_dn", "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com") .put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + "." +
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".group_search.scope", randomBoolean() ? SUB_TREE : ONE_LEVEL) ActiveDirectorySessionFactorySettings.AD_GC_LDAP_PORT_SETTING.getKey(), AD_GC_LDAP_PORT)
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".url", "ldap://ad.test.elasticsearch.com:389") .put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + "." +
ActiveDirectorySessionFactorySettings.AD_GC_LDAPS_PORT_SETTING.getKey(), AD_GC_LDAPS_PORT)
.build()), .build()),
AD_LDAP_GROUPS_FROM_SEARCH(true, AD_ROLE_MAPPING, AD_LDAP_GROUPS_FROM_SEARCH(true, AD_ROLE_MAPPING,
Settings.builder() Settings.builder()
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".type", LdapRealmSettings.LDAP_TYPE) .put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".type", LdapRealmSettings.LDAP_TYPE)
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".url", "ldaps://ad.test.elasticsearch.com:636") .put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".url", ActiveDirectorySessionFactoryTests.AD_LDAP_URL)
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL .put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL
+ ".group_search.base_dn", "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com") + ".group_search.base_dn", "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com")
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".group_search.scope", randomBoolean() ? SUB_TREE : ONE_LEVEL) .put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".group_search.scope", randomBoolean() ? SUB_TREE : ONE_LEVEL)
.putList(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".user_dn_templates", .putList(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".user_dn_templates",
"cn={0},CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com") "cn={0},CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com")
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".follow_referrals",
ActiveDirectorySessionFactoryTests.FOLLOW_REFERRALS)
.build()), .build()),
AD_LDAP_GROUPS_FROM_ATTRIBUTE(true, AD_ROLE_MAPPING, AD_LDAP_GROUPS_FROM_ATTRIBUTE(true, AD_ROLE_MAPPING,
Settings.builder() Settings.builder()
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".type", LdapRealmSettings.LDAP_TYPE) .put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".type", LdapRealmSettings.LDAP_TYPE)
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".url", "ldaps://ad.test.elasticsearch.com:636") .put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".url", ActiveDirectorySessionFactoryTests.AD_LDAP_URL)
.putList(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".user_dn_templates", .putList(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".user_dn_templates",
"cn={0},CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com") "cn={0},CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com")
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".follow_referrals",
ActiveDirectorySessionFactoryTests.FOLLOW_REFERRALS)
.build()); .build());
final boolean mapGroupsAsRoles; final boolean mapGroupsAsRoles;

View File

@ -9,9 +9,9 @@ import com.unboundid.ldap.sdk.Filter;
import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.test.junit.annotations.Network;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope; import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope;
import org.elasticsearch.xpack.core.security.support.NoOpLogger; import org.elasticsearch.xpack.core.security.support.NoOpLogger;
import org.junit.Before;
import java.util.List; import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -21,12 +21,16 @@ import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@Network
public class ActiveDirectoryGroupsResolverTests extends GroupsResolverTestCase { public class ActiveDirectoryGroupsResolverTests extends GroupsResolverTestCase {
private static final String BRUCE_BANNER_DN = private static final String BRUCE_BANNER_DN =
"cn=Bruce Banner,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com"; "cn=Bruce Banner,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com";
@Before
public void setReferralFollowing() {
ldapConnection.getConnectionOptions().setFollowReferrals(AbstractActiveDirectoryTestCase.FOLLOW_REFERRALS);
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void testResolveSubTree() throws Exception { public void testResolveSubTree() throws Exception {
Settings settings = Settings.builder() Settings settings = Settings.builder()
@ -76,7 +80,6 @@ public class ActiveDirectoryGroupsResolverTests extends GroupsResolverTestCase {
{ {
String[] expectedSids = new String[]{ String[] expectedSids = new String[]{
"S-1-5-32-545", //Default Users group "S-1-5-32-545", //Default Users group
"S-1-5-21-3510024162-210737641-214529065-513" //Default Domain Users group
}; };
final String dn = "CN=Jarvis, CN=Users, DC=ad, DC=test, DC=elasticsearch, DC=com"; final String dn = "CN=Jarvis, CN=Users, DC=ad, DC=test, DC=elasticsearch, DC=com";
PlainActionFuture<Filter> future = new PlainActionFuture<>(); PlainActionFuture<Filter> future = new PlainActionFuture<>();
@ -89,9 +92,8 @@ public class ActiveDirectoryGroupsResolverTests extends GroupsResolverTestCase {
//test a user of one groups //test a user of one groups
{ {
String[] expectedSids = new String[]{ String[] expectedSids = new String[]{
"S-1-5-32-545", //Default Users group "S-1-5-32-545" //Default Users group
"S-1-5-21-3510024162-210737641-214529065-513", //Default Domain Users group };
"S-1-5-21-3510024162-210737641-214529065-1117"}; //Gods group
final String dn = "CN=Odin, CN=Users, DC=ad, DC=test, DC=elasticsearch, DC=com"; final String dn = "CN=Odin, CN=Users, DC=ad, DC=test, DC=elasticsearch, DC=com";
PlainActionFuture<Filter> future = new PlainActionFuture<>(); PlainActionFuture<Filter> future = new PlainActionFuture<>();
ActiveDirectoryGroupsResolver.buildGroupQuery(ldapConnection, dn, ActiveDirectoryGroupsResolver.buildGroupQuery(ldapConnection, dn,
@ -99,25 +101,6 @@ public class ActiveDirectoryGroupsResolverTests extends GroupsResolverTestCase {
Filter query = future.actionGet(); Filter query = future.actionGet();
assertValidSidQuery(query, expectedSids); assertValidSidQuery(query, expectedSids);
} }
//test a user of many groups
{
String[] expectedSids = new String[]{
"S-1-5-32-545", //Default Users Group
"S-1-5-21-3510024162-210737641-214529065-513", //Default Domain Users group
"S-1-5-21-3510024162-210737641-214529065-1123", //Supers
"S-1-5-21-3510024162-210737641-214529065-1110", //Philanthropists
"S-1-5-21-3510024162-210737641-214529065-1108", //Geniuses
"S-1-5-21-3510024162-210737641-214529065-1106", //SHIELD
"S-1-5-21-3510024162-210737641-214529065-1105"};//Avengers
final String dn = BRUCE_BANNER_DN;
PlainActionFuture<Filter> future = new PlainActionFuture<>();
ActiveDirectoryGroupsResolver.buildGroupQuery(ldapConnection, dn,
TimeValue.timeValueSeconds(10), false, future);
Filter query = future.actionGet();
assertValidSidQuery(query, expectedSids);
}
} }
private void assertValidSidQuery(Filter query, String[] expectedSids) { private void assertValidSidQuery(Filter query, String[] expectedSids) {
@ -125,7 +108,7 @@ public class ActiveDirectoryGroupsResolverTests extends GroupsResolverTestCase {
Pattern sidQueryPattern = Pattern.compile("\\(\\|(\\(objectSid=S(-\\d+)+\\))+\\)"); Pattern sidQueryPattern = Pattern.compile("\\(\\|(\\(objectSid=S(-\\d+)+\\))+\\)");
assertThat("[" + queryString + "] didn't match the search filter pattern", assertThat("[" + queryString + "] didn't match the search filter pattern",
sidQueryPattern.matcher(queryString).matches(), is(true)); sidQueryPattern.matcher(queryString).matches(), is(true));
for(String sid: expectedSids) { for (String sid: expectedSids) {
assertThat(queryString, containsString(sid)); assertThat(queryString, containsString(sid));
} }
} }

View File

@ -3,20 +3,18 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.integration.ldap; package org.elasticsearch.xpack.security.authc.ldap;
import org.elasticsearch.action.ActionFuture; import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.common.collect.MapBuilder; import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.junit.annotations.Network;
import org.elasticsearch.xpack.core.security.action.user.AuthenticateAction; 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.AuthenticateRequest;
import org.elasticsearch.xpack.core.security.action.user.AuthenticateResponse; import org.elasticsearch.xpack.core.security.action.user.AuthenticateResponse;
import org.elasticsearch.xpack.core.security.authc.AuthenticationServiceField; import org.elasticsearch.xpack.core.security.authc.AuthenticationServiceField;
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken; import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.core.security.user.ElasticUser; import org.elasticsearch.xpack.core.security.user.ElasticUser;
import org.elasticsearch.xpack.security.authc.ldap.ActiveDirectorySessionFactoryTests;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.junit.BeforeClass; import org.junit.BeforeClass;
@ -28,12 +26,11 @@ import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswo
/** /**
* This tests that "run-as" works on LDAP/AD realms * This tests that "run-as" works on LDAP/AD realms
*/ */
@Network
public class ActiveDirectoryRunAsIT extends AbstractAdLdapRealmTestCase { public class ActiveDirectoryRunAsIT extends AbstractAdLdapRealmTestCase {
@BeforeClass @BeforeClass
public static void selectRealmConfig() { public static void selectRealmConfig() {
realmConfig = randomFrom(RealmConfig.AD, RealmConfig.AD_SSL); realmConfig = RealmConfig.AD;
} }
@Override @Override
@ -41,7 +38,6 @@ public class ActiveDirectoryRunAsIT extends AbstractAdLdapRealmTestCase {
final Settings.Builder builder = Settings.builder().put(super.nodeSettings(nodeOrdinal)); final Settings.Builder builder = Settings.builder().put(super.nodeSettings(nodeOrdinal));
switch (realmConfig) { switch (realmConfig) {
case AD: case AD:
case AD_SSL:
builder.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".bind_dn", "ironman@ad.test.elasticsearch.com") 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 + ".bind_password", ActiveDirectorySessionFactoryTests.PASSWORD)
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".user_search.pool.enabled", false); .put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".user_search.pool.enabled", false);

View File

@ -13,7 +13,6 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.util.concurrent.UncategorizedExecutionException; import org.elasticsearch.common.util.concurrent.UncategorizedExecutionException;
import org.elasticsearch.env.TestEnvironment; import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.test.junit.annotations.Network;
import org.elasticsearch.threadpool.TestThreadPool; import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.core.security.authc.RealmConfig; import org.elasticsearch.xpack.core.security.authc.RealmConfig;
@ -39,8 +38,7 @@ import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@Network public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryTestCase {
public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryIntegTests {
private final SecureString SECURED_PASSWORD = new SecureString(PASSWORD); private final SecureString SECURED_PASSWORD = new SecureString(PASSWORD);
private ThreadPool threadPool; private ThreadPool threadPool;
@ -87,7 +85,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void testNetbiosAuth() throws Exception { public void testNetbiosAuth() throws Exception {
final String adUrl = randomFrom("ldap://54.213.145.20:3268", "ldaps://54.213.145.20:3269", AD_LDAP_URL); final String adUrl = randomFrom(AD_LDAP_URL, AD_LDAP_GC_URL);
RealmConfig config = new RealmConfig("ad-test", buildAdSettings(adUrl, AD_DOMAIN, false), globalSettings, RealmConfig config = new RealmConfig("ad-test", buildAdSettings(adUrl, AD_DOMAIN, false), globalSettings,
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings)); TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) { try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
@ -290,13 +288,16 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
public void testStandardLdapConnection() throws Exception { public void testStandardLdapConnection() throws Exception {
String groupSearchBase = "DC=ad,DC=test,DC=elasticsearch,DC=com"; String groupSearchBase = "DC=ad,DC=test,DC=elasticsearch,DC=com";
String userTemplate = "CN={0},CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com"; String userTemplate = "CN={0},CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com";
Settings settings = LdapTestCase.buildLdapSettings( Settings settings = Settings.builder()
new String[] { AD_LDAP_URL }, .put(LdapTestCase.buildLdapSettings(
new String[] { userTemplate }, new String[] { AD_LDAP_URL },
groupSearchBase, new String[] { userTemplate },
LdapSearchScope.SUB_TREE, groupSearchBase,
null, LdapSearchScope.SUB_TREE,
true); null,
true))
.put("follow_referrals", FOLLOW_REFERRALS)
.build();
if (useGlobalSSL == false) { if (useGlobalSSL == false) {
settings = Settings.builder() settings = Settings.builder()
.put(settings) .put(settings)
@ -387,42 +388,6 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
} }
} }
public void testAdAuthWithHostnameVerification() throws Exception {
RealmConfig config = new RealmConfig("ad-test", buildAdSettings(AD_LDAP_URL, AD_DOMAIN, true), globalSettings,
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
try (ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool)) {
String userName = "ironman";
UncategorizedExecutionException e = expectThrows(UncategorizedExecutionException.class,
() -> session(sessionFactory, userName, SECURED_PASSWORD));
assertThat(e.getCause(), instanceOf(ExecutionException.class));
assertThat(e.getCause().getCause(), instanceOf(LDAPException.class));
final LDAPException expected = (LDAPException) e.getCause().getCause();
assertThat(expected.getMessage(),
anyOf(containsString("Hostname verification failed"), containsString("peer not authenticated")));
}
}
public void testStandardLdapHostnameVerification() throws Exception {
String groupSearchBase = "DC=ad,DC=test,DC=elasticsearch,DC=com";
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("ssl.verification_mode", VerificationMode.FULL)
.build();
RealmConfig config = new RealmConfig("ad-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
String user = "Bruce Banner";
UncategorizedExecutionException e = expectThrows(UncategorizedExecutionException.class,
() -> session(sessionFactory, user, SECURED_PASSWORD));
assertThat(e.getCause(), instanceOf(ExecutionException.class));
assertThat(e.getCause().getCause(), instanceOf(LDAPException.class));
final LDAPException expected = (LDAPException) e.getCause().getCause();
assertThat(expected.getMessage(), anyOf(containsString("Hostname verification failed"), containsString("peer not authenticated")));
}
public void testADLookup() throws Exception { public void testADLookup() throws Exception {
RealmConfig config = new RealmConfig("ad-test", RealmConfig config = new RealmConfig("ad-test",
buildAdSettings(AD_LDAP_URL, AD_DOMAIN, false, true), buildAdSettings(AD_LDAP_URL, AD_DOMAIN, false, true),
@ -450,7 +415,12 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI
private Settings buildAdSettings(String ldapUrl, String adDomainName, boolean hostnameVerification, boolean useBindUser) { private Settings buildAdSettings(String ldapUrl, String adDomainName, boolean hostnameVerification, boolean useBindUser) {
Settings.Builder builder = Settings.builder() Settings.Builder builder = Settings.builder()
.put(SessionFactorySettings.URLS_SETTING, ldapUrl) .put(SessionFactorySettings.URLS_SETTING, ldapUrl)
.put(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING, adDomainName); .put(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING, adDomainName)
.put(ActiveDirectorySessionFactorySettings.AD_LDAP_PORT_SETTING.getKey(), AD_LDAP_PORT)
.put(ActiveDirectorySessionFactorySettings.AD_LDAPS_PORT_SETTING.getKey(), AD_LDAPS_PORT)
.put(ActiveDirectorySessionFactorySettings.AD_GC_LDAP_PORT_SETTING.getKey(), AD_GC_LDAP_PORT)
.put(ActiveDirectorySessionFactorySettings.AD_GC_LDAPS_PORT_SETTING.getKey(), AD_GC_LDAPS_PORT)
.put("follow_referrals", FOLLOW_REFERRALS);
if (randomBoolean()) { if (randomBoolean()) {
builder.put("ssl.verification_mode", hostnameVerification ? VerificationMode.FULL : VerificationMode.CERTIFICATE); builder.put("ssl.verification_mode", hostnameVerification ? VerificationMode.FULL : VerificationMode.CERTIFICATE);
} else { } else {

View File

@ -3,9 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.integration.ldap; package org.elasticsearch.xpack.security.authc.ldap;
import org.elasticsearch.test.junit.annotations.Network;
import java.io.IOException; import java.io.IOException;
@ -13,8 +11,7 @@ import java.io.IOException;
* This tests the group to role mappings from LDAP sources provided by the super class - available from super.realmConfig. * This tests the group to role mappings from LDAP sources provided by the super class - available from super.realmConfig.
* The super class will provide appropriate group mappings via configGroupMappings() * The super class will provide appropriate group mappings via configGroupMappings()
*/ */
@Network public class GroupMappingIT extends AbstractAdLdapRealmTestCase {
public class GroupMappingTests extends AbstractAdLdapRealmTestCase {
public void testAuthcAuthz() throws IOException { public void testAuthcAuthz() throws IOException {
String avenger = realmConfig.loginWithCommonName ? "Natasha Romanoff" : "blackwidow"; String avenger = realmConfig.loginWithCommonName ? "Natasha Romanoff" : "blackwidow";
assertAccessAllowed(avenger, "avengers"); assertAccessAllowed(avenger, "avengers");

View File

@ -3,9 +3,8 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.integration.ldap; package org.elasticsearch.xpack.security.authc.ldap;
import org.elasticsearch.test.junit.annotations.Network;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import java.io.IOException; import java.io.IOException;
@ -14,8 +13,7 @@ import java.util.ArrayList;
/** /**
* This tests the mapping of multiple groups to a role in a file based role-mapping * This tests the mapping of multiple groups to a role in a file based role-mapping
*/ */
@Network public class MultiGroupMappingIT extends AbstractAdLdapRealmTestCase {
public class MultiGroupMappingTests extends AbstractAdLdapRealmTestCase {
@BeforeClass @BeforeClass
public static void setRoleMappingType() { public static void setRoleMappingType() {

View File

@ -3,11 +3,10 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.integration.ldap; package org.elasticsearch.xpack.security.authc.ldap;
import org.elasticsearch.common.logging.ESLoggerFactory; import org.elasticsearch.common.logging.ESLoggerFactory;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.junit.annotations.Network;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import java.io.IOException; import java.io.IOException;
@ -21,8 +20,7 @@ import java.util.stream.Collectors;
* The required behaviour is that users from both realms (directory servers) can be authenticated using * The required behaviour is that users from both realms (directory servers) can be authenticated using
* just their userid (the AuthenticationService tries them in order) * just their userid (the AuthenticationService tries them in order)
*/ */
@Network public class MultipleAdRealmIT extends AbstractAdLdapRealmTestCase {
public class MultipleAdRealmTests extends AbstractAdLdapRealmTestCase {
private static RealmConfig secondaryRealmConfig; private static RealmConfig secondaryRealmConfig;

View File

@ -10,7 +10,6 @@ import com.unboundid.ldap.sdk.SearchRequest;
import com.unboundid.ldap.sdk.SearchScope; import com.unboundid.ldap.sdk.SearchScope;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.test.junit.annotations.Network;
import org.elasticsearch.xpack.core.security.support.NoOpLogger; import org.elasticsearch.xpack.core.security.support.NoOpLogger;
import org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils; import org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils;
@ -22,7 +21,6 @@ import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.hasItems;
@Network
public class UserAttributeGroupsResolverTests extends GroupsResolverTestCase { public class UserAttributeGroupsResolverTests extends GroupsResolverTestCase {
public static final String BRUCE_BANNER_DN = "cn=Bruce Banner,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com"; public static final String BRUCE_BANNER_DN = "cn=Bruce Banner,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com";

20
test/smb-fixture/Vagrantfile vendored Normal file
View File

@ -0,0 +1,20 @@
Vagrant.configure("2") do |config|
config.vm.define "test.ad.elastic.local" do |config|
config.vm.box = "elastic/ubuntu-16.04-x86_64"
end
config.vm.hostname = "ad.test.elastic.local"
if Vagrant.has_plugin?("vagrant-cachier")
config.cache.scope = :box
end
config.vm.network "forwarded_port", guest: 389, host: 61389, protocol: "tcp"
config.vm.network "forwarded_port", guest: 636, host: 61636, protocol: "tcp"
config.vm.network "forwarded_port", guest: 3268, host: 63268, protocol: "tcp"
config.vm.network "forwarded_port", guest: 3269, host: 63269, protocol: "tcp"
config.vm.provision "shell", path: "src/main/resources/provision/installsmb.sh"
end

View File

@ -0,0 +1,43 @@
apply plugin: 'elasticsearch.build'
Map<String, String> vagrantEnvVars = [
'VAGRANT_CWD' : "${project.projectDir.absolutePath}",
'VAGRANT_VAGRANTFILE' : 'Vagrantfile',
'VAGRANT_PROJECT_DIR' : "${project.projectDir.absolutePath}"
]
String box = "test.ad.elastic.local"
task update(type: org.elasticsearch.gradle.vagrant.VagrantCommandTask) {
command 'box'
subcommand 'update'
boxName box
environmentVars vagrantEnvVars
}
task up(type: org.elasticsearch.gradle.vagrant.VagrantCommandTask) {
command 'up'
args '--provision', '--provider', 'virtualbox'
boxName box
environmentVars vagrantEnvVars
dependsOn update
}
task halt(type: org.elasticsearch.gradle.vagrant.VagrantCommandTask) {
command 'halt'
boxName box
environmentVars vagrantEnvVars
}
task destroy(type: org.elasticsearch.gradle.vagrant.VagrantCommandTask) {
command 'destroy'
args '-f'
boxName box
environmentVars vagrantEnvVars
dependsOn halt
}
thirdPartyAudit.enabled = false
licenseHeaders.enabled = false
test.enabled = false
jarHell.enabled = false

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEApAA/+F2xZ27cKT9m16iyK3KeZclMKeR5wFhIu2OBiH2s8MWm
mP0p2xnv7k/0W/Eu/+3hjDzVgjbhOseTQKcysP9AFpcOI8Z5P1vpP+BZZWbXNCPb
/nruAfZRoiQh9/LurT0Ej0gJdIoMFFdEwuBVHX2KImTBZvdvlNW9pAjgzywSYkgd
d6Lb9x8QpVHmEGmu3N4qS+Dqj0NfH6cO/ZkRRnuK3mkQ3kCMPm3RLfKa2VRTmWqe
vx6vr9Byu5rYRfETUfI8SSk38LCXu0XUgIx2C5++CG3mqXX8+TjdWYEy6Uj/rPl7
7sZnX7Hv1gDXuBpu0Yn6icHTMnGAMGPS22jsfwIDAQABAoIBAAYdrEUK2W7OB4/S
OXeZZuuP3rBVDW4SgyfVIwE5+L6qUSS5ejkCV+k/0l7ExIwZNnN834hnTF8KxON4
RdmHYrCPFEjDYVecMzFVsCEdsLfDWgsruyyGURHpqamuR0YD3TrAp8bgHNonu8OW
bY4G56Wt5NTbhQrd919JiUTwv9F59+6TnP9cubdt2GHDD2M6TkUNpgQS0hnM578X
zrkiQlakAi+rlC2ZQkH94wxKlm53okBliiAykUmbCOGkLUT/GaQLMoN+MZ7Wv6Ib
nsH8lC0KDcH4T9VGmxjlScIJtxGUMO+dNWx6Kg7E/MSwEasUAJOCqIofRtpDUTr4
QJNo4eECgYEA32l+vZLm7OMFxhbqGnueiZXbnc/v0kveeFTDt4OWcUozMBez5H3W
AFFILTRADNbvgEAwuK5oC1hEOH5zoRfnaGXcmWayurD8ibK/t23gE5Xf6rL/vCBN
LMS6WoKXXgCKOwQ0Ke5AoaPmca0Iq8bHFmb4pBF9C/0Z1mc1fc+RWxUCgYEAu+xD
w0zhh5Ktob8Q8eNiqVMrSa9jq0MUS1ljx6qCeIGxbuvQARkJxqms3SXwR4JjEwf3
BAzetYCTFvkqrne9jhoVyZGGS0gLXSG9v3iOaP6GIa51GZwtYhBrzDuGao+UL/Cc
ke4hXpC9S7TSoprW8WWevXVa4dy1kaoFUbrTPkMCgYAxRrx8pcUnZJ9mZLF36+I4
6IPLGA0GblOAaPnOJUjubfZCWkgEUrj70vG/frHN4y5qND5KzbUHI43QhBuO4Y3Z
2fXBJASx5s2ctX9RvvtYdosv4hFD9j/vaujLg9hNFINopvG2eeVpgZQXaJnsAWjy
CP44ed8B4O5s+tCykjC2TQKBgCMxJqt/TUjnRg7hShoSXBqbkaK17rNW14kYz1/H
5bENkJ3WGVjrSHJkuhOcFDhACa+5sR+YDWjuEB2gQcb0c5IV/niGASE996rUM8WU
nQ66g4HxOsq1/aW8r4NKrmxsQPMNWzTU5HjiICD6VuvOlWwVfLm8LW3YuEP0FBTv
KLojAoGAW2EKM7SnstY4khKnC+029aZNuSy/VE6LDcn+E5vwEUgpBN5UTqOWweTv
krlEbD1uAI6aI0Ybc4jM6uyo5LSBzw1TZRS5u3prLZxyyG10JvRD0/f/QTOI21TS
LubgfTc+LXbvUpv6F29lIxHZcIe9lX7cUzHK3Wwo24QOCsXYeqU=
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDmzCCAoOgAwIBAgIUdwsnIxjgSneHNVKT6JNCCsrQ3T0wDQYJKoZIhvcNAQEL
BQAwNDEyMDAGA1UEAxMpRWxhc3RpYyBDZXJ0aWZpY2F0ZSBUb29sIEF1dG9nZW5l
cmF0ZWQgQ0EwHhcNMTgwMjE1MTc0ODQ2WhcNMjEwMjE0MTc0ODQ2WjA0MTIwMAYD
VQQDEylFbGFzdGljIENlcnRpZmljYXRlIFRvb2wgQXV0b2dlbmVyYXRlZCBDQTCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKQAP/hdsWdu3Ck/Zteosity
nmXJTCnkecBYSLtjgYh9rPDFppj9KdsZ7+5P9FvxLv/t4Yw81YI24TrHk0CnMrD/
QBaXDiPGeT9b6T/gWWVm1zQj2/567gH2UaIkIffy7q09BI9ICXSKDBRXRMLgVR19
iiJkwWb3b5TVvaQI4M8sEmJIHXei2/cfEKVR5hBprtzeKkvg6o9DXx+nDv2ZEUZ7
it5pEN5AjD5t0S3ymtlUU5lqnr8er6/Qcrua2EXxE1HyPEkpN/Cwl7tF1ICMdguf
vght5ql1/Pk43VmBMulI/6z5e+7GZ1+x79YA17gabtGJ+onB0zJxgDBj0tto7H8C
AwEAAaOBpDCBoTAdBgNVHQ4EFgQUZo2Y3maL2NoxbbkwRZiC37k6QMEwbwYDVR0j
BGgwZoAUZo2Y3maL2NoxbbkwRZiC37k6QMGhOKQ2MDQxMjAwBgNVBAMTKUVsYXN0
aWMgQ2VydGlmaWNhdGUgVG9vbCBBdXRvZ2VuZXJhdGVkIENBghR3CycjGOBKd4c1
UpPok0IKytDdPTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBf
mkc4bvUR5+We/2rRqCmP4LFnl/LxfbZ9/pUPRdcxuowuK7YfxN8i44VXGpJvLtec
izhA8gvlj6GbYB/GNlHMogqEORbrMlu2o5Cev4HE/pcWpoqtVaDJqI5Hq4763EmJ
p2dXGMmU04H4LtkcCEt3xQfLQ+QIP4Dl2yEsNd248BKSsscCGm9V3vgzFzbdgndo
zUWv9hQCaEsKNtqvnkTqDy2uFjnf+xNoXFr/bI94gvD9HlZHnIC+g0TL5jjtSfCH
gjeXhC2bBKFtlSt4ClIdZTXWievYs6YDRREfaOi4F0757A/gf+hT0fjZ+9WWnUeM
UuvUnl71CNRnJ5JlNKBA
-----END CERTIFICATE-----

View File

@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDoDCCAoigAwIBAgIUMVGoHuyNTjTFaoRmqFELz75jzDEwDQYJKoZIhvcNAQEL
BQAwNDEyMDAGA1UEAxMpRWxhc3RpYyBDZXJ0aWZpY2F0ZSBUb29sIEF1dG9nZW5l
cmF0ZWQgQ0EwHhcNMTgwMjE1MTc0OTExWhcNMjEwMjE0MTc0OTExWjARMQ8wDQYD
VQQDEwZzYW1iYTQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtGBwa
n+7JN2vweSUsYh4zPmh8RPIE+nEVjK1lx/rADUBY7UVjfTYC+MVKKiezZe7gYCNT
7JNKazPpgVI9e3ZFKw/UxomLqRuuvn5bTh+1tMs3afY5+GGzi7oPmEbBO3ceg0Hi
rNSTDa1rfroZnRYK8uIeSZacQnAW90plITI7rBBt9jq+W9albFbDybfDgNv+yS/C
rzIsofm4rbFC3SMRYfrT6HvwDhjOmmYKZci5x7tsn0T+3tSiR44Bw5/DgiN5kX3m
/kl9qg1eoYWbCUy1dKmQlb4Nb4uNcxrIugLB3zjBkfhMZ0OHoveKh/lJASTWik9k
xQ9rEYbpsRbuXpsHAgMBAAGjgcwwgckwHQYDVR0OBBYEFJOLa7UXKtLPibgKeFh7
Kq1+rS0/MG8GA1UdIwRoMGaAFGaNmN5mi9jaMW25MEWYgt+5OkDBoTikNjA0MTIw
MAYDVQQDEylFbGFzdGljIENlcnRpZmljYXRlIFRvb2wgQXV0b2dlbmVyYXRlZCBD
QYIUdwsnIxjgSneHNVKT6JNCCsrQ3T0wLAYDVR0RBCUwI4IJbG9jYWxob3N0hwR/
AAABhxAAAAAAAAAAAAAAAAAAAAABMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQAD
ggEBAEHqT1WHkcF8DuOgyIBx7wKcUVQ5H1qYYlJ1xgMGrKFFZLUzouLcON7oadEu
HLIJ4Z3AKD3bqWpcls5XJ9MTECGR48tou67x9cXqTV7jR3Rh0H/VGwzwhR85vbpu
o8ielOPL8XAQOfnAFESJii5sfCU4ZwLg+3evmGZdKfhU6rqQtLimgG/Gm96vOJne
y0a/TZTWrfAarithkOHHXSSAhEI5SdW5SlZAytF4AmYqFvafwxe1+NyFwfCRy0Xl
H40WgVsq+z84psU+WyORb3THX5rgB4au9nuMXOqFKAtrJSI/uApncYraaqU28rqB
gYd8XrtjhKOLw+6viqAKu8l7/cs=
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEArRgcGp/uyTdr8HklLGIeMz5ofETyBPpxFYytZcf6wA1AWO1F
Y302AvjFSions2Xu4GAjU+yTSmsz6YFSPXt2RSsP1MaJi6kbrr5+W04ftbTLN2n2
Ofhhs4u6D5hGwTt3HoNB4qzUkw2ta366GZ0WCvLiHkmWnEJwFvdKZSEyO6wQbfY6
vlvWpWxWw8m3w4Db/skvwq8yLKH5uK2xQt0jEWH60+h78A4YzppmCmXIuce7bJ9E
/t7UokeOAcOfw4IjeZF95v5JfaoNXqGFmwlMtXSpkJW+DW+LjXMayLoCwd84wZH4
TGdDh6L3iof5SQEk1opPZMUPaxGG6bEW7l6bBwIDAQABAoIBAFkjr2Vus3PgHLAs
Ux52MQNGwlwszU4PAymL1sgxokpBCMBDAJbppmUFY+R7rRJQDiJyn/7aOEf8yTEZ
LhcHe7LHKFH1JGRN5DmrVDsFEoNq5bRV1z2nUfk6ncjmLJnaW8/U3Js1Ugug4YwY
KRKDuRROXHAoiW1TMZJCK4fE/q+HZeG/lz110C+GJfhtCH6PzowC4eVPeh1/FExl
TFGRFh2qnN/d5IfGWaZwazTR16OGOoZf/WYydBilcugxQFNx5osR+4nAFdMW0xD2
x2diukMf+WBjIWlO3vt9GMs8PBQsU2Ix3/+MUxC5MCUafL1GBqUSphB4YWTrNWQ0
izFEYZECgYEA1Ue8S0xL6Qxy8F1cZj+tvoGlblCTxHL65JeMl6LwMHzuNHX27s8Q
Ax9j8Z2MTWH7IBATmA56CYlA09FWRiIr38k7cNUC8KdjvjPeqHKJeTIhluiBWGLl
AE2XbEkOdjBXXg7ipF0tcBWb+/WrobzJ2T9dpMzZZOnWEB+7wsN2fy0CgYEAz8PG
TJ0u/+2q+RfeAxo0zdC/dwx8T5rJfZD0AiJpEu69oqMZdiX2M1JDabh/CFdYWyAm
AWQdSw0ugeUHeiZ0i2gujtbxDLAhpCsQ1jleJpJm7VWvgCKY7FotmXhVxA8Acmm0
slv280ezNJMJFKIONuuOtDATdX1b+MXoh5D2A4MCgYAuadwKLuJeJv1kXYzcG4N9
78zGgvaFS9hZorlPzn+ira1Q8VL5iUocw9oGHJkJxgbWZWk+L/hS1vGqpuW1gX42
xx4OYeyv3l2QaM1Nrw9Htqckphhv2aWoOTp4sDVbdw2sRGUCC9z1hV5aqI3fNqxe
gLGqSYINue2BuMYtjkfdSQKBgC0uefU3SX1GhiPdWN572HfZqYmOIYp+Mssntqiw
KwF/AaZYqbTT1JKclSRshtOdiw1mFF3BE826dB6zW8joi/e1FErj20/TDb3Rz7uG
hj8FH3UFaUEIRRFBGyGA1cXpLUO0USNodG+7a/FG+HaQN18iIsp0mga22EVlZIf2
sklZAoGAOJTQtMJfVk5KvqaZWnFou1De5BLnTq7LEvuNHlddIlXG0QQe9QcyB82G
UFqbpBR8QBTFsHdIQEA4LNQE7L1WrKR2Qj087QXHaUnlo7x2WPoSyziPet0nUn3E
gE5dgnkzX/MENKjG90wJFWNiJqz3JXIbVZKZLzkbM+u+X2+oRvs=
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,95 @@
#! /bin/bash
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
# or more contributor license agreements. Licensed under the Elastic License;
# you may not use this file except in compliance with the Elastic License.
set -ex
MARKER_FILE=/etc/marker
if [ -f $MARKER_FILE ]; then
echo "Already provisioned..."
exit 0;
fi
VDIR=/vagrant
RESOURCES=$VDIR/src/main/resources
CERTS_DIR=$RESOURCES/certs
SSL_DIR=/var/lib/samba/private/tls
# Update package manager
apt-get update -qqy
# Install krb5 packages
apt-get install -qqy samba ldap-utils
# install ssl certs
mkdir -p $SSL_DIR
cp $CERTS_DIR/*.pem $SSL_DIR
chmod 600 $SSL_DIR/key.pem
cat $SSL_DIR/ca.pem >> /etc/ssl/certs/ca-certificates.crt
mv /etc/samba/smb.conf /etc/samba/smb.conf.orig
samba-tool domain provision --server-role=dc --use-rfc2307 --dns-backend=SAMBA_INTERNAL --realm=AD.TEST.ELASTICSEARCH.COM --domain=ADES --adminpass=Passw0rd
cp /var/lib/samba/private/krb5.conf /etc/krb5.conf
service samba-ad-dc restart
# Add users
samba-tool user add ironman Passw0rd --surname=Stark --given-name=Tony --job-title=CEO
samba-tool user add hulk Passw0rd --surname=Banner --given-name=Bruce
samba-tool user add phil Passw0rd --surname=Coulson --given-name=Phil
samba-tool user add cap Passw0rd --surname=Rogers --given-name=Steve
samba-tool user add blackwidow Passw0rd --surname=Romanoff --given-name=Natasha
samba-tool user add hawkeye Passw0rd --surname=Barton --given-name=Clint
samba-tool user add Thor Passw0rd
samba-tool user add selvig Passw0rd --surname=Selvig --given-name=Erik
samba-tool user add Odin Passw0rd
samba-tool user add Jarvis Passw0rd
samba-tool user add kraken Passw0rd --surname=Kraken --given-name=Commander
samba-tool user add fury Passw0rd --surname=Fury --given-name=Nick
# Add groups
samba-tool group add SHIELD
samba-tool group add Avengers
samba-tool group add Supers
samba-tool group add Geniuses
samba-tool group add Playboys
samba-tool group add Philanthropists
samba-tool group add Gods
samba-tool group add Billionaires
samba-tool group add "World Security Council"
samba-tool group add Hydra
# Group membership
samba-tool group addmembers "SHIELD" Thor,hawkeye,blackwidow,cap,phil,hulk,ironman
samba-tool group addmembers "Avengers" Thor,hawkeye,blackwidow,cap,hulk,ironman
samba-tool group addmembers "Supers" Avengers
samba-tool group addmembers "Geniuses" selvig,hulk,ironman
samba-tool group addmembers "Playboys" ironman
samba-tool group addmembers "Philanthropists" Thor,hulk,ironman
samba-tool group addmembers "Gods" Thor,Odin
samba-tool group addmembers "Billionaires" ironman
samba-tool group addmembers "World Security Council" fury
samba-tool group addmembers "Hydra" kraken
# update UPN
cat > /tmp/entrymods << EOL
dn: CN=Erik Selvig,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com
changetype: modify
replace: userPrincipalName
userPrincipalName: erik.selvig@ad.test.elasticsearch.com
dn: CN=Bruce Banner,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com
changetype: modify
add: seeAlso
seeAlso: CN=Avengers,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com
EOL
ldapmodify -D Administrator@ad.test.elasticsearch.com -w Passw0rd -H ldaps://127.0.0.1:636 -f /tmp/entrymods -v
touch $MARKER_FILE