diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/LdapLoginIT.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/LdapLoginIT.java index 78b05c74dfb..cddd562c209 100644 --- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/LdapLoginIT.java +++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/LdapLoginIT.java @@ -68,7 +68,7 @@ public class LdapLoginIT { @BeforeClass public static void startLocalLdap() { - server = InMemoryLdapServer.startLdap(33389); + server = InMemoryLdapServer.startLdap(); } @AfterClass @@ -107,7 +107,7 @@ public void cleanup() { @Test public void ldapLogin_with_StartTLS() throws Exception { Long beforeTest = System.currentTimeMillis(); - performLdapLogin("testzone2", server.getLdapBaseUrl(), "marissa4", "ldap4"); + performLdapLogin("testzone2", server.getUrl(), "marissa4", "ldap4"); Long afterTest = System.currentTimeMillis(); assertThat(webDriver.findElement(By.cssSelector("h1")).getText(), Matchers.containsString("Where to?")); ScimUser user = IntegrationTestUtils.getUserByZone(zoneAdminToken, baseUrl, "testzone2", "marissa4"); @@ -117,7 +117,7 @@ public void ldapLogin_with_StartTLS() throws Exception { @Test public void ldap_login_using_utf8_characters() throws Exception { - performLdapLogin("testzone2", server.getLdapBaseUrl(), "\u7433\u8D3A", "koala"); + performLdapLogin("testzone2", server.getUrl(), "\u7433\u8D3A", "koala"); assertThat(webDriver.findElement(By.cssSelector("h1")).getText(), Matchers.containsString("Where to?")); } diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/AbstractLdapMockMvcTest.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/AbstractLdapMockMvcTest.java index 2d212299446..e8607b747f7 100644 --- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/AbstractLdapMockMvcTest.java +++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/AbstractLdapMockMvcTest.java @@ -166,7 +166,7 @@ MockMvc getMockMvc() { protected abstract void stopLdapServer(); - protected abstract String getLdapOrLdapSBaseUrl(); + protected abstract String getLdapUrl(); // Called by child classes. Allows this abstract parent class to act like a parameterized test. AbstractLdapMockMvcTest(String ldapProfile, String ldapGroup, String tlsConfig) { @@ -190,11 +190,13 @@ void setUp(@Autowired WebApplicationContext webApplicationContext, zone = MockMvcUtils.createZoneForInvites(getMockMvc(), getWebApplicationContext(), userId, REDIRECT_URI, IdentityZoneHolder.getCurrentZoneId()); try { + ensureLdapServerIsRunning(); + LdapIdentityProviderDefinition definition = new LdapIdentityProviderDefinition(); definition.setLdapProfileFile("ldap/" + ldapProfile); definition.setLdapGroupFile("ldap/" + ldapGroup); definition.setMaxGroupSearchDepth(10); - definition.setBaseUrl(getLdapOrLdapSBaseUrl()); + definition.setBaseUrl(getLdapUrl()); definition.setBindUserDn("cn=admin,ou=Users,dc=test,dc=com"); definition.setBindPassword("adminsecret"); definition.setSkipSSLVerification(false); @@ -210,8 +212,6 @@ void setUp(@Autowired WebApplicationContext webApplicationContext, listener = (ApplicationListener) mock(ApplicationListener.class); configurableApplicationContext.addApplicationListener(listener); - ensureLdapServerIsRunning(); - testLogger = new InterceptingLogger(); originalAuditServiceLogger = loggingAuditService.getLogger(); loggingAuditService.setLogger(testLogger); @@ -806,19 +806,14 @@ void passcodeGrantIdTokenContainsExternalGroupsAsRolesClaim() throws Exception { @Test void testTwoLdapServers() throws Exception { // Setup second ldap server - int port = 33000 + getRandomPortOffset(); - int sslPort = 34000 + getRandomPortOffset(); - InMemoryLdapServer secondLdapServer; - String ldapBaseUrl; - if (getLdapOrLdapSBaseUrl().contains("ldap://")) { - ldapBaseUrl = getLdapOrLdapSBaseUrl() + " ldap://localhost:" + port; - secondLdapServer = InMemoryLdapServer.startLdap(port); + if (getLdapUrl().contains("ldap://")) { + secondLdapServer = InMemoryLdapServer.startLdap(); } else { - ldapBaseUrl = getLdapOrLdapSBaseUrl() + " ldaps://localhost:" + sslPort; - secondLdapServer = InMemoryLdapServer.startLdapWithTls(port, sslPort, KEYSTORE); + secondLdapServer = InMemoryLdapServer.startLdapWithTls(KEYSTORE); } + ldapBaseUrl = getLdapUrl() + " " + secondLdapServer.getUrl(); provider.getConfig().setBaseUrl(ldapBaseUrl); updateLdapProvider(); diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/LdapCertificateMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/LdapCertificateMockMvcTests.java index 8ee395cc224..f68856cbb19 100644 --- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/LdapCertificateMockMvcTests.java +++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/LdapCertificateMockMvcTests.java @@ -32,11 +32,6 @@ @DefaultTestContext @ExtendWith(InMemoryLdapServer.LdapTrustStoreExtension.class) class LdapCertificateMockMvcTests { - private static final int LDAP_VALID_LDAP_PORT = 33390; - private static final int LDAP_EXPIRED_LDAP_PORT = LDAP_VALID_LDAP_PORT + 1; - private static final int LDAP_VALID_LDAPS_PORT = 33637; - private static final int LDAP_EXPIRED_LDAPS_PORT = LDAP_VALID_LDAPS_PORT + 1; - private static File ldapRootDirectoryExpired; private static File ldapRootDirectoryValid; private static InMemoryLdapServer validLdapCertServer; @@ -58,8 +53,8 @@ static void startLdapsServers() { ldapRootDirectoryValid = new File(System.getProperty("java.io.tmpdir"), generator.generate()); ldapRootDirectoryExpired = new File(System.getProperty("java.io.tmpdir"), generator.generate()); - validLdapCertServer = InMemoryLdapServer.startLdapWithTls(LDAP_VALID_LDAP_PORT, LDAP_VALID_LDAPS_PORT, validKeystore); - expiredLdapCertServer = InMemoryLdapServer.startLdapWithTls(LDAP_EXPIRED_LDAP_PORT, LDAP_EXPIRED_LDAPS_PORT, expiredKeystore); + validLdapCertServer = InMemoryLdapServer.startLdapWithTls(validKeystore); + expiredLdapCertServer = InMemoryLdapServer.startLdapWithTls(expiredKeystore); } @AfterAll @@ -81,7 +76,7 @@ void setUp(@Autowired WebApplicationContext webApplicationContext, @Autowired Mo null, IdentityZoneHolder.getCurrentZoneId()); LdapIdentityProviderDefinition definition = LdapIdentityProviderDefinition.searchAndBindMapGroupToScopes( - validLdapCertServer.getLdapSBaseUrl(), + validLdapCertServer.getUrl(), "cn=admin,ou=Users,dc=test,dc=com", "adminsecret", "dc=test,dc=com", @@ -103,7 +98,7 @@ void setUp(@Autowired WebApplicationContext webApplicationContext, @Autowired Mo mockMvc, webApplicationContext, null, IdentityZoneHolder.getCurrentZoneId()); - definition.setBaseUrl(expiredLdapCertServer.getLdapSBaseUrl()); + definition.setBaseUrl(expiredLdapCertServer.getUrl()); MockMvcUtils.createIdentityProvider(mockMvc, trustedButExpiredCertZone, OriginKeys.LDAP, definition); } diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/LdapMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/LdapMockMvcTests.java index 01940281801..c13578e2673 100644 --- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/LdapMockMvcTests.java +++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/LdapMockMvcTests.java @@ -1,5 +1,6 @@ package org.cloudfoundry.identity.uaa.mock.ldap; +import org.assertj.core.api.Assertions; import org.cloudfoundry.identity.uaa.DefaultTestContext; import org.cloudfoundry.identity.uaa.mock.util.MockMvcUtils; import org.cloudfoundry.identity.uaa.provider.IdentityProvider; @@ -9,9 +10,15 @@ import org.cloudfoundry.identity.uaa.util.JsonUtils; import org.cloudfoundry.identity.uaa.zone.IdentityZone; import org.cloudfoundry.identity.uaa.zone.IdentityZoneSwitchingFilter; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; +import java.io.File; + import static org.cloudfoundry.identity.uaa.constants.OriginKeys.LDAP; import static org.cloudfoundry.identity.uaa.provider.LdapIdentityProviderDefinition.LDAP_TLS_NONE; import static org.hamcrest.Matchers.containsString; @@ -39,7 +46,6 @@ class LdapMockMvcTests { class LdapSimpleBindTest extends AbstractLdapMockMvcTest { private static InMemoryLdapServer ldapContainer; - private static final int ldapPort = 44389; LdapSimpleBindTest() { super( @@ -51,7 +57,7 @@ class LdapSimpleBindTest extends AbstractLdapMockMvcTest { @BeforeAll static void beforeAll() { - ldapContainer = InMemoryLdapServer.startLdap(ldapPort); + ldapContainer = InMemoryLdapServer.startLdap(); } @AfterAll @@ -62,7 +68,7 @@ static void afterAll() { @Override protected void ensureLdapServerIsRunning() { if (!ldapContainer.isRunning()) { - ldapContainer = InMemoryLdapServer.startLdap(ldapPort); + ldapContainer = InMemoryLdapServer.startLdap(); } } @@ -74,15 +80,13 @@ protected void stopLdapServer() { } @Override - protected String getLdapOrLdapSBaseUrl() { - return "ldap://localhost:" + ldapPort; + protected String getLdapUrl() { + return ldapContainer.getUrl(); } } class LdapSearchAndCompareTest extends AbstractLdapMockMvcTest { private static InMemoryLdapServer ldapContainer; - private static final int ldapPort = 44390; - private static final int ldapSPort = 44337; LdapSearchAndCompareTest() { super( @@ -94,7 +98,7 @@ class LdapSearchAndCompareTest extends AbstractLdapMockMvcTest { @BeforeAll static void beforeAll() { - ldapContainer = InMemoryLdapServer.startLdapWithTls(ldapPort, ldapSPort, KEYSTORE); + ldapContainer = InMemoryLdapServer.startLdapWithTls(KEYSTORE); } @AfterAll @@ -105,7 +109,7 @@ static void afterAll() { @Override protected void ensureLdapServerIsRunning() { if (!ldapContainer.isRunning()) { - ldapContainer = InMemoryLdapServer.startLdapWithTls(ldapPort, ldapSPort, KEYSTORE); + ldapContainer = InMemoryLdapServer.startLdapWithTls(KEYSTORE); } } @@ -117,15 +121,13 @@ protected void stopLdapServer() { } @Override - protected String getLdapOrLdapSBaseUrl() { - return "ldaps://localhost:" + ldapSPort; + protected String getLdapUrl() { + return ldapContainer.getUrl(); } } class LdapSearchAndBindTest extends AbstractLdapMockMvcTest { private static InMemoryLdapServer ldapContainer; - private static final int ldapPort = 44391; - private static final int ldapSPort = 44338; LdapSearchAndBindTest() { super( @@ -137,7 +139,7 @@ class LdapSearchAndBindTest extends AbstractLdapMockMvcTest { @BeforeAll static void beforeAll() { - ldapContainer = InMemoryLdapServer.startLdapWithTls(ldapPort, ldapSPort, KEYSTORE); + ldapContainer = InMemoryLdapServer.startLdapWithTls(KEYSTORE); } @AfterAll @@ -148,7 +150,7 @@ static void afterAll() { @Override protected void ensureLdapServerIsRunning() { if (!ldapContainer.isRunning()) { - ldapContainer = InMemoryLdapServer.startLdapWithTls(ldapPort, ldapSPort, KEYSTORE); + ldapContainer = InMemoryLdapServer.startLdapWithTls(KEYSTORE); } } @@ -160,8 +162,8 @@ protected void stopLdapServer() { } @Override - protected String getLdapOrLdapSBaseUrl() { - return "ldap://localhost:" + ldapPort; + protected String getLdapUrl() { + return ldapContainer.getUrl(); } @Nested @@ -183,7 +185,7 @@ void setUp() throws Exception { String zoneAdminToken = MockMvcUtils.getZoneAdminToken(getMockMvc(), adminAccessToken, zone.getId()); definition = LdapIdentityProviderDefinition.searchAndBindMapGroupToScopes( - getLdapOrLdapSBaseUrl(), + getLdapUrl(), "cn=admin,ou=Users,dc=test,dc=com", "adminsecret", "dc=test,dc=com", @@ -289,36 +291,19 @@ void invalidSearchBase() throws Exception { */ @Test void unableToConnectToLdapWithInvalidSsl() { - int port = 37000 + getRandomPortOffset(); - int sslPort = 38000 + getRandomPortOffset(); - - try (InMemoryLdapServer inMemoryLdapServer = InMemoryLdapServer.startLdapWithTls(port, sslPort, null)) { - definition.setBaseUrl(inMemoryLdapServer.getLdapSBaseUrl()); + File expiredKeystore = new File(getClass().getClassLoader().getResource("certs/expired-self-signed-ldap-cert.jks").getFile()); + try (InMemoryLdapServer inMemoryLdapServer = InMemoryLdapServer.startLdapWithTls(expiredKeystore)) { + definition.setBaseUrl(inMemoryLdapServer.getUrl()); definition.setSkipSSLVerification(false); getMockMvc().perform( - baseRequest.content(JsonUtils.writeValueAsString(request))) + baseRequest.content(JsonUtils.writeValueAsString(request))) .andDo(print()) .andExpect(status().isBadRequest()) .andExpect(content().string(containsString("Caused by:"))); } catch (Exception ignored) { - + Assertions.fail("should not be able to connect to LDAP server"); } } - - /** - * TODO: We're not sure what this test is trying to do - * Is the UAA SSL configuration invalid? - * Is the LDAP server configuration invalid? - */ - @Test - void ableToConnectToLdapWithInvalidSsl_WithSkipValidation() throws Exception { - definition.setBaseUrl("ldaps://localhost:" + ldapSPort); - - getMockMvc().perform( - baseRequest.content(JsonUtils.writeValueAsString(request))) - .andExpect(status().isOk()) - .andExpect(content().string("\"ok\"")); - } } } diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/LdapSkipCertificateMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/LdapSkipCertificateMockMvcTests.java index 8f1c5b43d74..7075a8ac4de 100644 --- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/LdapSkipCertificateMockMvcTests.java +++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/LdapSkipCertificateMockMvcTests.java @@ -32,11 +32,6 @@ @DefaultTestContext @ExtendWith(InMemoryLdapServer.LdapTrustStoreExtension.class) class LdapSkipCertificateMockMvcTests { - private static final int LDAP_VALID_LDAP_PORT = 33390; - private static final int LDAP_EXPIRED_LDAP_PORT = LDAP_VALID_LDAP_PORT + 1; - private static final int LDAP_VALID_LDAPS_PORT = 33637; - private static final int LDAP_EXPIRED_LDAPS_PORT = LDAP_VALID_LDAPS_PORT + 1; - private static File ldapRootDirectoryExpired; private static InMemoryLdapServer expiredLdapCertServer; private MockMvcUtils.IdentityZoneCreationResult trustedCertZone; @@ -53,8 +48,7 @@ static void startLdapsServers() { File expiredKeystore = new File(classLoader.getResource("certs/expired-self-signed-ldap-cert.jks").getFile()); RandomValueStringGenerator generator = new RandomValueStringGenerator(); ldapRootDirectoryExpired = new File(System.getProperty("java.io.tmpdir"), generator.generate()); - - expiredLdapCertServer = InMemoryLdapServer.startLdapWithTls(LDAP_EXPIRED_LDAP_PORT, LDAP_EXPIRED_LDAPS_PORT, expiredKeystore); + expiredLdapCertServer = InMemoryLdapServer.startLdapWithTls(expiredKeystore); } @AfterAll @@ -74,7 +68,7 @@ void setUp(@Autowired WebApplicationContext webApplicationContext, @Autowired Mo null, IdentityZoneHolder.getCurrentZoneId()); LdapIdentityProviderDefinition definition = LdapIdentityProviderDefinition.searchAndBindMapGroupToScopes( - expiredLdapCertServer.getLdapSBaseUrl(), + expiredLdapCertServer.getUrl(), "cn=admin,ou=Users,dc=test,dc=com", "adminsecret", "dc=test,dc=com", @@ -97,7 +91,7 @@ void setUp(@Autowired WebApplicationContext webApplicationContext, @Autowired Mo mockMvc, webApplicationContext, null, IdentityZoneHolder.getCurrentZoneId()); - definition.setBaseUrl(expiredLdapCertServer.getLdapSBaseUrl()); + definition.setBaseUrl(expiredLdapCertServer.getUrl()); MockMvcUtils.createIdentityProvider(mockMvc, trustedButExpiredCertZone, OriginKeys.LDAP, definition); } diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/providers/IdentityProviderEndpointDocs.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/providers/IdentityProviderEndpointDocs.java index 6598351cec5..27b91bb0359 100644 --- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/providers/IdentityProviderEndpointDocs.java +++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/providers/IdentityProviderEndpointDocs.java @@ -159,8 +159,6 @@ class IdentityProviderEndpointDocs extends EndpointDocs { private static final SnippetUtils.ConstrainableField VERSION = (SnippetUtils.ConstrainableField) fieldWithPath("version").type(NUMBER).description(VERSION_DESC); private static final Snippet commonRequestParams = requestParameters(parameterWithName("rawConfig").optional("false").type(BOOLEAN).description("UAA 3.4.0 Flag indicating whether the response should use raw, unescaped JSON for the `config` field of the IDP, rather than the default behavior of encoding the JSON as a string.")); - private static final int LDAP_PORT = 23389; - private String adminToken; private IdentityProviderProvisioning identityProviderProvisioning; @@ -241,7 +239,7 @@ static void afterClass() throws Exception { @BeforeAll static void startLdapContainer() { - ldapContainer = InMemoryLdapServer.startLdap(LDAP_PORT); + ldapContainer = InMemoryLdapServer.startLdap(); } private final FieldDescriptor ldapType = fieldWithPath("type").required().description("`ldap`"); @@ -792,7 +790,7 @@ void create_Simple_Bind_LDAPIdentityProvider() throws Exception { LdapIdentityProviderDefinition providerDefinition = new LdapIdentityProviderDefinition(); providerDefinition.setLdapProfileFile("ldap/ldap-simple-bind.xml"); providerDefinition.setLdapGroupFile("ldap/ldap-groups-null.xml"); - providerDefinition.setBaseUrl(ldapContainer.getLdapBaseUrl()); + providerDefinition.setBaseUrl(ldapContainer.getUrl()); providerDefinition.setUserDNPattern("cn={0},ou=Users,dc=test,dc=com"); providerDefinition.setUserDNPatternDelimiter(";"); providerDefinition.setMailAttributeName("mail"); @@ -812,7 +810,7 @@ void create_SearchAndBind_Groups_Map_ToScopes_LDAPIdentityProvider() throws Exce LdapIdentityProviderDefinition providerDefinition = new LdapIdentityProviderDefinition(); providerDefinition.setLdapProfileFile("ldap/ldap-search-and-bind.xml"); providerDefinition.setLdapGroupFile("ldap/ldap-groups-map-to-scopes.xml"); - providerDefinition.setBaseUrl(ldapContainer.getLdapBaseUrl()); + providerDefinition.setBaseUrl(ldapContainer.getUrl()); providerDefinition.setBindUserDn("cn=admin,ou=Users,dc=test,dc=com"); providerDefinition.setBindPassword("adminsecret"); providerDefinition.setUserSearchBase("dc=test,dc=com"); @@ -841,7 +839,7 @@ void create_SearchAndCompare_Groups_As_Scopes_LDAPIdentityProvider() throws Exce LdapIdentityProviderDefinition providerDefinition = new LdapIdentityProviderDefinition(); providerDefinition.setLdapProfileFile("ldap/ldap-search-and-compare.xml"); providerDefinition.setLdapGroupFile("ldap/ldap-groups-as-scopes.xml"); - providerDefinition.setBaseUrl(ldapContainer.getLdapBaseUrl()); + providerDefinition.setBaseUrl(ldapContainer.getUrl()); providerDefinition.setBindUserDn("cn=admin,ou=Users,dc=test,dc=com"); providerDefinition.setBindPassword("adminsecret"); providerDefinition.setUserSearchBase("dc=test,dc=com"); diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/providers/IdentityProviderEndpointsMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/providers/IdentityProviderEndpointsMockMvcTests.java index cfba9c67526..a60ee5e9780 100644 --- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/providers/IdentityProviderEndpointsMockMvcTests.java +++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/providers/IdentityProviderEndpointsMockMvcTests.java @@ -300,8 +300,8 @@ void test_delete_response_not_containing_bind_password() throws Exception { providerDefinition.setGroupRoleAttribute("description"); try (InMemoryLdapServer ldapServer = - InMemoryLdapServer.startLdap(33389)) { - providerDefinition.setBaseUrl(ldapServer.getLdapBaseUrl()); + InMemoryLdapServer.startLdap()) { + providerDefinition.setBaseUrl(ldapServer.getUrl()); newIdp.setConfig(providerDefinition); // Create an ldap identity provider diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/test/InMemoryLdapServer.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/test/InMemoryLdapServer.java index 4c169a6e81a..3720f3dc244 100644 --- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/test/InMemoryLdapServer.java +++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/test/InMemoryLdapServer.java @@ -15,6 +15,7 @@ import org.junit.jupiter.api.extension.BeforeAllCallback; import org.junit.jupiter.api.extension.ExtensionContext; +import javax.validation.constraints.NotNull; import java.io.Closeable; import java.io.File; import java.io.IOException; @@ -24,6 +25,13 @@ import java.util.ArrayList; import java.util.List; +/** + * In-memory LDAP server that runs on a random port, so that it avoids port collisions. + *

+ * Can be run with or without TLS. Start a server with {@link InMemoryLdapServer#startLdap()} + * or {@link InMemoryLdapServer#startLdapWithTls(File keystore)}, then obtain the URL of the + * running LDAP server with {@link InMemoryLdapServer#getUrl()}. + */ public final class InMemoryLdapServer implements Closeable { private static final String JAVAX_NET_SSL_TRUST_STORE = "javax.net.ssl.trustStore"; @@ -41,37 +49,32 @@ public final class InMemoryLdapServer implements Closeable { InMemoryLdapServer.class.getClassLoader().getResource("ldap_init.ldif"); private InMemoryDirectoryServer directoryServer; - private final int port; - private boolean tlsEnabled; - private int tlsPort; - private File keyStore; - private File trustStore; + private final boolean tlsEnabled; + private final File keyStore; - public static InMemoryLdapServer startLdap(int port) { - return startLdapWithTls(port, 0, null); + public static InMemoryLdapServer startLdap() { + InMemoryLdapServer server = new InMemoryLdapServer(); + server.start(); + server.applyChangesFromLDIF(LDAP_INIT_LIDF_URL); + return server; } - public static InMemoryLdapServer startLdapWithTls(int port, int tlsPort, File keyStore) { - InMemoryLdapServer server = new InMemoryLdapServer(port); - if (keyStore != null) { - server.configureStartTLS(tlsPort, keyStore, new File(TRUST_STORE_URL.getFile())); - } + public static InMemoryLdapServer startLdapWithTls(@NotNull File keyStore) { + InMemoryLdapServer server = new InMemoryLdapServer(keyStore); server.start(); server.applyChangesFromLDIF(LDAP_INIT_LIDF_URL); return server; } - private InMemoryLdapServer(int port) { + private InMemoryLdapServer() { this.tlsEnabled = false; - this.port = port; + this.keyStore = null; } - private void configureStartTLS(int tlsPort, File keyStore, File trustStore) { + private InMemoryLdapServer(File keyStore) { this.tlsEnabled = true; - this.tlsPort = tlsPort; this.keyStore = keyStore; - this.trustStore = trustStore; } public void start() { @@ -92,12 +95,18 @@ private void applyChangesFromLDIF(URL ldif) { } } - public String getLdapBaseUrl() { - return "ldap://localhost:" + port; + /** + * Get the URL of the running LDAP server. + * + * @return - + */ + public String getUrl() { + var scheme = this.tlsEnabled ? "ldaps" : "ldap"; + return "%s://localhost:%s".formatted(scheme, getBoundPort()); } - public String getLdapSBaseUrl() { - return "ldaps://localhost:" + tlsPort; + private Integer getBoundPort() { + return this.directoryServer.getListenPort(); } public void stop() { @@ -116,7 +125,6 @@ private InMemoryDirectoryServerConfig buildConfig() throws LDAPException, Genera InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(DEFAULT_ROOTS); List listenerConfigs = new ArrayList<>(); - listenerConfigs.add(InMemoryListenerConfig.createLDAPConfig("LDAP", port)); config.setEnforceSingleStructuralObjectClass(false); config.setEnforceAttributeSyntaxCompliance(true); config.setSchema(null); @@ -128,18 +136,20 @@ private InMemoryDirectoryServerConfig buildConfig() throws LDAPException, Genera : null; final SSLUtil serverSSLUtil = new SSLUtil( keyStoreKeyManager, - new TrustStoreTrustManager(trustStore) + new TrustStoreTrustManager(TRUST_STORE_URL.getFile()) ); listenerConfigs.add( InMemoryListenerConfig.createLDAPSConfig( "LDAPS", null, - tlsPort, + 0, serverSSLUtil.createSSLServerSocketFactory(), clientSSLUtil.createSSLSocketFactory() ) ); + } else { + listenerConfigs.add(InMemoryListenerConfig.createLDAPConfig("LDAP", 0)); } config.setListenerConfigs(listenerConfigs);