From 6ddb964c619ed1c9eeead3f6b2c86718ee320434 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Wed, 18 Jun 2025 18:29:16 -0600 Subject: [PATCH] Remove ApacheDS Support Closes gh-13852 --- config/spring-security-config.gradle | 6 - ...onProviderBuilderSecurityBuilderTests.java | 10 +- ...indAuthenticationManagerFactoryITests.java | 12 +- ...sonAuthenticationManagerFactoryITests.java | 12 +- ...LdapProviderBeanDefinitionParserTests.java | 23 +- .../LdapServerBeanDefinitionParserTests.java | 6 +- .../resources/logback-test.xml | 1 - .../security/config/BeanIds.java | 2 - .../LdapAuthenticationProviderConfigurer.java | 18 +- .../ldap/LdapServerBeanDefinitionParser.java | 30 +- .../security/config/spring-security-7.0.rnc | 4 +- .../security/config/spring-security-7.0.xsd | 3 +- ...ntextConfigurationResourceServerTests.java | 4 +- .../config/doc/XsdDocumentedTests.java | 6 +- config/src/test/resources/logback-test.xml | 2 - .../spring-security-dependencies.gradle | 6 - docs/modules/ROOT/pages/modules.adoc | 10 +- .../ROOT/pages/servlet/appendix/faq.adoc | 53 +-- .../servlet/appendix/namespace/ldap.adoc | 2 +- .../authentication/passwords/ldap.adoc | 78 +--- .../servlet/configuration/xml-namespace.adoc | 2 +- docs/spring-security-docs.gradle | 1 - gradle/libs.versions.toml | 7 - ...test-ldap-embedded-apacheds-default.gradle | 30 -- .../LdapServerBeanDefinitionParserTests.java | 56 --- .../resources/applicationContext-security.xml | 9 - .../src/integration-test/resources/users.ldif | 60 --- ...y-itest-ldap-embedded-mode-apacheds.gradle | 30 -- .../LdapServerBeanDefinitionParserTests.java | 56 --- .../resources/applicationContext-security.xml | 9 - .../src/integration-test/resources/users.ldif | 60 --- ldap/spring-security-ldap.gradle | 6 - ...faultSpringSecurityContextSourceTests.java | 2 +- .../SpringSecurityLdapTemplateITests.java | 12 +- ...fig.java => UnboundIdContainerConfig.java} | 16 +- .../BindAuthenticatorTests.java | 4 +- .../PasswordComparisonAuthenticatorTests.java | 4 +- .../FilterBasedLdapUserSearchTests.java | 4 +- ...terBasedLdapUserSearchWithSpacesTests.java | 16 +- .../ldap/server/ApacheDSContainerTests.java | 221 ----------- .../server/ApacheDSEmbeddedLdifTests.java | 79 ---- ...esPopulatorGetGrantedAuthoritiesTests.java | 16 +- .../DefaultLdapAuthoritiesPopulatorTests.java | 4 +- .../LdapUserDetailsManagerTests.java | 4 +- .../NestedLdapAuthoritiesPopulatorTests.java | 4 +- .../ldap/server/ApacheDSContainer.java | 365 ------------------ .../security/ldap/server/package-info.java | 3 +- .../server/core/avltree/ArrayMarshaller.java | 173 --------- ...ectoryLdapAuthenticationProviderTests.java | 3 +- 49 files changed, 138 insertions(+), 1406 deletions(-) delete mode 100644 itest/ldap/embedded-ldap-apacheds-default/spring-security-itest-ldap-embedded-apacheds-default.gradle delete mode 100644 itest/ldap/embedded-ldap-apacheds-default/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java delete mode 100644 itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/applicationContext-security.xml delete mode 100644 itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/users.ldif delete mode 100644 itest/ldap/embedded-ldap-mode-apacheds/spring-security-itest-ldap-embedded-mode-apacheds.gradle delete mode 100644 itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java delete mode 100644 itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/applicationContext-security.xml delete mode 100644 itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/users.ldif rename ldap/src/integration-test/java/org/springframework/security/ldap/{ApacheDsContainerConfig.java => UnboundIdContainerConfig.java} (67%) delete mode 100644 ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSContainerTests.java delete mode 100644 ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSEmbeddedLdifTests.java delete mode 100644 ldap/src/main/java/org/springframework/security/ldap/server/ApacheDSContainer.java delete mode 100644 ldap/src/test/java/org/apache/directory/server/core/avltree/ArrayMarshaller.java diff --git a/config/spring-security-config.gradle b/config/spring-security-config.gradle index 83f91c9bf0..322f77af47 100644 --- a/config/spring-security-config.gradle +++ b/config/spring-security-config.gradle @@ -78,12 +78,6 @@ dependencies { exclude group: 'commons-logging', module: 'commons-logging' exclude group: 'xml-apis', module: 'xml-apis' } - testImplementation "org.apache.directory.server:apacheds-core" - testImplementation "org.apache.directory.server:apacheds-core-entry" - testImplementation "org.apache.directory.server:apacheds-protocol-shared" - testImplementation "org.apache.directory.server:apacheds-protocol-ldap" - testImplementation "org.apache.directory.server:apacheds-server-jndi" - testImplementation 'org.apache.directory.shared:shared-ldap' testImplementation "com.unboundid:unboundid-ldapsdk" testImplementation 'jakarta.persistence:jakarta.persistence-api' testImplementation "org.hibernate.orm:hibernate-core" diff --git a/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.java b/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.java index 17362f02ae..890ed32048 100644 --- a/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.java +++ b/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.java @@ -44,7 +44,7 @@ import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMap import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; import org.springframework.security.ldap.authentication.LdapAuthenticationProvider; -import org.springframework.security.ldap.server.ApacheDSContainer; +import org.springframework.security.ldap.server.UnboundIdContainer; import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.web.servlet.MockMvc; @@ -326,11 +326,11 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests { abstract static class BaseLdapServerConfig extends BaseLdapProviderConfig { @Bean - ApacheDSContainer ldapServer() throws Exception { - ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org", + UnboundIdContainer ldapServer() throws Exception { + UnboundIdContainer unboundIdContainer = new UnboundIdContainer("dc=springframework,dc=org", "classpath:/test-server.ldif"); - apacheDSContainer.setPort(getPort()); - return apacheDSContainer; + unboundIdContainer.setPort(getPort()); + return unboundIdContainer; } } diff --git a/config/src/integration-test/java/org/springframework/security/config/ldap/LdapBindAuthenticationManagerFactoryITests.java b/config/src/integration-test/java/org/springframework/security/config/ldap/LdapBindAuthenticationManagerFactoryITests.java index 9496ba2651..25c02eb69a 100644 --- a/config/src/integration-test/java/org/springframework/security/config/ldap/LdapBindAuthenticationManagerFactoryITests.java +++ b/config/src/integration-test/java/org/springframework/security/config/ldap/LdapBindAuthenticationManagerFactoryITests.java @@ -43,7 +43,7 @@ import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMap import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; -import org.springframework.security.ldap.server.ApacheDSContainer; +import org.springframework.security.ldap.server.UnboundIdContainer; import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator; import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator; import org.springframework.security.ldap.userdetails.UserDetailsContextMapper; @@ -226,18 +226,18 @@ public class LdapBindAuthenticationManagerFactoryITests { @EnableWebSecurity abstract static class BaseLdapServerConfig implements DisposableBean { - private ApacheDSContainer container; + private UnboundIdContainer container; @Bean - ApacheDSContainer ldapServer() throws Exception { - this.container = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif"); + UnboundIdContainer ldapServer() { + this.container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:/test-server.ldif"); this.container.setPort(0); return this.container; } @Bean - BaseLdapPathContextSource contextSource(ApacheDSContainer container) { - int port = container.getLocalPort(); + BaseLdapPathContextSource contextSource(UnboundIdContainer container) { + int port = container.getPort(); return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org"); } diff --git a/config/src/integration-test/java/org/springframework/security/config/ldap/LdapPasswordComparisonAuthenticationManagerFactoryITests.java b/config/src/integration-test/java/org/springframework/security/config/ldap/LdapPasswordComparisonAuthenticationManagerFactoryITests.java index 668fe9b994..fd0ace02aa 100644 --- a/config/src/integration-test/java/org/springframework/security/config/ldap/LdapPasswordComparisonAuthenticationManagerFactoryITests.java +++ b/config/src/integration-test/java/org/springframework/security/config/ldap/LdapPasswordComparisonAuthenticationManagerFactoryITests.java @@ -31,7 +31,7 @@ import org.springframework.security.config.test.SpringTestContextExtension; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; -import org.springframework.security.ldap.server.ApacheDSContainer; +import org.springframework.security.ldap.server.UnboundIdContainer; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin; @@ -93,18 +93,18 @@ public class LdapPasswordComparisonAuthenticationManagerFactoryITests { @EnableWebSecurity abstract static class BaseLdapServerConfig implements DisposableBean { - private ApacheDSContainer container; + private UnboundIdContainer container; @Bean - ApacheDSContainer ldapServer() throws Exception { - this.container = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif"); + UnboundIdContainer ldapServer() { + this.container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:/test-server.ldif"); this.container.setPort(0); return this.container; } @Bean - BaseLdapPathContextSource contextSource(ApacheDSContainer container) { - int port = container.getLocalPort(); + BaseLdapPathContextSource contextSource(UnboundIdContainer container) { + int port = container.getPort(); return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org"); } diff --git a/config/src/integration-test/java/org/springframework/security/config/ldap/LdapProviderBeanDefinitionParserTests.java b/config/src/integration-test/java/org/springframework/security/config/ldap/LdapProviderBeanDefinitionParserTests.java index 162fcc8495..a992de947e 100644 --- a/config/src/integration-test/java/org/springframework/security/config/ldap/LdapProviderBeanDefinitionParserTests.java +++ b/config/src/integration-test/java/org/springframework/security/config/ldap/LdapProviderBeanDefinitionParserTests.java @@ -56,7 +56,7 @@ public class LdapProviderBeanDefinitionParserTests { AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, AuthenticationManager.class); Authentication auth = authenticationManager - .authenticate(UsernamePasswordAuthenticationToken.unauthenticated("ben", "benspassword")); + .authenticate(UsernamePasswordAuthenticationToken.unauthenticated("otherben", "otherbenspassword")); UserDetails ben = (UserDetails) auth.getPrincipal(); assertThat(ben.getAuthorities()).hasSize(3); } @@ -127,6 +127,27 @@ public class LdapProviderBeanDefinitionParserTests { assertThat(auth).isNotNull(); } + @Test + public void supportsShaPasswordEncoder() { + this.appCtx = new InMemoryXmlApplicationContext(""" + + + + + + + + + + """); + AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, + AuthenticationManager.class); + Authentication auth = authenticationManager + .authenticate(UsernamePasswordAuthenticationToken.unauthenticated("ben", "benspassword")); + + assertThat(auth).isNotNull(); + } + @Test public void inetOrgContextMapperIsSupported() { this.appCtx = new InMemoryXmlApplicationContext( diff --git a/config/src/integration-test/java/org/springframework/security/config/ldap/LdapServerBeanDefinitionParserTests.java b/config/src/integration-test/java/org/springframework/security/config/ldap/LdapServerBeanDefinitionParserTests.java index cf5a5b16bd..c453fe1cef 100644 --- a/config/src/integration-test/java/org/springframework/security/config/ldap/LdapServerBeanDefinitionParserTests.java +++ b/config/src/integration-test/java/org/springframework/security/config/ldap/LdapServerBeanDefinitionParserTests.java @@ -26,7 +26,7 @@ import org.springframework.ldap.core.LdapTemplate; import org.springframework.security.config.BeanIds; import org.springframework.security.config.util.InMemoryXmlApplicationContext; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; -import org.springframework.security.ldap.server.ApacheDSContainer; +import org.springframework.security.ldap.server.UnboundIdContainer; import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -92,9 +92,9 @@ public class LdapServerBeanDefinitionParserTests { @Test public void defaultLdifFileIsSuccessful() { this.appCtx = new InMemoryXmlApplicationContext(""); - ApacheDSContainer dsContainer = this.appCtx.getBean(ApacheDSContainer.class); + UnboundIdContainer dsContainer = this.appCtx.getBean(UnboundIdContainer.class); - assertThat(ReflectionTestUtils.getField(dsContainer, "ldifResources")).isEqualTo("classpath*:*.ldif"); + assertThat(ReflectionTestUtils.getField(dsContainer, "ldif")).isEqualTo("classpath*:*.ldif"); } private int getDefaultPort() throws IOException { diff --git a/config/src/integration-test/resources/logback-test.xml b/config/src/integration-test/resources/logback-test.xml index 473e666748..1024d52dec 100644 --- a/config/src/integration-test/resources/logback-test.xml +++ b/config/src/integration-test/resources/logback-test.xml @@ -7,7 +7,6 @@ - diff --git a/config/src/main/java/org/springframework/security/config/BeanIds.java b/config/src/main/java/org/springframework/security/config/BeanIds.java index fcf2e5fc1d..da398cac57 100644 --- a/config/src/main/java/org/springframework/security/config/BeanIds.java +++ b/config/src/main/java/org/springframework/security/config/BeanIds.java @@ -54,8 +54,6 @@ public abstract class BeanIds { public static final String METHOD_SECURITY_METADATA_SOURCE_ADVISOR = PREFIX + "methodSecurityMetadataSourceAdvisor"; - public static final String EMBEDDED_APACHE_DS = PREFIX + "apacheDirectoryServerContainer"; - public static final String EMBEDDED_UNBOUNDID = PREFIX + "unboundidServerContainer"; public static final String CONTEXT_SOURCE = PREFIX + "securityContextSource"; diff --git a/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java index c54d6378ec..0f47afa594 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java @@ -37,7 +37,6 @@ import org.springframework.security.ldap.authentication.LdapAuthenticator; import org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator; import org.springframework.security.ldap.search.FilterBasedLdapUserSearch; import org.springframework.security.ldap.search.LdapUserSearch; -import org.springframework.security.ldap.server.ApacheDSContainer; import org.springframework.security.ldap.server.UnboundIdContainer; import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator; import org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper; @@ -60,12 +59,8 @@ import org.springframework.util.ClassUtils; public class LdapAuthenticationProviderConfigurer> extends SecurityConfigurerAdapter { - private static final String APACHEDS_CLASSNAME = "org.apache.directory.server.core.DefaultDirectoryService"; - private static final String UNBOUNDID_CLASSNAME = "com.unboundid.ldap.listener.InMemoryDirectoryServer"; - private static final boolean apacheDsPresent; - private static final boolean unboundIdPresent; private String groupRoleAttribute = "cn"; @@ -100,7 +95,6 @@ public class LdapAuthenticationProviderConfigurer with no Id), that server will be used. diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd index 4ff414800b..676b55a13d 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd +++ b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd @@ -224,13 +224,12 @@ - Explicitly specifies which embedded ldap server should use. Values are 'apacheds' and + Explicitly specifies which embedded ldap server should use. The only supported value is 'unboundid'. By default, it will depends if the library is available in the classpath. - diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/SecurityReactorContextConfigurationResourceServerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/SecurityReactorContextConfigurationResourceServerTests.java index 95f85c9be4..76001a2fac 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/SecurityReactorContextConfigurationResourceServerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/SecurityReactorContextConfigurationResourceServerTests.java @@ -21,7 +21,6 @@ import okhttp3.mockwebserver.Dispatcher; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.RecordedRequest; -import org.apache.commons.lang.StringUtils; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -39,6 +38,7 @@ import org.springframework.security.oauth2.server.resource.web.reactive.function import org.springframework.security.web.SecurityFilterChain; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.reactive.function.client.WebClient; @@ -197,7 +197,7 @@ public class SecurityReactorContextConfigurationResourceServerTests { public MockResponse dispatch(RecordedRequest request) { MockResponse response = new MockResponse().setResponseCode(200); String header = request.getHeader("Authorization"); - if (StringUtils.isBlank(header)) { + if (!StringUtils.hasText(header)) { return response; } return response.setBody(header); diff --git a/config/src/test/java/org/springframework/security/config/doc/XsdDocumentedTests.java b/config/src/test/java/org/springframework/security/config/doc/XsdDocumentedTests.java index ccab6cb535..5607501eda 100644 --- a/config/src/test/java/org/springframework/security/config/doc/XsdDocumentedTests.java +++ b/config/src/test/java/org/springframework/security/config/doc/XsdDocumentedTests.java @@ -30,12 +30,12 @@ import java.util.TreeMap; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.commons.lang.StringUtils; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.springframework.core.io.ClassPathResource; import org.springframework.security.config.http.SecurityFiltersAssertions; +import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -86,7 +86,7 @@ public class XsdDocumentedTests { .flatMap(XmlNode::children) .flatMap(XmlNode::children) .map((node) -> node.attribute("value")) - .filter(StringUtils::isNotEmpty) + .filter(StringUtils::hasText) .collect(Collectors.toList()); // @formatter:on SecurityFiltersAssertions.assertEquals(nodes); @@ -129,7 +129,7 @@ public class XsdDocumentedTests { .flatMap(XmlNode::children) .flatMap(XmlNode::children) .map((node) -> node.attribute("value")) - .filter(StringUtils::isNotEmpty) + .filter(StringUtils::hasText) .collect(Collectors.toList()); // @formatter:on assertThat(nodes).isEqualTo(expected); diff --git a/config/src/test/resources/logback-test.xml b/config/src/test/resources/logback-test.xml index fc35a34be1..e107f50bc8 100644 --- a/config/src/test/resources/logback-test.xml +++ b/config/src/test/resources/logback-test.xml @@ -7,8 +7,6 @@ - - diff --git a/dependencies/spring-security-dependencies.gradle b/dependencies/spring-security-dependencies.gradle index 2a2d433252..1a8be3ff73 100644 --- a/dependencies/spring-security-dependencies.gradle +++ b/dependencies/spring-security-dependencies.gradle @@ -49,12 +49,6 @@ dependencies { api libs.ldapsdk api libs.net.sourceforge.htmlunit api libs.org.htmlunit.htmlunit - api libs.org.apache.directory.server.apacheds.entry - api libs.org.apache.directory.server.apacheds.core - api libs.org.apache.directory.server.apacheds.protocol.ldap - api libs.org.apache.directory.server.apacheds.protocol.shared - api libs.org.apache.directory.server.apacheds.server.jndi - api libs.org.apache.directory.shared.shared.ldap api libs.org.apache.httpcomponents.httpclient api libs.org.aspectj.aspectjrt api libs.org.aspectj.aspectjweaver diff --git a/docs/modules/ROOT/pages/modules.adoc b/docs/modules/ROOT/pages/modules.adoc index df36c89014..12c2fca3b1 100644 --- a/docs/modules/ROOT/pages/modules.adoc +++ b/docs/modules/ROOT/pages/modules.adoc @@ -166,13 +166,9 @@ The top-level package is `org.springframework.security.ldap`. | | Data exception classes are required. -| apache-ds -| 1.5.5 -| Required if you are using an embedded LDAP server (optional). If you use `apache-ds`, the `apacheds-core`, `apacheds-core-entry`, `apacheds-protocol-shared`, `apacheds-protocol-ldap` and `apacheds-server-jndi` modules are required. - -| shared-ldap -| 0.9.15 -| Required if you are using an embedded LDAP server (optional). +| com.unboundid:unboundid-ldapsdk +| +| Required if using an embedded LDAP server | ldapsdk | 4.1 diff --git a/docs/modules/ROOT/pages/servlet/appendix/faq.adoc b/docs/modules/ROOT/pages/servlet/appendix/faq.adoc index d987b67642..0c72852891 100644 --- a/docs/modules/ROOT/pages/servlet/appendix/faq.adoc +++ b/docs/modules/ROOT/pages/servlet/appendix/faq.adoc @@ -363,7 +363,7 @@ This section addresses common Spring Security architecture questions: . <> . <> . <> -. <> +. <> . <> @@ -412,30 +412,39 @@ The reference manual also includes <> that lists If you build your project with Maven, adding the appropriate Spring Security modules as dependencies to your `pom.xml` file automatically pulls in the core jars that the framework requires. Any that are marked as "`optional`" in the Spring Security `pom.xml` files have to be added to your own `pom.xml` file if you need them. +[[appendix-faq-unboundid-deps]] +=== What dependences are needed to run an embedded UnboundID LDAP server? + +You need to add the following dependency to your project: + +[tabs] +====== +Maven:: ++ +[source,maven,role="primary"] +---- + + com.unboundid + unboundid-ldapsdk + 7.0.1 + runtime + +---- + +Gradle:: ++ +[source,gradle,role="secondary"] +---- +implementation 'com.unboundid:unboundid-ldapsdk:7.0.1' +---- +====== + + [[appendix-faq-apacheds-deps]] === What dependencies are needed to run an embedded ApacheDS LDAP server? -If you use Maven, you need to add the following to your `pom.xml` file dependencies: - -[source] ----- - - - org.apache.directory.server - apacheds-core - 1.5.5 - runtime - - - org.apache.directory.server - apacheds-server-jndi - 1.5.5 - runtime - - ----- - -The other required jars should be pulled in transitively. +Spring Security 7 removes support for Apache DS. +Please use <> instead. [[appendix-faq-what-is-userdetailservice]] === What is a UserDetailsService and do I need one? diff --git a/docs/modules/ROOT/pages/servlet/appendix/namespace/ldap.adoc b/docs/modules/ROOT/pages/servlet/appendix/namespace/ldap.adoc index f3c07e6d76..819189b0b3 100644 --- a/docs/modules/ROOT/pages/servlet/appendix/namespace/ldap.adoc +++ b/docs/modules/ROOT/pages/servlet/appendix/namespace/ldap.adoc @@ -24,7 +24,7 @@ This is actually the bean `id` of the `ContextSource` instance, if you want to u [[nsa-ldap-server-mode]] * **mode** -Explicitly specifies which embedded ldap server should use. Values are `apacheds` and `unboundid`. By default, it will depends if the library is available in the classpath. +Explicitly specifies which embedded ldap server should use. The only supported value is `unboundid`. By default, it will depends if the library is available in the classpath. [[nsa-ldap-server-id]] * **id** diff --git a/docs/modules/ROOT/pages/servlet/authentication/passwords/ldap.adoc b/docs/modules/ROOT/pages/servlet/authentication/passwords/ldap.adoc index de64a1d448..1ee0668e7a 100644 --- a/docs/modules/ROOT/pages/servlet/authentication/passwords/ldap.adoc +++ b/docs/modules/ROOT/pages/servlet/authentication/passwords/ldap.adoc @@ -223,82 +223,8 @@ fun ldapContainer(): UnboundIdContainer { [[servlet-authentication-ldap-apacheds]] === Embedded ApacheDS Server -[NOTE] -==== -Spring Security uses ApacheDS 1.x, which is no longer maintained. -Unfortunately, ApacheDS 2.x has only released milestone versions with no stable release. -Once a stable release of ApacheDS 2.x is available, we will consider updating. -==== - -If you wish to use https://directory.apache.org/apacheds/[Apache DS], specify the following dependencies: - -.ApacheDS Dependencies -[tabs] -====== -Maven:: -+ -[source,xml,role="primary",subs="+attributes"] ----- - - org.apache.directory.server - apacheds-core - {apacheds-core-version} - runtime - - - org.apache.directory.server - apacheds-server-jndi - {apacheds-core-version} - runtime - ----- - -Gradle:: -+ -[source,groovy,role="secondary",subs="+attributes"] ----- -depenendencies { - runtimeOnly "org.apache.directory.server:apacheds-core:{apacheds-core-version}" - runtimeOnly "org.apache.directory.server:apacheds-server-jndi:{apacheds-core-version}" -} ----- -====== - -You can then configure the Embedded LDAP Server: - -.Embedded LDAP Server Configuration -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Bean -ApacheDSContainer ldapContainer() { - return new ApacheDSContainer("dc=springframework,dc=org", - "classpath:users.ldif"); -} ----- - -XML:: -+ -[source,xml,role="secondary"] ----- - ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Bean -fun ldapContainer(): ApacheDSContainer { - return ApacheDSContainer("dc=springframework,dc=org", "classpath:users.ldif") -} ----- -====== +Spring Security 7 removes support for Apache DS. +Please use <> instead. [[servlet-authentication-ldap-contextsource]] == LDAP ContextSource diff --git a/docs/modules/ROOT/pages/servlet/configuration/xml-namespace.adoc b/docs/modules/ROOT/pages/servlet/configuration/xml-namespace.adoc index e6f2ed028d..ddf652799c 100644 --- a/docs/modules/ROOT/pages/servlet/configuration/xml-namespace.adoc +++ b/docs/modules/ROOT/pages/servlet/configuration/xml-namespace.adoc @@ -15,7 +15,7 @@ For example, adding the following element from the `security` namespace to an ap ---- -This is much simpler than wiring up the equivalent Apache Directory Server beans. +This is much simpler than wiring up the equivalent UnboundID Server beans. The most common alternative configuration requirements are supported by attributes on the `ldap-server` element, and the user is isolated from worrying about which beans they need to create and what the bean property names are. You can find out more about the use of the `ldap-server` element in the chapter on xref:servlet/authentication/passwords/ldap.adoc#servlet-authentication-ldap[LDAP Authentication]. A good XML editor while editing the application context file should provide information on the attributes and elements that are available. diff --git a/docs/spring-security-docs.gradle b/docs/spring-security-docs.gradle index 680ab725e9..23e8d0db91 100644 --- a/docs/spring-security-docs.gradle +++ b/docs/spring-security-docs.gradle @@ -45,7 +45,6 @@ dependencies { testImplementation libs.webauthn4j.core testImplementation 'org.jetbrains.kotlin:kotlin-reflect' testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' - testImplementation 'org.apache.directory.server:apacheds-core' testImplementation 'org.springframework:spring-core' testImplementation 'org.springframework:spring-test' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1969124ad4..acd27bc3f4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,7 +4,6 @@ io-rsocket = "1.1.5" io-spring-javaformat = "0.0.46" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" -org-apache-directory-server = "1.5.5" org-apache-maven-resolver = "1.9.23" org-aspectj = "1.9.24" org-bouncycastle = "1.80" @@ -50,12 +49,6 @@ jakarta-xml-bind-jakarta-xml-bind-api = "jakarta.xml.bind:jakarta.xml.bind-api:4 ldapsdk = "ldapsdk:ldapsdk:4.1" net-sourceforge-htmlunit = "net.sourceforge.htmlunit:htmlunit:2.70.0" org-htmlunit-htmlunit = "org.htmlunit:htmlunit:4.11.1" -org-apache-directory-server-apacheds-core = { module = "org.apache.directory.server:apacheds-core", version.ref = "org-apache-directory-server" } -org-apache-directory-server-apacheds-entry = { module = "org.apache.directory.server:apacheds-core-entry", version.ref = "org-apache-directory-server" } -org-apache-directory-server-apacheds-protocol-ldap = { module = "org.apache.directory.server:apacheds-protocol-ldap", version.ref = "org-apache-directory-server" } -org-apache-directory-server-apacheds-protocol-shared = { module = "org.apache.directory.server:apacheds-protocol-shared", version.ref = "org-apache-directory-server" } -org-apache-directory-server-apacheds-server-jndi = { module = "org.apache.directory.server:apacheds-server-jndi", version.ref = "org-apache-directory-server" } -org-apache-directory-shared-shared-ldap = "org.apache.directory.shared:shared-ldap:0.9.15" org-apache-httpcomponents-httpclient = "org.apache.httpcomponents:httpclient:4.5.14" org-apache-maven-maven-resolver-provider = "org.apache.maven:maven-resolver-provider:3.9.10" org-apache-maven-resolver-maven-resolver-connector-basic = { module = "org.apache.maven.resolver:maven-resolver-connector-basic", version.ref = "org-apache-maven-resolver" } diff --git a/itest/ldap/embedded-ldap-apacheds-default/spring-security-itest-ldap-embedded-apacheds-default.gradle b/itest/ldap/embedded-ldap-apacheds-default/spring-security-itest-ldap-embedded-apacheds-default.gradle deleted file mode 100644 index b48ab908a9..0000000000 --- a/itest/ldap/embedded-ldap-apacheds-default/spring-security-itest-ldap-embedded-apacheds-default.gradle +++ /dev/null @@ -1,30 +0,0 @@ -apply plugin: 'io.spring.convention.spring-test' - -dependencies { - implementation platform(project(":spring-security-dependencies")) - implementation project(':spring-security-core') - implementation 'org.springframework:spring-beans' - implementation 'org.springframework:spring-context' - implementation 'org.springframework:spring-core' - implementation 'org.springframework:spring-tx' - implementation project(':spring-security-config') - implementation project(':spring-security-ldap') - - runtimeOnly "org.apache.directory.server:apacheds-core" - runtimeOnly "org.apache.directory.server:apacheds-core-entry" - runtimeOnly "org.apache.directory.server:apacheds-protocol-shared" - runtimeOnly "org.apache.directory.server:apacheds-protocol-ldap" - runtimeOnly "org.apache.directory.server:apacheds-server-jndi" - runtimeOnly 'org.apache.directory.shared:shared-ldap' - - testImplementation project(path : ':spring-security-ldap', configuration : 'tests') - testImplementation "org.assertj:assertj-core" - testImplementation "org.junit.jupiter:junit-jupiter-api" - testImplementation "org.junit.jupiter:junit-jupiter-params" - testImplementation "org.junit.jupiter:junit-jupiter-engine" - testImplementation "org.mockito:mockito-core" - testImplementation "org.mockito:mockito-junit-jupiter" - testImplementation "org.springframework:spring-test" - - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' -} diff --git a/itest/ldap/embedded-ldap-apacheds-default/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java b/itest/ldap/embedded-ldap-apacheds-default/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java deleted file mode 100644 index 4f2be179a3..0000000000 --- a/itest/ldap/embedded-ldap-apacheds-default/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.context.support.ClassPathXmlApplicationContext; -import org.springframework.security.config.BeanIds; -import org.springframework.security.ldap.server.ApacheDSContainer; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - */ -public class LdapServerBeanDefinitionParserTests { - - private ClassPathXmlApplicationContext context; - - @BeforeEach - public void setup() { - this.context = new ClassPathXmlApplicationContext("applicationContext-security.xml"); - } - - @AfterEach - public void closeAppContext() { - if (this.context != null) { - this.context.close(); - this.context = null; - } - } - - @Test - public void apacheDirectoryServerIsStartedByDefault() { - String[] beanNames = this.context.getBeanNamesForType(ApacheDSContainer.class); - assertThat(beanNames).hasSize(1); - assertThat(beanNames[0]).isEqualTo(BeanIds.EMBEDDED_APACHE_DS); - } - -} diff --git a/itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/applicationContext-security.xml b/itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/applicationContext-security.xml deleted file mode 100644 index b1b80079c5..0000000000 --- a/itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/applicationContext-security.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - diff --git a/itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/users.ldif b/itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/users.ldif deleted file mode 100644 index 222e03793c..0000000000 --- a/itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/users.ldif +++ /dev/null @@ -1,60 +0,0 @@ -dn: ou=groups,dc=springframework,dc=org -objectclass: top -objectclass: organizationalUnit -ou: groups - -dn: ou=people,dc=springframework,dc=org -objectclass: top -objectclass: organizationalUnit -ou: people - -dn: uid=rod,ou=people,dc=springframework,dc=org -objectclass: top -objectclass: person -objectclass: organizationalPerson -objectclass: inetOrgPerson -cn: Rod Johnson -sn: Johnson -uid: rod -userPassword: koala - -dn: uid=dianne,ou=people,dc=springframework,dc=org -objectclass: top -objectclass: person -objectclass: organizationalPerson -objectclass: inetOrgPerson -cn: Dianne Emu -sn: Emu -uid: dianne -userPassword: emu - -dn: uid=scott,ou=people,dc=springframework,dc=org -objectclass: top -objectclass: person -objectclass: organizationalPerson -objectclass: inetOrgPerson -cn: Scott -sn: Wombat -uid: scott -userPassword: wombat - -dn: cn=user,ou=groups,dc=springframework,dc=org -objectclass: top -objectclass: groupOfNames -cn: user -member: uid=rod,ou=people,dc=springframework,dc=org -member: uid=dianne,ou=people,dc=springframework,dc=org -member: uid=scott,ou=people,dc=springframework,dc=org - -dn: cn=teller,ou=groups,dc=springframework,dc=org -objectclass: top -objectclass: groupOfNames -cn: teller -member: uid=rod,ou=people,dc=springframework,dc=org -member: uid=dianne,ou=people,dc=springframework,dc=org - -dn: cn=supervisor,ou=groups,dc=springframework,dc=org -objectclass: top -objectclass: groupOfNames -cn: supervisor -member: uid=rod,ou=people,dc=springframework,dc=org diff --git a/itest/ldap/embedded-ldap-mode-apacheds/spring-security-itest-ldap-embedded-mode-apacheds.gradle b/itest/ldap/embedded-ldap-mode-apacheds/spring-security-itest-ldap-embedded-mode-apacheds.gradle deleted file mode 100644 index b48ab908a9..0000000000 --- a/itest/ldap/embedded-ldap-mode-apacheds/spring-security-itest-ldap-embedded-mode-apacheds.gradle +++ /dev/null @@ -1,30 +0,0 @@ -apply plugin: 'io.spring.convention.spring-test' - -dependencies { - implementation platform(project(":spring-security-dependencies")) - implementation project(':spring-security-core') - implementation 'org.springframework:spring-beans' - implementation 'org.springframework:spring-context' - implementation 'org.springframework:spring-core' - implementation 'org.springframework:spring-tx' - implementation project(':spring-security-config') - implementation project(':spring-security-ldap') - - runtimeOnly "org.apache.directory.server:apacheds-core" - runtimeOnly "org.apache.directory.server:apacheds-core-entry" - runtimeOnly "org.apache.directory.server:apacheds-protocol-shared" - runtimeOnly "org.apache.directory.server:apacheds-protocol-ldap" - runtimeOnly "org.apache.directory.server:apacheds-server-jndi" - runtimeOnly 'org.apache.directory.shared:shared-ldap' - - testImplementation project(path : ':spring-security-ldap', configuration : 'tests') - testImplementation "org.assertj:assertj-core" - testImplementation "org.junit.jupiter:junit-jupiter-api" - testImplementation "org.junit.jupiter:junit-jupiter-params" - testImplementation "org.junit.jupiter:junit-jupiter-engine" - testImplementation "org.mockito:mockito-core" - testImplementation "org.mockito:mockito-junit-jupiter" - testImplementation "org.springframework:spring-test" - - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' -} diff --git a/itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java b/itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java deleted file mode 100644 index 4f2be179a3..0000000000 --- a/itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.context.support.ClassPathXmlApplicationContext; -import org.springframework.security.config.BeanIds; -import org.springframework.security.ldap.server.ApacheDSContainer; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - */ -public class LdapServerBeanDefinitionParserTests { - - private ClassPathXmlApplicationContext context; - - @BeforeEach - public void setup() { - this.context = new ClassPathXmlApplicationContext("applicationContext-security.xml"); - } - - @AfterEach - public void closeAppContext() { - if (this.context != null) { - this.context.close(); - this.context = null; - } - } - - @Test - public void apacheDirectoryServerIsStartedByDefault() { - String[] beanNames = this.context.getBeanNamesForType(ApacheDSContainer.class); - assertThat(beanNames).hasSize(1); - assertThat(beanNames[0]).isEqualTo(BeanIds.EMBEDDED_APACHE_DS); - } - -} diff --git a/itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/applicationContext-security.xml b/itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/applicationContext-security.xml deleted file mode 100644 index 8e3f4b4380..0000000000 --- a/itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/applicationContext-security.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - diff --git a/itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/users.ldif b/itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/users.ldif deleted file mode 100644 index 222e03793c..0000000000 --- a/itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/users.ldif +++ /dev/null @@ -1,60 +0,0 @@ -dn: ou=groups,dc=springframework,dc=org -objectclass: top -objectclass: organizationalUnit -ou: groups - -dn: ou=people,dc=springframework,dc=org -objectclass: top -objectclass: organizationalUnit -ou: people - -dn: uid=rod,ou=people,dc=springframework,dc=org -objectclass: top -objectclass: person -objectclass: organizationalPerson -objectclass: inetOrgPerson -cn: Rod Johnson -sn: Johnson -uid: rod -userPassword: koala - -dn: uid=dianne,ou=people,dc=springframework,dc=org -objectclass: top -objectclass: person -objectclass: organizationalPerson -objectclass: inetOrgPerson -cn: Dianne Emu -sn: Emu -uid: dianne -userPassword: emu - -dn: uid=scott,ou=people,dc=springframework,dc=org -objectclass: top -objectclass: person -objectclass: organizationalPerson -objectclass: inetOrgPerson -cn: Scott -sn: Wombat -uid: scott -userPassword: wombat - -dn: cn=user,ou=groups,dc=springframework,dc=org -objectclass: top -objectclass: groupOfNames -cn: user -member: uid=rod,ou=people,dc=springframework,dc=org -member: uid=dianne,ou=people,dc=springframework,dc=org -member: uid=scott,ou=people,dc=springframework,dc=org - -dn: cn=teller,ou=groups,dc=springframework,dc=org -objectclass: top -objectclass: groupOfNames -cn: teller -member: uid=rod,ou=people,dc=springframework,dc=org -member: uid=dianne,ou=people,dc=springframework,dc=org - -dn: cn=supervisor,ou=groups,dc=springframework,dc=org -objectclass: top -objectclass: groupOfNames -cn: supervisor -member: uid=rod,ou=people,dc=springframework,dc=org diff --git a/ldap/spring-security-ldap.gradle b/ldap/spring-security-ldap.gradle index d15029ffdd..f816af7ab8 100644 --- a/ldap/spring-security-ldap.gradle +++ b/ldap/spring-security-ldap.gradle @@ -15,12 +15,6 @@ dependencies { optional 'com.fasterxml.jackson.core:jackson-databind' optional 'ldapsdk:ldapsdk' optional "com.unboundid:unboundid-ldapsdk" - optional "org.apache.directory.server:apacheds-core" - optional "org.apache.directory.server:apacheds-core-entry" - optional "org.apache.directory.server:apacheds-protocol-shared" - optional "org.apache.directory.server:apacheds-protocol-ldap" - optional "org.apache.directory.server:apacheds-server-jndi" - optional 'org.apache.directory.shared:shared-ldap' api ('org.springframework.ldap:spring-ldap-core') { exclude(group: 'commons-logging', module: 'commons-logging') exclude(group: 'org.springframework', module: 'spring-beans') diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/DefaultSpringSecurityContextSourceTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/DefaultSpringSecurityContextSourceTests.java index 607b0a2414..f03af31b4d 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/DefaultSpringSecurityContextSourceTests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/DefaultSpringSecurityContextSourceTests.java @@ -38,7 +38,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException * @author Eddú Meléndez */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = ApacheDsContainerConfig.class) +@ContextConfiguration(classes = UnboundIdContainerConfig.class) public class DefaultSpringSecurityContextSourceTests { @Autowired diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/SpringSecurityLdapTemplateITests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/SpringSecurityLdapTemplateITests.java index 5b7ca9f69f..25d65e1215 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/SpringSecurityLdapTemplateITests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/SpringSecurityLdapTemplateITests.java @@ -45,7 +45,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; * @author Eddú Meléndez */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = ApacheDsContainerConfig.class) +@ContextConfiguration(classes = UnboundIdContainerConfig.class) public class SpringSecurityLdapTemplateITests { @Autowired @@ -116,10 +116,10 @@ public class SpringSecurityLdapTemplateITests { assertThat(values).hasSize(1); Map> record = values.iterator().next(); assertAttributeValue(record, "uid", "bob"); - assertAttributeValue(record, "objectclass", "top", "person", "organizationalPerson", "inetOrgPerson"); + assertAttributeValue(record, "objectClass", "top", "person", "organizationalPerson", "inetOrgPerson"); assertAttributeValue(record, "cn", "Bob Hamilton"); assertAttributeValue(record, "sn", "Hamilton"); - assertThat(record.containsKey("userPassword")).isFalse(); + assertThat(record.containsKey("userPassword")).isTrue(); } @Test @@ -129,10 +129,10 @@ public class SpringSecurityLdapTemplateITests { assertThat(values).hasSize(1); Map> record = values.iterator().next(); assertAttributeValue(record, "uid", "bob"); - assertAttributeValue(record, "objectclass", "top", "person", "organizationalPerson", "inetOrgPerson"); + assertAttributeValue(record, "objectClass", "top", "person", "organizationalPerson", "inetOrgPerson"); assertAttributeValue(record, "cn", "Bob Hamilton"); assertAttributeValue(record, "sn", "Hamilton"); - assertThat(record.containsKey("userPassword")).isFalse(); + assertThat(record.containsKey("userPassword")).isTrue(); } @Test @@ -145,7 +145,7 @@ public class SpringSecurityLdapTemplateITests { assertAttributeValue(record, "cn", "Bob Hamilton"); assertAttributeValue(record, "sn", "Hamilton"); assertThat(record.containsKey("userPassword")).isFalse(); - assertThat(record.containsKey("objectclass")).isFalse(); + assertThat(record.containsKey("objectClass")).isFalse(); } protected void assertAttributeValue(Map> record, String attributeName, String... values) { diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/ApacheDsContainerConfig.java b/ldap/src/integration-test/java/org/springframework/security/ldap/UnboundIdContainerConfig.java similarity index 67% rename from ldap/src/integration-test/java/org/springframework/security/ldap/ApacheDsContainerConfig.java rename to ldap/src/integration-test/java/org/springframework/security/ldap/UnboundIdContainerConfig.java index 41478863d6..b56abddd62 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/ApacheDsContainerConfig.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/UnboundIdContainerConfig.java @@ -20,31 +20,31 @@ import org.springframework.beans.factory.DisposableBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.ldap.core.ContextSource; -import org.springframework.security.ldap.server.ApacheDSContainer; +import org.springframework.security.ldap.server.UnboundIdContainer; /** * @author Eddú Meléndez */ @Configuration -public class ApacheDsContainerConfig implements DisposableBean { +public class UnboundIdContainerConfig implements DisposableBean { - private ApacheDSContainer container; + private UnboundIdContainer container; @Bean - ApacheDSContainer ldapContainer() throws Exception { - this.container = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); + UnboundIdContainer ldapContainer() { + this.container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); this.container.setPort(0); return this.container; } @Bean - ContextSource contextSource(ApacheDSContainer ldapContainer) throws Exception { + ContextSource contextSource(UnboundIdContainer ldapContainer) { return new DefaultSpringSecurityContextSource( - "ldap://127.0.0.1:" + ldapContainer.getLocalPort() + "/dc=springframework,dc=org"); + "ldap://127.0.0.1:" + ldapContainer.getPort() + "/dc=springframework,dc=org"); } @Override - public void destroy() throws Exception { + public void destroy() { this.container.stop(); } diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/authentication/BindAuthenticatorTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/authentication/BindAuthenticatorTests.java index 95e73bd217..46f6d71fb0 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/authentication/BindAuthenticatorTests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/authentication/BindAuthenticatorTests.java @@ -33,8 +33,8 @@ import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.SpringSecurityMessageSource; -import org.springframework.security.ldap.ApacheDsContainerConfig; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; +import org.springframework.security.ldap.UnboundIdContainerConfig; import org.springframework.security.ldap.search.FilterBasedLdapUserSearch; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -53,7 +53,7 @@ import static org.mockito.Mockito.spy; * @author Eddú Meléndez */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = ApacheDsContainerConfig.class) +@ContextConfiguration(classes = UnboundIdContainerConfig.class) public class BindAuthenticatorTests { @Autowired diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/authentication/PasswordComparisonAuthenticatorTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/authentication/PasswordComparisonAuthenticatorTests.java index 5ba4a7d72c..a7598b3c4e 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/authentication/PasswordComparisonAuthenticatorTests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/authentication/PasswordComparisonAuthenticatorTests.java @@ -30,8 +30,8 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.keygen.KeyGenerators; import org.springframework.security.crypto.password.LdapShaPasswordEncoder; import org.springframework.security.crypto.password.NoOpPasswordEncoder; -import org.springframework.security.ldap.ApacheDsContainerConfig; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; +import org.springframework.security.ldap.UnboundIdContainerConfig; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -46,7 +46,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException * @author Eddú Meléndez */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = ApacheDsContainerConfig.class) +@ContextConfiguration(classes = UnboundIdContainerConfig.class) public class PasswordComparisonAuthenticatorTests { @Autowired diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchTests.java index 5dd196fb02..57b2f3bddb 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchTests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchTests.java @@ -25,8 +25,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.ldap.core.DirContextOperations; import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.security.ldap.ApacheDsContainerConfig; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; +import org.springframework.security.ldap.UnboundIdContainerConfig; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -40,7 +40,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; * @author Eddú Meléndez */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = ApacheDsContainerConfig.class) +@ContextConfiguration(classes = UnboundIdContainerConfig.class) public class FilterBasedLdapUserSearchTests { @Autowired diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchWithSpacesTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchWithSpacesTests.java index 6db08933fa..9b790f711b 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchWithSpacesTests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchWithSpacesTests.java @@ -28,7 +28,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.DirContextOperations; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; -import org.springframework.security.ldap.server.ApacheDSContainer; +import org.springframework.security.ldap.server.UnboundIdContainer; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -40,7 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Steve Riesenberg */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = FilterBasedLdapUserSearchWithSpacesTests.ApacheDsContainerWithSpacesConfig.class) +@ContextConfiguration(classes = FilterBasedLdapUserSearchWithSpacesTests.UnboundIdContainerWithSpacesConfig.class) public class FilterBasedLdapUserSearchWithSpacesTests { @Autowired @@ -61,22 +61,22 @@ public class FilterBasedLdapUserSearchWithSpacesTests { } @Configuration - static class ApacheDsContainerWithSpacesConfig implements DisposableBean { + static class UnboundIdContainerWithSpacesConfig implements DisposableBean { - private ApacheDSContainer container; + private UnboundIdContainer container; @Bean - ApacheDSContainer ldapContainer() throws Exception { - this.container = new ApacheDSContainer("dc=spring framework,dc=org", + UnboundIdContainer ldapContainer() { + this.container = new UnboundIdContainer("dc=spring framework,dc=org", "classpath:test-server-with-spaces.ldif"); this.container.setPort(0); return this.container; } @Bean - ContextSource contextSource(ApacheDSContainer ldapContainer) { + ContextSource contextSource(UnboundIdContainer ldapContainer) { return new DefaultSpringSecurityContextSource( - "ldap://127.0.0.1:" + ldapContainer.getLocalPort() + "/dc=spring%20framework,dc=org"); + "ldap://127.0.0.1:" + ldapContainer.getPort() + "/dc=spring%20framework,dc=org"); } @Override diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSContainerTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSContainerTests.java deleted file mode 100644 index f4f3953a19..0000000000 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSContainerTests.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.ldap.server; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.ServerSocket; -import java.security.UnrecoverableKeyException; -import java.util.ArrayList; -import java.util.List; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledOnOs; -import org.junit.jupiter.api.condition.OS; -import org.junit.jupiter.api.io.TempDir; - -import org.springframework.core.io.ClassPathResource; -import org.springframework.util.FileCopyUtils; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.assertj.core.api.Assertions.fail; - -/** - * Useful for debugging the container by itself. - * - * @author Luke Taylor - * @author Rob Winch - * @author Gunnar Hillert - * @author Evgeniy Cheban - * @since 3.0 - */ -public class ApacheDSContainerTests { - - @TempDir - public File temporaryFolder; - - // SEC-2162 - @Test - public void failsToStartThrowsException() throws Exception { - ApacheDSContainer server1 = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); - ApacheDSContainer server2 = new ApacheDSContainer("dc=springframework,dc=org", "classpath:missing.ldif"); - List ports = getDefaultPorts(1); - server1.setPort(ports.get(0)); - server2.setPort(ports.get(0)); - try { - server1.afterPropertiesSet(); - try { - server2.afterPropertiesSet(); - fail("Expected Exception"); - } - catch (RuntimeException success) { - } - } - finally { - try { - server1.destroy(); - } - catch (Throwable ex) { - } - try { - server2.destroy(); - } - catch (Throwable ex) { - } - } - } - - // SEC-2161 - @Test - public void multipleInstancesSimultanciously() throws Exception { - ApacheDSContainer server1 = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); - ApacheDSContainer server2 = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); - List ports = getDefaultPorts(2); - server1.setPort(ports.get(0)); - server2.setPort(ports.get(1)); - try { - server1.afterPropertiesSet(); - server2.afterPropertiesSet(); - } - finally { - try { - server1.destroy(); - } - catch (Throwable ex) { - } - try { - server2.destroy(); - } - catch (Throwable ex) { - } - } - } - - @Test - public void startWithLdapOverSslWithoutCertificate() throws Exception { - ApacheDSContainer server = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); - List ports = getDefaultPorts(1); - server.setPort(ports.get(0)); - server.setLdapOverSslEnabled(true); - assertThatIllegalArgumentException().isThrownBy(server::afterPropertiesSet) - .withMessage("When LdapOverSsl is enabled, the keyStoreFile property must be set."); - } - - @Test - @DisabledOnOs(OS.WINDOWS) - public void startWithLdapOverSslWithWrongPassword() throws Exception { - final ClassPathResource keyStoreResource = new ClassPathResource( - "/org/springframework/security/ldap/server/spring.keystore"); - final File temporaryKeyStoreFile = new File(this.temporaryFolder, "spring.keystore"); - FileCopyUtils.copy(keyStoreResource.getInputStream(), new FileOutputStream(temporaryKeyStoreFile)); - - assertThat(temporaryKeyStoreFile).isFile(); - - ApacheDSContainer server = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); - - List ports = getDefaultPorts(1); - server.setPort(ports.get(0)); - - server.setLdapOverSslEnabled(true); - server.setKeyStoreFile(temporaryKeyStoreFile); - server.setCertificatePassord("incorrect-password"); - assertThatExceptionOfType(RuntimeException.class).isThrownBy(server::afterPropertiesSet) - .withMessage("Server startup failed") - .withRootCauseInstanceOf(UnrecoverableKeyException.class); - } - - /** - * This test starts an LDAP server using LDAPs (LDAP over SSL). A self-signed - * certificate is being used, which was previously generated with: - * - *
-	 * {@code
-	 * keytool -genkey -alias spring -keyalg RSA -keystore spring.keystore -validity 3650 -storetype JKS \
-	 * -dname "CN=localhost, OU=Spring, O=Pivotal, L=Kailua-Kona, ST=HI, C=US" -keypass spring -storepass spring
-	 * }
-	 * 
- * @throws Exception - */ - @Test - @DisabledOnOs(OS.WINDOWS) - public void startWithLdapOverSsl() throws Exception { - - final ClassPathResource keyStoreResource = new ClassPathResource( - "/org/springframework/security/ldap/server/spring.keystore"); - final File temporaryKeyStoreFile = new File(this.temporaryFolder, "spring.keystore"); - FileCopyUtils.copy(keyStoreResource.getInputStream(), new FileOutputStream(temporaryKeyStoreFile)); - - assertThat(temporaryKeyStoreFile).isFile(); - - ApacheDSContainer server = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); - - List ports = getDefaultPorts(1); - server.setPort(ports.get(0)); - - server.setLdapOverSslEnabled(true); - server.setKeyStoreFile(temporaryKeyStoreFile); - server.setCertificatePassord("spring"); - - try { - server.afterPropertiesSet(); - } - finally { - try { - server.destroy(); - } - catch (Throwable ex) { - } - } - } - - private List getDefaultPorts(int count) throws IOException { - List connections = new ArrayList<>(); - List availablePorts = new ArrayList<>(count); - try { - for (int i = 0; i < count; i++) { - ServerSocket socket = new ServerSocket(0); - connections.add(socket); - availablePorts.add(socket.getLocalPort()); - } - return availablePorts; - } - finally { - for (ServerSocket conn : connections) { - conn.close(); - } - } - } - - @Test - public void afterPropertiesSetWhenPortIsZeroThenRandomPortIsSelected() throws Exception { - ApacheDSContainer server = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); - server.setPort(0); - try { - server.afterPropertiesSet(); - - assertThat(server.getPort()).isEqualTo(0); - assertThat(server.getLocalPort()).isNotEqualTo(0); - } - finally { - server.destroy(); - } - } - -} diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSEmbeddedLdifTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSEmbeddedLdifTests.java deleted file mode 100644 index 232f241845..0000000000 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSEmbeddedLdifTests.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.ldap.server; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import org.springframework.ldap.core.support.LdapContextSource; -import org.springframework.security.ldap.SpringSecurityLdapTemplate; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests reproducing problems with loading structures from ldif on embedded ApacheDS - * server. - * - * @author Marcin Zajączkowski - */ -public class ApacheDSEmbeddedLdifTests { - - private static final String LDAP_ROOT = "ou=ssattributes,dc=springframework,dc=org"; - - private static final int LDAP_PORT = 52389; - - private ApacheDSContainer server; - - private SpringSecurityLdapTemplate ldapTemplate; - - @BeforeEach - public void setUp() throws Exception { - // TODO: InMemoryXmlApplicationContext would be useful here, but it is not visible - this.server = new ApacheDSContainer(LDAP_ROOT, "classpath:test-server-custom-attribute-types.ldif"); - this.server.setPort(LDAP_PORT); - this.server.afterPropertiesSet(); - - this.ldapTemplate = new SpringSecurityLdapTemplate(createLdapContextSource()); - } - - private LdapContextSource createLdapContextSource() { - LdapContextSource ldapContextSource = new LdapContextSource(); - ldapContextSource.setUrl("ldap://localhost:" + LDAP_PORT); - ldapContextSource.setBase(LDAP_ROOT); - ldapContextSource.afterPropertiesSet(); - return ldapContextSource; - } - - @AfterEach - public void tearDown() throws Exception { - if (this.server != null) { - this.server.destroy(); - } - } - - @Disabled // Not fixed yet - @Test // SEC-2387 - public void customAttributeTypesShouldBeProperlyCreatedWhenLoadedFromLdif() { - assertThat(this.ldapTemplate.compare("uid=objectWithCustomAttribute1", "uid", "objectWithCustomAttribute1")) - .isTrue(); - assertThat(this.ldapTemplate.compare("uid=objectWithCustomAttribute1", "customAttribute", "I am custom")) - .isTrue(); - } - -} diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests.java index 95181b7651..f48f4c90b6 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests.java @@ -31,7 +31,7 @@ import org.springframework.ldap.core.DirContextAdapter; import org.springframework.ldap.core.DistinguishedName; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; -import org.springframework.security.ldap.server.ApacheDSContainer; +import org.springframework.security.ldap.server.UnboundIdContainer; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -42,7 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat; */ @ExtendWith(SpringExtension.class) @ContextConfiguration( - classes = DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests.ApacheDsContainerWithUndefinedGroupRoleAttributeConfig.class) + classes = DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests.UnboundIdContainerWithUndefinedGroupRoleAttributeConfig.class) public class DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests { @Autowired @@ -77,22 +77,22 @@ public class DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests { } @Configuration - static class ApacheDsContainerWithUndefinedGroupRoleAttributeConfig implements DisposableBean { + static class UnboundIdContainerWithUndefinedGroupRoleAttributeConfig implements DisposableBean { - private ApacheDSContainer container; + private UnboundIdContainer container; @Bean - ApacheDSContainer ldapContainer() throws Exception { - this.container = new ApacheDSContainer("dc=springframework,dc=org", + UnboundIdContainer ldapContainer() { + this.container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:test-server-with-undefined-group-role-attributes.ldif"); this.container.setPort(0); return this.container; } @Bean - ContextSource contextSource(ApacheDSContainer ldapContainer) { + ContextSource contextSource(UnboundIdContainer ldapContainer) { return new DefaultSpringSecurityContextSource( - "ldap://127.0.0.1:" + ldapContainer.getLocalPort() + "/dc=springframework,dc=org"); + "ldap://127.0.0.1:" + ldapContainer.getPort() + "/dc=springframework,dc=org"); } @Override diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorTests.java index 1d6e2d6664..a7fc6aafc5 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorTests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorTests.java @@ -31,8 +31,8 @@ import org.springframework.ldap.core.DirContextOperations; import org.springframework.ldap.core.DistinguishedName; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.ldap.ApacheDsContainerConfig; import org.springframework.security.ldap.SpringSecurityLdapTemplate; +import org.springframework.security.ldap.UnboundIdContainerConfig; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -44,7 +44,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException * @author Eddú Meléndez */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = ApacheDsContainerConfig.class) +@ContextConfiguration(classes = UnboundIdContainerConfig.class) @SuppressWarnings({ "deprecation" }) public class DefaultLdapAuthoritiesPopulatorTests { diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/LdapUserDetailsManagerTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/LdapUserDetailsManagerTests.java index 0a53171efb..df1f8b6e39 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/LdapUserDetailsManagerTests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/LdapUserDetailsManagerTests.java @@ -34,9 +34,9 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.core.context.SecurityContextImpl; import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.security.ldap.ApacheDsContainerConfig; import org.springframework.security.ldap.DefaultLdapUsernameToDnMapper; import org.springframework.security.ldap.SpringSecurityLdapTemplate; +import org.springframework.security.ldap.UnboundIdContainerConfig; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -52,7 +52,7 @@ import static org.mockito.Mockito.verify; * @author Roman Zabaluev */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = ApacheDsContainerConfig.class) +@ContextConfiguration(classes = UnboundIdContainerConfig.class) public class LdapUserDetailsManagerTests { @Autowired diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/NestedLdapAuthoritiesPopulatorTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/NestedLdapAuthoritiesPopulatorTests.java index aec53f235c..3139673b43 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/NestedLdapAuthoritiesPopulatorTests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/NestedLdapAuthoritiesPopulatorTests.java @@ -28,7 +28,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.DirContextAdapter; import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.ldap.ApacheDsContainerConfig; +import org.springframework.security.ldap.UnboundIdContainerConfig; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -39,7 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Eddú Meléndez */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = ApacheDsContainerConfig.class) +@ContextConfiguration(classes = UnboundIdContainerConfig.class) public class NestedLdapAuthoritiesPopulatorTests { @Autowired diff --git a/ldap/src/main/java/org/springframework/security/ldap/server/ApacheDSContainer.java b/ldap/src/main/java/org/springframework/security/ldap/server/ApacheDSContainer.java deleted file mode 100644 index 1fe397ac51..0000000000 --- a/ldap/src/main/java/org/springframework/security/ldap/server/ApacheDSContainer.java +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Copyright 2002-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.ldap.server; - -import java.io.File; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.directory.server.core.DefaultDirectoryService; -import org.apache.directory.server.core.authn.AuthenticationInterceptor; -import org.apache.directory.server.core.entry.ServerEntry; -import org.apache.directory.server.core.exception.ExceptionInterceptor; -import org.apache.directory.server.core.interceptor.Interceptor; -import org.apache.directory.server.core.normalization.NormalizationInterceptor; -import org.apache.directory.server.core.operational.OperationalAttributeInterceptor; -import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition; -import org.apache.directory.server.core.referral.ReferralInterceptor; -import org.apache.directory.server.core.subtree.SubentryInterceptor; -import org.apache.directory.server.ldap.LdapServer; -import org.apache.directory.server.protocol.shared.store.LdifFileLoader; -import org.apache.directory.server.protocol.shared.transport.TcpTransport; -import org.apache.directory.shared.ldap.exception.LdapNameNotFoundException; -import org.apache.directory.shared.ldap.name.LdapDN; -import org.apache.mina.transport.socket.SocketAcceptor; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.Lifecycle; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.util.Assert; - -/** - * Provides lifecycle services for the embedded apacheDS server defined by the supplied - * configuration. Used by {@code LdapServerBeanDefinitionParser}. An instance will be - * stored in the application context for each embedded server instance. It will start the - * server when the context is initialized and shut it down when it is closed. It is - * intended for temporary embedded use and will not retain changes across start/stop - * boundaries. The working directory is deleted on shutdown. - * - *

- * If used repeatedly in a single JVM process with the same configuration (for example, - * when repeatedly loading an application context during testing), it's important that the - * application context is closed to allow the bean to be disposed of and the server - * shutdown prior to attempting to start it again. - *

- * This class is intended for testing and internal security namespace use, only, and is - * not considered part of the framework's public API. - * - * @author Luke Taylor - * @author Rob Winch - * @author Gunnar Hillert - * @author Evgeniy Cheban - * @deprecated For removal in 7.0. Use {@link UnboundIdContainer} instead because ApacheDS - * 1.x is no longer supported with no GA version to replace it. - */ -@Deprecated(since = "5.2", forRemoval = true) -public class ApacheDSContainer - implements EmbeddedLdapServerContainer, InitializingBean, DisposableBean, Lifecycle, ApplicationContextAware { - - private final Log logger = LogFactory.getLog(getClass()); - - final DefaultDirectoryService service; - - LdapServer server; - - private TcpTransport transport; - - private ApplicationContext ctxt; - - private File workingDir; - - private boolean running; - - private final String ldifResources; - - private final JdbmPartition partition; - - private final String root; - - private int port = 53389; - - private int localPort; - - private boolean ldapOverSslEnabled; - - private File keyStoreFile; - - private String certificatePassord; - - public ApacheDSContainer(String root, String ldifs) throws Exception { - this.ldifResources = ldifs; - this.service = new DefaultDirectoryService(); - List list = new ArrayList<>(); - list.add(new NormalizationInterceptor()); - list.add(new AuthenticationInterceptor()); - list.add(new ReferralInterceptor()); - list.add(new ExceptionInterceptor()); - list.add(new OperationalAttributeInterceptor()); - list.add(new SubentryInterceptor()); - this.service.setInterceptors(list); - this.partition = new JdbmPartition(); - this.partition.setId("rootPartition"); - this.partition.setSuffix(root); - this.root = root; - this.service.addPartition(this.partition); - this.service.setExitVmOnShutdown(false); - this.service.setShutdownHookEnabled(false); - this.service.getChangeLog().setEnabled(false); - this.service.setDenormalizeOpAttrsEnabled(true); - } - - @Override - public void afterPropertiesSet() throws Exception { - if (this.workingDir == null) { - String apacheWorkDir = System.getProperty("apacheDSWorkDir"); - if (apacheWorkDir == null) { - apacheWorkDir = createTempDirectory("apacheds-spring-security-"); - } - setWorkingDirectory(new File(apacheWorkDir)); - } - Assert.isTrue(!this.ldapOverSslEnabled || this.keyStoreFile != null, - "When LdapOverSsl is enabled, the keyStoreFile property must be set."); - this.server = new LdapServer(); - this.server.setDirectoryService(this.service); - // AbstractLdapIntegrationTests assume IPv4, so we specify the same here - this.transport = new TcpTransport(this.port); - if (this.ldapOverSslEnabled) { - this.transport.setEnableSSL(true); - this.server.setKeystoreFile(this.keyStoreFile.getAbsolutePath()); - this.server.setCertificatePassword(this.certificatePassord); - } - this.server.setTransports(this.transport); - start(); - } - - @Override - public void destroy() { - stop(); - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.ctxt = applicationContext; - } - - public void setWorkingDirectory(File workingDir) { - Assert.notNull(workingDir, "workingDir cannot be null"); - this.logger.info("Setting working directory for LDAP_PROVIDER: " + workingDir.getAbsolutePath()); - Assert.isTrue(!workingDir.exists(), - "The specified working directory '" + workingDir.getAbsolutePath() - + "' already exists. Another directory service instance may be using it or it may be from a " - + " previous unclean shutdown. Please confirm and delete it or configure a different " - + "working directory"); - this.workingDir = workingDir; - this.service.setWorkingDirectory(workingDir); - } - - @Override - public void setPort(int port) { - this.port = port; - } - - @Override - public int getPort() { - return this.port; - } - - /** - * Returns the port that is resolved by {@link TcpTransport}. - * @return the port that is resolved by {@link TcpTransport} - */ - public int getLocalPort() { - return this.localPort; - } - - /** - * If set to {@code true} will enable LDAP over SSL (LDAPs). If set to {@code true} - * {@link ApacheDSContainer#setCertificatePassord(String)} must be set as well. - * @param ldapOverSslEnabled If not set, will default to false - */ - public void setLdapOverSslEnabled(boolean ldapOverSslEnabled) { - this.ldapOverSslEnabled = ldapOverSslEnabled; - } - - /** - * The keyStore must not be null and must be a valid file. Will set the keyStore file - * on the underlying {@link LdapServer}. - * @param keyStoreFile Mandatory if LDAPs is enabled - */ - public void setKeyStoreFile(File keyStoreFile) { - Assert.notNull(keyStoreFile, "The keyStoreFile must not be null."); - Assert.isTrue(keyStoreFile.isFile(), "The keyStoreFile must be a file."); - this.keyStoreFile = keyStoreFile; - } - - /** - * Will set the certificate password on the underlying {@link LdapServer}. - * @param certificatePassord May be null - */ - public void setCertificatePassord(String certificatePassord) { - this.certificatePassord = certificatePassord; - } - - public DefaultDirectoryService getService() { - return this.service; - } - - @Override - public void start() { - if (isRunning()) { - return; - } - Assert.state(!this.service.isStarted(), "DirectoryService is already running."); - this.logger.info("Starting directory server..."); - try { - this.service.startup(); - this.server.start(); - } - catch (Exception ex) { - throw new RuntimeException("Server startup failed", ex); - } - try { - this.service.getAdminSession().lookup(this.partition.getSuffixDn()); - } - catch (LdapNameNotFoundException ex) { - handleLdapNameNotFoundException(); - } - catch (Exception ex) { - this.logger.error("Lookup failed", ex); - } - SocketAcceptor socketAcceptor = this.server.getSocketAcceptor(this.transport); - InetSocketAddress localAddress = socketAcceptor.getLocalAddress(); - this.localPort = localAddress.getPort(); - this.running = true; - try { - importLdifs(); - } - catch (Exception ex) { - throw new RuntimeException("Failed to import LDIF file(s)", ex); - } - } - - private void handleLdapNameNotFoundException() { - try { - LdapDN dn = new LdapDN(this.root); - Assert.isTrue(this.root.startsWith("dc="), "root must start with dc="); - String dc = this.root.substring(3, this.root.indexOf(',')); - ServerEntry entry = this.service.newEntry(dn); - entry.add("objectClass", "top", "domain", "extensibleObject"); - entry.add("dc", dc); - this.service.getAdminSession().add(entry); - } - catch (Exception ex) { - this.logger.error("Failed to create dc entry", ex); - } - } - - @Override - public void stop() { - if (!isRunning()) { - return; - } - this.logger.info("Shutting down directory server ..."); - try { - this.server.stop(); - this.service.shutdown(); - } - catch (Exception ex) { - this.logger.error("Shutdown failed", ex); - return; - } - this.running = false; - if (this.workingDir.exists()) { - this.logger.info("Deleting working directory " + this.workingDir.getAbsolutePath()); - deleteDir(this.workingDir); - } - } - - private void importLdifs() throws Exception { - // Import any ldif files - Resource[] ldifs = (this.ctxt != null) ? this.ctxt.getResources(this.ldifResources) - : new PathMatchingResourcePatternResolver().getResources(this.ldifResources); - // Note that we can't just import using the ServerContext returned - // from starting Apache DS, apparently because of the long-running issue - // DIRSERVER-169. - // We need a standard context. - // DirContext dirContext = contextSource.getReadWriteContext(); - if (ldifs == null || ldifs.length == 0) { - return; - } - Assert.isTrue(ldifs.length == 1, () -> "More than one LDIF resource found with the supplied pattern:" - + this.ldifResources + " Got " + Arrays.toString(ldifs)); - String ldifFile = getLdifFile(ldifs); - this.logger.info("Loading LDIF file: " + ldifFile); - LdifFileLoader loader = new LdifFileLoader(this.service.getAdminSession(), new File(ldifFile), null, - getClass().getClassLoader()); - loader.execute(); - } - - private String getLdifFile(Resource[] ldifs) throws IOException { - try { - return ldifs[0].getFile().getAbsolutePath(); - } - catch (IOException ex) { - return ldifs[0].getURI().toString(); - } - } - - private String createTempDirectory(String prefix) throws IOException { - String parentTempDir = System.getProperty("java.io.tmpdir"); - String fileNamePrefix = prefix + System.nanoTime(); - String fileName = fileNamePrefix; - for (int i = 0; i < 1000; i++) { - File tempDir = new File(parentTempDir, fileName); - if (!tempDir.exists()) { - return tempDir.getAbsolutePath(); - } - fileName = fileNamePrefix + "~" + i; - } - throw new IOException( - "Failed to create a temporary directory for file at " + new File(parentTempDir, fileNamePrefix)); - } - - private boolean deleteDir(File dir) { - if (dir.isDirectory()) { - String[] children = dir.list(); - for (String child : children) { - boolean success = deleteDir(new File(dir, child)); - if (!success) { - return false; - } - } - } - return dir.delete(); - } - - @Override - public boolean isRunning() { - return this.running; - } - -} diff --git a/ldap/src/main/java/org/springframework/security/ldap/server/package-info.java b/ldap/src/main/java/org/springframework/security/ldap/server/package-info.java index eb33468157..52f0ab3da2 100644 --- a/ldap/src/main/java/org/springframework/security/ldap/server/package-info.java +++ b/ldap/src/main/java/org/springframework/security/ldap/server/package-info.java @@ -15,7 +15,6 @@ */ /** - * Embedded Apache Directory Server implementation, as used by the configuration - * namespace. + * Embedded UnboundID Server implementation, as used by the configuration namespace. */ package org.springframework.security.ldap.server; diff --git a/ldap/src/test/java/org/apache/directory/server/core/avltree/ArrayMarshaller.java b/ldap/src/test/java/org/apache/directory/server/core/avltree/ArrayMarshaller.java deleted file mode 100644 index c2d02fc9f2..0000000000 --- a/ldap/src/test/java/org/apache/directory/server/core/avltree/ArrayMarshaller.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2002-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.directory.server.core.avltree; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.Comparator; - -import org.apache.directory.shared.ldap.util.StringTools; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class to serialize the Array data. - * - * @author Apache Directory Project - * @version $Rev$, $Date$ - */ -@SuppressWarnings("unchecked") -public class ArrayMarshaller implements Marshaller> { - - /** static logger */ - private static final Logger LOG = LoggerFactory.getLogger(ArrayMarshaller.class); - - /** used for serialized form of an empty AvlTree */ - private static final byte[] EMPTY_TREE = new byte[1]; - - /** marshaller to be used for marshalling the keys */ - private Marshaller keyMarshaller; - - /** key Comparator for the AvlTree */ - private Comparator comparator; - - /** - * Creates a new instance of AvlTreeMarshaller with a custom key Marshaller. - * @param comparator Comparator to be used for key comparision - * @param keyMarshaller marshaller for keys - */ - public ArrayMarshaller(Comparator comparator, Marshaller keyMarshaller) { - this.comparator = comparator; - this.keyMarshaller = keyMarshaller; - } - - /** - * Creates a new instance of AvlTreeMarshaller with the default key Marshaller which - * uses Java Serialization. - * @param comparator Comparator to be used for key comparision - */ - public ArrayMarshaller(Comparator comparator) { - this.comparator = comparator; - this.keyMarshaller = DefaultMarshaller.INSTANCE; - } - - /** - * Marshals the given tree to bytes - * @param tree the tree to be marshalled - */ - public byte[] serialize(ArrayTree tree) { - if ((tree == null) || tree.isEmpty()) { - return EMPTY_TREE; - } - - ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(byteStream); - byte[] data = null; - - try { - out.writeByte(0); // represents the start of an Array byte stream - out.writeInt(tree.size()); - - for (int position = 0; position < tree.size(); position++) { - E value = tree.get(position); - byte[] bytes = this.keyMarshaller.serialize(value); - - // Write the key length - out.writeInt(bytes.length); - - // Write the key if its length is not null - if (bytes.length != 0) { - out.write(bytes); - } - } - - out.flush(); - data = byteStream.toByteArray(); - - // Try to deserialize, just to see - try { - deserialize(data); - } - catch (NullPointerException npe) { - System.out.println("Bad serialization, tree : [" + StringTools.dumpBytes(data) + "]"); - throw npe; - } - - out.close(); - } - catch (IOException ex) { - ex.printStackTrace(); - } - - return data; - } - - /** - * Creates an Array from given bytes of data. - * @param data byte array to be converted into an array - */ - public ArrayTree deserialize(byte[] data) throws IOException { - try { - if ((data == null) || (data.length == 0)) { - throw new IOException("Null or empty data array is invalid."); - } - - if ((data.length == 1) && (data[0] == 0)) { - E[] array = (E[]) new Object[] {}; - ArrayTree tree = new ArrayTree(this.comparator, array); - return tree; - } - - ByteArrayInputStream bin = new ByteArrayInputStream(data); - DataInputStream din = new DataInputStream(bin); - - byte startByte = din.readByte(); - - if (startByte != 0) { - throw new IOException("wrong array serialized data format"); - } - - int size = din.readInt(); - E[] nodes = (E[]) new Object[size]; - - for (int i = 0; i < size; i++) { - // Read the object's size - int dataSize = din.readInt(); - - if (dataSize != 0) { - byte[] bytes = new byte[dataSize]; - - din.read(bytes); - E key = this.keyMarshaller.deserialize(bytes); - nodes[i] = key; - } - } - - ArrayTree arrayTree = new ArrayTree(this.comparator, nodes); - - return arrayTree; - } - catch (NullPointerException npe) { - System.out.println("Bad tree : [" + StringTools.dumpBytes(data) + "]"); - throw npe; - } - } - -} diff --git a/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java b/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java index 6185ff81ca..0c10e1edd7 100644 --- a/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java +++ b/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java @@ -29,7 +29,6 @@ import javax.naming.directory.DirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; -import org.apache.directory.shared.ldap.util.EmptyEnumeration; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; @@ -175,7 +174,7 @@ public class ActiveDirectoryLdapAuthenticationProviderTests { @Test public void noUserSearchCausesUsernameNotFound() throws Exception { given(this.ctx.search(any(Name.class), any(String.class), any(Object[].class), any(SearchControls.class))) - .willReturn(new EmptyEnumeration<>()); + .willReturn(new MockNamingEnumeration(null)); this.provider.contextFactory = createContextFactoryReturning(this.ctx); assertThatExceptionOfType(BadCredentialsException.class).isThrownBy(() -> this.provider.authenticate(this.joe)); }