소스 검색

Add ApacheDS Migration Steps

Issue gh-13852
Josh Cummings 2 달 전
부모
커밋
09983e2349

+ 245 - 0
docs/modules/ROOT/pages/migration-7/ldap.adoc

@@ -9,3 +9,248 @@ Consequently, support for ApacheDS will be discontinued in version 7.0.
 
 If you are currently using ApacheDS as an embedded LDAP server, we recommend migrating to https://ldap.com/unboundid-ldap-sdk-for-java/[UnboundId].
 You can find instructions in xref:servlet/authentication/passwords/ldap.adoc#servlet-authentication-ldap-embedded[this section] that describe how to set up an embedded UnboundId LDAP server.
+
+To migrate, you will need to consider the following:
+
+1. <<ldap-migrate-apacheds-unboundid-dependencies,Dependencies>>
+2. <<ldap-migrate-apacheds-unboundid-container,Container Declaration>>
+3. <<ldap-migrate-apacheds-unboundid-password-encoding,Password Encoding>>
+4. <<ldap-migrate-apacheds-unboundid-password-encoding,Password Hiding>>
+
+[[ldap-migrate-apacheds-unboundid-dependencies]]
+=== Switch Your Dependencies
+
+To use UnboundID, you will at least need to remove the ApacheDS dependencies:
+
+[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>
+	<scope>runtime</scope>
+</dependency>
+----
+
+Gradle::
++
+[source,gradkle,role="secondary"]
+----
+implementation("org.apache.directory.server:apacheds-server-jndi")
+implementation("org.apache.directory.server:apacheds-core")
+----
+======
+
+and replace them with UnboundID:
+
+[tabs]
+======
+Maven::
++
+[source,maven,role="primary"]
+----
+<dependency>
+	<groupId>com.unboundid</groupId>
+	<artifactId>unboundid-ldapsdk</artifactId>
+	<version>7.0.3</version>
+	<scope>runtime</scope>
+</dependency>
+----
+
+Gradle::
++
+[source,gradkle,role="secondary"]
+----
+implementation("org.apache.directory.server:apacheds-server-jndi")
+implementation("org.apache.directory.server:apacheds-core")
+----
+======
+
+If you are accepting the LDAP server defaults, this is likely all you will need to do.
+
+[[ldap-migrate-apacheds-unboundid-container]]
+=== Change Server Declaration
+
+If you are declaring an ApacheDS server, then you will need to change its declaration.
+Your configuration may vary somewhat from the following.
+Change this:
+
+[tabs]
+======
+Java::
++
+[source,java,role="primary"]
+----
+@Bean
+EmbeddedLdapServerContainer ldapContainer() {
+	EmbeddedLdapServerContainer container =
+        new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif");
+	container.setPort(0);
+	return container;
+}
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary"]
+----
+@Bean
+fun ldapContainer(): EmbeddedLdapServerContainer {
+	val container =
+        ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif")
+	container.setPort(0)
+	return container
+}
+----
+
+Xml::
++
+[source,xml,role="secondary"]
+----
+<ldap-server mode="apacheds"/>
+----
+======
+
+to this:
+
+[tabs]
+======
+Java::
++
+[source,java,role="primary"]
+----
+@Bean
+EmbeddedLdapServerContainer ldapContainer() {
+	EmbeddedLdapServerContainer container =
+        new UnboundIdContainer("dc=springframework,dc=org", "classpath:test-server.ldif");
+	container.setPort(0);
+	return container;
+}
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary"]
+----
+@Bean
+fun ldapContainer(): EmbeddedLdapServerContainer {
+	val container =
+        UnboundIdContainer("dc=springframework,dc=org", "classpath:test-server.ldif")
+	container.setPort(0)
+	return container
+}
+----
+
+Xml::
++
+[source,xml,role="secondary"]
+----
+<ldap-server mode="unboundid"/>
+----
+======
+
+
+[[ldap-migrate-apacheds-unboundid-password-encoding]]
+=== Configure Password Encoding
+
+Apache Directory Server supports binding with SHA-hashed passwords, but UnboundID does not.
+
+If you run into trouble with binding users with SHA-hashed passwords, move to Spring Security's `PasswordComparisonAuthenticator` by providing a password encoder to the authentication provider:
+
+[tabs]
+======
+Java::
++
+[source,java,role="primary"]
+----
+@Bean
+AuthenticationManager ldapAuthenticationManager(BaseLdapPathContextSource contextSource) {
+    LdapPasswordComparisonAuthenticationManagerFactory factory =
+        new LdapPasswordComparisonAuthenticationManagerFactory(
+            contextSource, new LdapShaPasswordEncoder());
+    // ...
+    return factory.createAuthenticationManager();
+}
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary"]
+----
+@Bean
+fun ldapAuthenticationManager(val contextSource: BaseLdapPathContextSource): AuthenticationManager {
+    val factory = LdapPasswordComparisonAuthenticationManagerFactory(
+            contextSource, LdapShaPasswordEncoder())
+    // ...
+    return factory.createAuthenticationManager()
+}
+----
+
+Xml::
++
+[source,xml,role="secondary"]
+----
+<auhentication-manager>
+    <ldap-authentication-provider>
+        <password-compare>
+			<password-encoder ref='pe' />
+		</password-compare>
+    </ldap-authentication-provider>
+</auhentication-manager>
+<b:bean id='pe' class='org.springframework.security.crypto.password.LdapShaPasswordEncoder' />
+----
+======
+
+[WARN]
+====
+Hashing passwords with `+{SHA}+` is not recommended.
+Please migrate to BCrypt, SCrypt, or Argon2 as soon as possible.
+You can use the same approach above to provide the corresponding password encoder.
+====
+
+[[ldap-migrate-apacheds-unboundid-password-hiding]]
+=== Configure Password Hiding
+
+ApacheDS is configured by Spring Security to hide the `userPassword` attribute from search results unless explicitly queried.
+UnboundID does not support this.
+
+You can achieve this behavior with a custom `InMemoryOperationInterceptor` like the following:
+
+[source,java]
+----
+static class PasswordRemovingOperationInterceptor
+    extends InMemoryOperationInterceptor {
+
+    @Override
+    public void processSearchEntry(InMemoryInterceptedSearchEntry entry) {
+        if (!entry.getRequest().getAttributeList().contains("userPassword")) {
+            if (entry.getSearchEntry().getAttribute("userPassword") != null) {
+                Entry old = entry.getSearchEntry();
+                Collection<Attribute> attributes = old.getAttributes().stream()
+                    .filter(attribute ->
+                        !"userPassword".equals(attribute.getName()))
+                    .collect(Collectors.toList());
+                Entry withoutPassword = new Entry(old.getDN(), attributes);
+                entry.setSearchEntry(withoutPassword);
+            }
+        }
+    }
+}
+----
+
+[NOTE]
+====
+It is better to secure passwords by hashing them and by using queries that identify the specific columns that you need.
+====
+
+`UnboundIdContainer` does not currently have a way to register a custom `InMemoryOperationInterceptor`, but you can either copy the contents of `UnboundIdContainer` or use Spring LDAP Test's `EmbeddedLdapServer` builder in order to provide this interceptor and confirm your application's readiness.

+ 34 - 1
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,9 +412,42 @@ 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-unboundid-deps]]
+=== What dependences are needed to run an embedded UnboundID LDAP server?
+
+You need to add the following dependency to your project:
+
+[tabs]
+======
+Maven::
++
+[source,maven,role="primary"]
+----
+<dependency>
+		<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?
 
+[NOTE]
+====
+Spring Security 7 removes support for Apache DS.
+Please use <<appendix-faq-unboundid-deps,UnboundID>> instead.
+====
+
 If you use Maven, you need to add the following to your `pom.xml` file dependencies:
 
 [source]

+ 2 - 3
docs/modules/ROOT/pages/servlet/authentication/passwords/ldap.adoc

@@ -225,9 +225,8 @@ fun ldapContainer(): UnboundIdContainer {
 
 [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.
+Spring Security 7 removes support for Apache DS.
+Please use <<servlet-authentication-ldap-unboundid,UnboundID>> instead.
 ====
 
 If you wish to use https://directory.apache.org/apacheds/[Apache DS], specify the following dependencies: