Преглед изворни кода

Remove ApacheDS Support

Closes gh-13852
Josh Cummings пре 2 месеци
родитељ
комит
6ddb964c61
49 измењених фајлова са 132 додато и 1400 уклоњено
  1. 0 6
      config/spring-security-config.gradle
  2. 5 5
      config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.java
  3. 6 6
      config/src/integration-test/java/org/springframework/security/config/ldap/LdapBindAuthenticationManagerFactoryITests.java
  4. 6 6
      config/src/integration-test/java/org/springframework/security/config/ldap/LdapPasswordComparisonAuthenticationManagerFactoryITests.java
  5. 22 1
      config/src/integration-test/java/org/springframework/security/config/ldap/LdapProviderBeanDefinitionParserTests.java
  6. 3 3
      config/src/integration-test/java/org/springframework/security/config/ldap/LdapServerBeanDefinitionParserTests.java
  7. 0 1
      config/src/integration-test/resources/logback-test.xml
  8. 0 2
      config/src/main/java/org/springframework/security/config/BeanIds.java
  9. 2 16
      config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java
  10. 3 27
      config/src/main/java/org/springframework/security/config/ldap/LdapServerBeanDefinitionParser.java
  11. 2 2
      config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc
  12. 1 2
      config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd
  13. 2 2
      config/src/test/java/org/springframework/security/config/annotation/web/configuration/SecurityReactorContextConfigurationResourceServerTests.java
  14. 3 3
      config/src/test/java/org/springframework/security/config/doc/XsdDocumentedTests.java
  15. 0 2
      config/src/test/resources/logback-test.xml
  16. 0 6
      dependencies/spring-security-dependencies.gradle
  17. 3 7
      docs/modules/ROOT/pages/modules.adoc
  18. 25 16
      docs/modules/ROOT/pages/servlet/appendix/faq.adoc
  19. 1 1
      docs/modules/ROOT/pages/servlet/appendix/namespace/ldap.adoc
  20. 2 76
      docs/modules/ROOT/pages/servlet/authentication/passwords/ldap.adoc
  21. 1 1
      docs/modules/ROOT/pages/servlet/configuration/xml-namespace.adoc
  22. 0 1
      docs/spring-security-docs.gradle
  23. 0 7
      gradle/libs.versions.toml
  24. 0 30
      itest/ldap/embedded-ldap-apacheds-default/spring-security-itest-ldap-embedded-apacheds-default.gradle
  25. 0 56
      itest/ldap/embedded-ldap-apacheds-default/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java
  26. 0 9
      itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/applicationContext-security.xml
  27. 0 60
      itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/users.ldif
  28. 0 30
      itest/ldap/embedded-ldap-mode-apacheds/spring-security-itest-ldap-embedded-mode-apacheds.gradle
  29. 0 56
      itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java
  30. 0 9
      itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/applicationContext-security.xml
  31. 0 60
      itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/users.ldif
  32. 0 6
      ldap/spring-security-ldap.gradle
  33. 1 1
      ldap/src/integration-test/java/org/springframework/security/ldap/DefaultSpringSecurityContextSourceTests.java
  34. 6 6
      ldap/src/integration-test/java/org/springframework/security/ldap/SpringSecurityLdapTemplateITests.java
  35. 8 8
      ldap/src/integration-test/java/org/springframework/security/ldap/UnboundIdContainerConfig.java
  36. 2 2
      ldap/src/integration-test/java/org/springframework/security/ldap/authentication/BindAuthenticatorTests.java
  37. 2 2
      ldap/src/integration-test/java/org/springframework/security/ldap/authentication/PasswordComparisonAuthenticatorTests.java
  38. 2 2
      ldap/src/integration-test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchTests.java
  39. 8 8
      ldap/src/integration-test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchWithSpacesTests.java
  40. 0 221
      ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSContainerTests.java
  41. 0 79
      ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSEmbeddedLdifTests.java
  42. 8 8
      ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests.java
  43. 2 2
      ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorTests.java
  44. 2 2
      ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/LdapUserDetailsManagerTests.java
  45. 2 2
      ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/NestedLdapAuthoritiesPopulatorTests.java
  46. 0 365
      ldap/src/main/java/org/springframework/security/ldap/server/ApacheDSContainer.java
  47. 1 2
      ldap/src/main/java/org/springframework/security/ldap/server/package-info.java
  48. 0 173
      ldap/src/test/java/org/apache/directory/server/core/avltree/ArrayMarshaller.java
  49. 1 2
      ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java

+ 0 - 6
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"

+ 5 - 5
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;
 		}
 
 	}

+ 6 - 6
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");
 		}
 

+ 6 - 6
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");
 		}
 

+ 22 - 1
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("""
+				<ldap-server ldif='classpath:test-server.ldif' port='0'/>
+				<authentication-manager>
+					<ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>
+						<password-compare>
+							<password-encoder ref='pe' />
+						</password-compare>
+					</ldap-authentication-provider>
+				</authentication-manager>
+				<b:bean id='pe' class='org.springframework.security.crypto.password.LdapShaPasswordEncoder' />
+				""");
+		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(

+ 3 - 3
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("<ldap-server/>");
-		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 {

+ 0 - 1
config/src/integration-test/resources/logback-test.xml

@@ -7,7 +7,6 @@
 
 	<logger name="org.springframework.security" level="${sec.log.level:-WARN}"/>
 
-	<logger name="org.apache.directory" level="ERROR"/>
 	<logger name="JdbmTable" level="INFO"/>
 	<logger name="JdbmIndex" level="INFO"/>
 	<logger name="org.apache.mina" level="WARN"/>

+ 0 - 2
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";

+ 2 - 16
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<B extends ProviderManagerBuilder<B>>
 		extends SecurityConfigurerAdapter<AuthenticationManager, B> {
 
-	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<B extends ProviderManagerBuild
 
 	static {
 		ClassLoader classLoader = LdapAuthenticationProviderConfigurer.class.getClassLoader();
-		apacheDsPresent = ClassUtils.isPresent(APACHEDS_CLASSNAME, classLoader);
 		unboundIdPresent = ClassUtils.isPresent(UNBOUNDID_CLASSNAME, classLoader);
 	}
 
@@ -467,8 +461,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
 	 */
 	public final class ContextSourceBuilder {
 
-		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 int DEFAULT_PORT = 33389;
@@ -584,14 +576,8 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
 			return contextSource;
 		}
 
-		private void startEmbeddedLdapServer() throws Exception {
-			if (apacheDsPresent) {
-				ApacheDSContainer apacheDsContainer = new ApacheDSContainer(this.root, this.ldif);
-				apacheDsContainer.setPort(getPort());
-				postProcess(apacheDsContainer);
-				this.port = apacheDsContainer.getLocalPort();
-			}
-			else if (unboundIdPresent) {
+		private void startEmbeddedLdapServer() {
+			if (unboundIdPresent) {
 				UnboundIdContainer unboundIdContainer = new UnboundIdContainer(this.root, this.ldif);
 				unboundIdContainer.setPort(getPort());
 				postProcess(unboundIdContainer);

+ 3 - 27
config/src/main/java/org/springframework/security/config/ldap/LdapServerBeanDefinitionParser.java

@@ -32,7 +32,6 @@ import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
 import org.springframework.security.config.BeanIds;
 import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
-import org.springframework.security.ldap.server.ApacheDSContainer;
 import org.springframework.security.ldap.server.UnboundIdContainer;
 import org.springframework.util.ClassUtils;
 import org.springframework.util.StringUtils;
@@ -47,7 +46,7 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
 	private static final String CONTEXT_SOURCE_CLASS = "org.springframework.security.ldap.DefaultSpringSecurityContextSource";
 
 	/**
-	 * Defines the Url of the ldap server to use. If not specified, an embedded apache DS
+	 * Defines the Url of the ldap server to use. If not specified, an embedded UnboundID
 	 * instance will be created
 	 */
 	private static final String ATT_URL = "url";
@@ -78,22 +77,15 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
 
 	private static final int DEFAULT_PORT = 33389;
 
-	private static final String APACHEDS_CLASSNAME = "org.apache.directory.server.core.DefaultDirectoryService";
-
 	private static final String UNBOUNID_CLASSNAME = "com.unboundid.ldap.listener.InMemoryDirectoryServer";
 
-	private static final String APACHEDS_CONTAINER_CLASSNAME = "org.springframework.security.ldap.server.ApacheDSContainer";
-
 	private static final String UNBOUNDID_CONTAINER_CLASSNAME = "org.springframework.security.ldap.server.UnboundIdContainer";
 
 	private static final boolean unboundIdPresent;
 
-	private static final boolean apacheDsPresent;
-
 	static {
 		ClassLoader classLoader = LdapServerBeanDefinitionParser.class.getClassLoader();
 		unboundIdPresent = ClassUtils.isPresent(UNBOUNID_CLASSNAME, classLoader);
-		apacheDsPresent = ClassUtils.isPresent(APACHEDS_CLASSNAME, classLoader);
 	}
 
 	@Override
@@ -128,10 +120,9 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
 	/**
 	 * Will be called if no url attribute is supplied.
 	 *
-	 * Registers beans to create an embedded apache directory server.
+	 * Registers beans to create an embedded UnboundID Server.
 	 * @return the BeanDefinition for the ContextSource for the embedded server.
 	 *
-	 * @see ApacheDSContainer
 	 * @see UnboundIdContainer
 	 */
 	private RootBeanDefinition createEmbeddedServer(Element element, ParserContext parserContext) {
@@ -162,8 +153,7 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
 		}
 		ldapContainer.getConstructorArgumentValues().addGenericArgumentValue(ldifs);
 		ldapContainer.getPropertyValues().addPropertyValue("port", getPort(element));
-		if (parserContext.getRegistry().containsBeanDefinition(BeanIds.EMBEDDED_APACHE_DS)
-				|| parserContext.getRegistry().containsBeanDefinition(BeanIds.EMBEDDED_UNBOUNDID)) {
+		if (parserContext.getRegistry().containsBeanDefinition(BeanIds.EMBEDDED_UNBOUNDID)) {
 			parserContext.getReaderContext()
 				.error("Only one embedded server bean is allowed per application context", element);
 		}
@@ -175,9 +165,6 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
 	}
 
 	private RootBeanDefinition getRootBeanDefinition(String mode) {
-		if (isApacheDsEnabled(mode)) {
-			return new RootBeanDefinition(APACHEDS_CONTAINER_CLASSNAME, null, null);
-		}
 		if (isUnboundidEnabled(mode)) {
 			return new RootBeanDefinition(UNBOUNDID_CONTAINER_CLASSNAME, null, null);
 		}
@@ -185,19 +172,12 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
 	}
 
 	private String resolveBeanId(String mode) {
-		if (isApacheDsEnabled(mode)) {
-			return BeanIds.EMBEDDED_APACHE_DS;
-		}
 		if (isUnboundidEnabled(mode)) {
 			return BeanIds.EMBEDDED_UNBOUNDID;
 		}
 		return null;
 	}
 
-	private boolean isApacheDsEnabled(String mode) {
-		return "apacheds".equals(mode) || apacheDsPresent;
-	}
-
 	private boolean isUnboundidEnabled(String mode) {
 		return "unboundid".equals(mode) || unboundIdPresent;
 	}
@@ -233,10 +213,6 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
 		}
 
 		private int getPort() {
-			if (apacheDsPresent) {
-				ApacheDSContainer apacheDSContainer = this.applicationContext.getBean(ApacheDSContainer.class);
-				return apacheDSContainer.getLocalPort();
-			}
 			if (unboundIdPresent) {
 				UnboundIdContainer unboundIdContainer = this.applicationContext.getBean(UnboundIdContainer.class);
 				return unboundIdContainer.getPort();

+ 2 - 2
config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc

@@ -84,8 +84,8 @@ ldap-server.attlist &=
 	## Optional root suffix for the embedded LDAP server. Default is "dc=springframework,dc=org"
 	attribute root { xsd:string }?
 ldap-server.attlist &=
-	## 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.
-	attribute mode { "apacheds" | "unboundid" }?
+	## 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.
+	attribute mode { "unboundid" }?
 
 ldap-server-ref-attribute =
 	## The optional server to use. If omitted, and a default LDAP server is registered (using <ldap-server> with no Id), that server will be used.

+ 1 - 2
config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd

@@ -224,13 +224,12 @@
       </xs:attribute>
       <xs:attribute name="mode">
          <xs:annotation>
-            <xs:documentation>Explicitly specifies which embedded ldap server should use. Values are 'apacheds' and
+            <xs:documentation>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.
                 </xs:documentation>
          </xs:annotation>
          <xs:simpleType>
             <xs:restriction base="xs:token">
-               <xs:enumeration value="apacheds"/>
                <xs:enumeration value="unboundid"/>
             </xs:restriction>
          </xs:simpleType>

+ 2 - 2
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);

+ 3 - 3
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);

+ 0 - 2
config/src/test/resources/logback-test.xml

@@ -7,8 +7,6 @@
 
 	<logger name="org.springframework.security" level="${sec.log.level:-WARN}"/>
 
-	<logger name="org.apache.directory" level="ERROR"/>
-
 	<root level="${root.level:-WARN}">
 	<appender-ref ref="STDOUT" />
 	</root>

+ 0 - 6
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

+ 3 - 7
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

+ 25 - 16
docs/modules/ROOT/pages/servlet/appendix/faq.adoc

@@ -363,7 +363,7 @@ This section addresses common Spring Security architecture questions:
 . <<appendix-faq-namespace-to-bean-mapping>>
 . <<appendix-faq-role-prefix>>
 . <<appendix-faq-what-dependencies>>
-. <<appendix-faq-apacheds-deps>>
+. <<appendix-faq-unboundid-deps>>
 . <<appendix-faq-what-is-userdetailservice>>
 
 
@@ -412,30 +412,39 @@ The reference manual also includes <<appendix-namespace,an appendix>> 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-apacheds-deps]]
-=== What dependencies are needed to run an embedded ApacheDS LDAP server?
+[[appendix-faq-unboundid-deps]]
+=== What dependences are needed to run an embedded UnboundID LDAP server?
 
-If you use Maven, you need to add the following to your `pom.xml` file dependencies:
+You need to add the following dependency to your project:
 
-[source]
+[tabs]
+======
+Maven::
++
+[source,maven,role="primary"]
 ----
-
-<dependency>
-		<groupId>org.apache.directory.server</groupId>
-		<artifactId>apacheds-core</artifactId>
-		<version>1.5.5</version>
-		<scope>runtime</scope>
-</dependency>
 <dependency>
-		<groupId>org.apache.directory.server</groupId>
-		<artifactId>apacheds-server-jndi</artifactId>
-		<version>1.5.5</version>
+		<groupId>com.unboundid</groupId>
+		<artifactId>unboundid-ldapsdk</artifactId>
+		<version>7.0.1</version>
 		<scope>runtime</scope>
 </dependency>
+----
 
+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?
 
-The other required jars should be pulled in transitively.
+Spring Security 7 removes support for Apache DS.
+Please use <<appendix-faq-unboundid-deps,UnboundID>> instead.
 
 [[appendix-faq-what-is-userdetailservice]]
 === What is a UserDetailsService and do I need one?

+ 1 - 1
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**

+ 2 - 76
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"]
-----
-<dependency>
-	<groupId>org.apache.directory.server</groupId>
-	<artifactId>apacheds-core</artifactId>
-	<version>{apacheds-core-version}</version>
-	<scope>runtime</scope>
-</dependency>
-<dependency>
-	<groupId>org.apache.directory.server</groupId>
-	<artifactId>apacheds-server-jndi</artifactId>
-	<version>{apacheds-core-version}</version>
-	<scope>runtime</scope>
-</dependency>
-----
-
-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"]
-----
-<b:bean class="org.springframework.security.ldap.server.ApacheDSContainer"
-	c:defaultPartitionSuffix="dc=springframework,dc=org"
-	c:ldif="classpath:users.ldif"/>
-----
-
-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 <<servlet-authentication-ldap-unboundid,UnboundID>> instead.
 
 [[servlet-authentication-ldap-contextsource]]
 == LDAP ContextSource

+ 1 - 1
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
 <security:ldap-server />
 ----
 
-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.

+ 0 - 1
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'
 

+ 0 - 7
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" }

+ 0 - 30
itest/ldap/embedded-ldap-apacheds-default/spring-security-itest-ldap-embedded-apacheds-default.gradle

@@ -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'
-}

+ 0 - 56
itest/ldap/embedded-ldap-apacheds-default/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java

@@ -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);
-	}
-
-}

+ 0 - 9
itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/applicationContext-security.xml

@@ -1,9 +0,0 @@
-<beans xmlns="http://www.springframework.org/schema/beans"
-	xmlns:s="http://www.springframework.org/schema/security"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
-	http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd">
-
-	<s:ldap-server ldif="classpath:users.ldif" port="0"/>
-
-</beans>

+ 0 - 60
itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/users.ldif

@@ -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

+ 0 - 30
itest/ldap/embedded-ldap-mode-apacheds/spring-security-itest-ldap-embedded-mode-apacheds.gradle

@@ -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'
-}

+ 0 - 56
itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java

@@ -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);
-	}
-
-}

+ 0 - 9
itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/applicationContext-security.xml

@@ -1,9 +0,0 @@
-<beans xmlns="http://www.springframework.org/schema/beans"
-	xmlns:s="http://www.springframework.org/schema/security"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
-	http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd">
-
-	<s:ldap-server mode="apacheds" ldif="classpath:users.ldif" port="0"/>
-
-</beans>

+ 0 - 60
itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/users.ldif

@@ -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

+ 0 - 6
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')

+ 1 - 1
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

+ 6 - 6
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<String, List<String>> 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<String, List<String>> 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<String, List<String>> record, String attributeName, String... values) {

+ 8 - 8
ldap/src/integration-test/java/org/springframework/security/ldap/ApacheDsContainerConfig.java → 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();
 	}
 

+ 2 - 2
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

+ 2 - 2
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

+ 2 - 2
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

+ 8 - 8
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

+ 0 - 221
ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSContainerTests.java

@@ -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<Integer> 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<Integer> 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<Integer> 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<Integer> 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:
-	 *
-	 * <pre>
-	 * {@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
-	 * }
-	 * </pre>
-	 * @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<Integer> 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<Integer> getDefaultPorts(int count) throws IOException {
-		List<ServerSocket> connections = new ArrayList<>();
-		List<Integer> 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();
-		}
-	}
-
-}

+ 0 - 79
ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSEmbeddedLdifTests.java

@@ -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();
-	}
-
-}

+ 8 - 8
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

+ 2 - 2
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 {
 

+ 2 - 2
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

+ 2 - 2
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

+ 0 - 365
ldap/src/main/java/org/springframework/security/ldap/server/ApacheDSContainer.java

@@ -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.
- *
- * <p>
- * 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.
- * <p>
- * 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<Interceptor> 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;
-	}
-
-}

+ 1 - 2
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;

+ 0 - 173
ldap/src/test/java/org/apache/directory/server/core/avltree/ArrayMarshaller.java

@@ -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 <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
- * @version $Rev$, $Date$
- */
-@SuppressWarnings("unchecked")
-public class ArrayMarshaller<E> implements Marshaller<ArrayTree<E>> {
-
-	/** 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<E> keyMarshaller;
-
-	/** key Comparator for the AvlTree */
-	private Comparator<E> 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<E> comparator, Marshaller<E> 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<E> 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<E> 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<E> 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<E> tree = new ArrayTree<E>(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<E> arrayTree = new ArrayTree<E>(this.comparator, nodes);
-
-			return arrayTree;
-		}
-		catch (NullPointerException npe) {
-			System.out.println("Bad tree : [" + StringTools.dumpBytes(data) + "]");
-			throw npe;
-		}
-	}
-
-}

+ 1 - 2
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));
 	}