Sfoglia il codice sorgente

Update Deprecated Usage

Issue gh-3834
Josh Cummings 1 anno fa
parent
commit
55895f3b08

+ 5 - 3
ldap/src/integration-test/java/org/springframework/security/ldap/authentication/BindAuthenticatorTests.java

@@ -159,17 +159,19 @@ public class BindAuthenticatorTests {
 		BindAuthenticator authenticator = new BindAuthenticator(contextSource);
 		authenticator.setUserDnPatterns(new String[] { "uid={0},ou=people" });
 		LdapContext dirContext = mock(LdapContext.class);
-		given(dirContext.getAttributes(any(Name.class), any())).willThrow(new javax.naming.AuthenticationException("exception"));
-		Name fullDn = LdapUtils.newLdapName("uid=bob,ou=people").addAll(0, contextSource.getBaseLdapPath());
+		given(dirContext.getAttributes(any(Name.class), any()))
+			.willThrow(new javax.naming.AuthenticationException("exception"));
+		Name fullDn = LdapUtils.prepend(LdapUtils.newLdapName("uid=bob,ou=people"), contextSource.getBaseLdapName());
 		given(contextSource.getContext(fullDn.toString(), (String) this.bob.getCredentials())).willReturn(dirContext);
 		authenticator.setAlsoHandleJavaxNamingBindExceptions(true);
 		assertThatExceptionOfType(BadCredentialsException.class).isThrownBy(authenticateBob(authenticator));
 		authenticator.setAlsoHandleJavaxNamingBindExceptions(false);
 		assertThatExceptionOfType(AuthenticationException.class).isThrownBy(authenticateBob(authenticator))
-				.withCauseInstanceOf(javax.naming.AuthenticationException.class);
+			.withCauseInstanceOf(javax.naming.AuthenticationException.class);
 	}
 
 	private ThrowingCallable authenticateBob(BindAuthenticator authenticator) {
 		return () -> authenticator.authenticate(this.bob);
 	}
+
 }

+ 1 - 1
ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/LdapUserDetailsManagerTests.java

@@ -185,7 +185,7 @@ public class LdapUserDetailsManagerTests {
 		assertThatExceptionOfType(UsernameNotFoundException.class).isThrownBy(() -> this.mgr.loadUserByUsername("don"));
 
 		// Check that no authorities are left
-		assertThat(this.mgr.getUserAuthorities(this.mgr.usernameMapper.buildDn("don"), "don")).hasSize(0);
+		assertThat(this.mgr.getUserAuthorities(this.mgr.usernameMapper.buildLdapName("don"), "don")).hasSize(0);
 	}
 
 	@Test

+ 10 - 0
ldap/src/main/java/org/springframework/security/ldap/DefaultLdapUsernameToDnMapper.java

@@ -16,7 +16,10 @@
 
 package org.springframework.security.ldap;
 
+import javax.naming.ldap.LdapName;
+
 import org.springframework.ldap.core.DistinguishedName;
+import org.springframework.ldap.support.LdapNameBuilder;
 
 /**
  * This implementation appends a name component to the <tt>userDnBase</tt> context using
@@ -43,12 +46,19 @@ public class DefaultLdapUsernameToDnMapper implements LdapUsernameToDnMapper {
 
 	/**
 	 * Assembles the Distinguished Name that should be used the given username.
+	 * @deprecated Use {@link #buildLdapName(String)} instead
 	 */
 	@Override
+	@Deprecated
 	public DistinguishedName buildDn(String username) {
 		DistinguishedName dn = new DistinguishedName(this.userDnBase);
 		dn.add(this.usernameAttribute, username);
 		return dn;
 	}
 
+	@Override
+	public LdapName buildLdapName(String username) {
+		return LdapNameBuilder.newInstance(this.userDnBase).add(this.usernameAttribute, username).build();
+	}
+
 }

+ 1 - 1
ldap/src/main/java/org/springframework/security/ldap/DefaultSpringSecurityContextSource.java

@@ -88,7 +88,7 @@ public class DefaultSpringSecurityContextSource extends LdapContextSource {
 			public void setupEnvironment(Hashtable env, String dn, String password) {
 				super.setupEnvironment(env, dn, password);
 				// Remove the pooling flag unless authenticating as the 'manager' user.
-				if (!DefaultSpringSecurityContextSource.this.userDn.equals(dn)
+				if (!DefaultSpringSecurityContextSource.this.getUserDn().equals(dn)
 						&& env.containsKey(SUN_LDAP_POOLING_FLAG)) {
 					DefaultSpringSecurityContextSource.this.logger.trace("Removing pooling flag for user " + dn);
 					env.remove(SUN_LDAP_POOLING_FLAG);

+ 10 - 0
ldap/src/main/java/org/springframework/security/ldap/LdapUsernameToDnMapper.java

@@ -16,6 +16,8 @@
 
 package org.springframework.security.ldap;
 
+import javax.naming.ldap.LdapName;
+
 import org.springframework.ldap.core.DistinguishedName;
 
 /**
@@ -25,6 +27,14 @@ import org.springframework.ldap.core.DistinguishedName;
  */
 public interface LdapUsernameToDnMapper {
 
+	/**
+	 * @deprecated Use {@link #buildLdapName(String)} instead
+	 */
+	@Deprecated
 	DistinguishedName buildDn(String username);
 
+	default LdapName buildLdapName(String username) {
+		return org.springframework.ldap.support.LdapUtils.newLdapName(buildDn(username));
+	}
+
 }

+ 17 - 3
ldap/src/main/java/org/springframework/security/ldap/LdapUtils.java

@@ -22,12 +22,14 @@ import java.net.URISyntaxException;
 import javax.naming.Context;
 import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
+import javax.naming.ldap.LdapName;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
 import org.springframework.ldap.core.DirContextAdapter;
 import org.springframework.ldap.core.DistinguishedName;
+import org.springframework.ldap.support.LdapNameBuilder;
 import org.springframework.security.crypto.codec.Utf8;
 import org.springframework.util.Assert;
 
@@ -84,13 +86,15 @@ public final class LdapUtils {
 		if (baseDn.length() == 0) {
 			return fullDn;
 		}
-		DistinguishedName base = new DistinguishedName(baseDn);
-		DistinguishedName full = new DistinguishedName(fullDn);
+		LdapName base = LdapNameBuilder.newInstance(baseDn).build();
+		LdapName full = LdapNameBuilder.newInstance(fullDn).build();
 		if (base.equals(full)) {
 			return "";
 		}
 		Assert.isTrue(full.startsWith(base), "Full DN does not start with base DN");
-		full.removeFirst(base);
+		for (int i = 0; i < base.size(); i++) {
+			full.remove(0);
+		}
 		return full.toString();
 	}
 
@@ -98,6 +102,7 @@ public final class LdapUtils {
 	 * Gets the full dn of a name by prepending the name of the context it is relative to.
 	 * If the name already contains the base name, it is returned unaltered.
 	 */
+	@Deprecated
 	public static DistinguishedName getFullDn(DistinguishedName dn, Context baseCtx) throws NamingException {
 		DistinguishedName baseDn = new DistinguishedName(baseCtx.getNameInNamespace());
 		if (dn.contains(baseDn)) {
@@ -107,6 +112,15 @@ public final class LdapUtils {
 		return baseDn;
 	}
 
+	public static LdapName getFullDn(LdapName dn, Context baseCtx) throws NamingException {
+		LdapName baseDn = LdapNameBuilder.newInstance(baseCtx.getNameInNamespace()).build();
+		if (dn.startsWith(baseDn)) {
+			return dn;
+		}
+		baseDn.addAll(dn);
+		return baseDn;
+	}
+
 	public static String convertPasswordToString(Object passObj) {
 		Assert.notNull(passObj, "Password object to convert must not be null");
 		if (passObj instanceof byte[]) {

+ 6 - 5
ldap/src/main/java/org/springframework/security/ldap/SpringSecurityLdapTemplate.java

@@ -33,6 +33,7 @@ import javax.naming.directory.Attributes;
 import javax.naming.directory.DirContext;
 import javax.naming.directory.SearchControls;
 import javax.naming.directory.SearchResult;
+import javax.naming.ldap.LdapName;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -44,8 +45,8 @@ import org.springframework.ldap.core.ContextMapper;
 import org.springframework.ldap.core.ContextSource;
 import org.springframework.ldap.core.DirContextAdapter;
 import org.springframework.ldap.core.DirContextOperations;
-import org.springframework.ldap.core.DistinguishedName;
 import org.springframework.ldap.core.LdapTemplate;
+import org.springframework.ldap.support.LdapNameBuilder;
 import org.springframework.util.Assert;
 import org.springframework.util.ObjectUtils;
 
@@ -113,8 +114,8 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
 	public DirContextOperations retrieveEntry(final String dn, final String[] attributesToRetrieve) {
 		return (DirContextOperations) executeReadOnly((ContextExecutor) (ctx) -> {
 			Attributes attrs = ctx.getAttributes(dn, attributesToRetrieve);
-			return new DirContextAdapter(attrs, new DistinguishedName(dn),
-					new DistinguishedName(ctx.getNameInNamespace()));
+			return new DirContextAdapter(attrs, LdapNameBuilder.newInstance(dn).build(),
+					LdapNameBuilder.newInstance(ctx.getNameInNamespace()).build());
 		});
 	}
 
@@ -266,8 +267,8 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
 	 */
 	public static DirContextOperations searchForSingleEntryInternal(DirContext ctx, SearchControls searchControls,
 			String base, String filter, Object[] params) throws NamingException {
-		final DistinguishedName ctxBaseDn = new DistinguishedName(ctx.getNameInNamespace());
-		final DistinguishedName searchBaseDn = new DistinguishedName(base);
+		final LdapName ctxBaseDn = LdapNameBuilder.newInstance(ctx.getNameInNamespace()).build();
+		final LdapName searchBaseDn = LdapNameBuilder.newInstance(base).build();
 		final NamingEnumeration<SearchResult> resultsEnum = ctx.search(searchBaseDn, filter, params,
 				buildControls(searchControls));
 		logger.trace(LogMessage.format("Searching for entry under DN '%s', base = '%s', filter = '%s'", ctxBaseDn,

+ 12 - 11
ldap/src/main/java/org/springframework/security/ldap/authentication/BindAuthenticator.java

@@ -16,6 +16,7 @@
 
 package org.springframework.security.ldap.authentication;
 
+import javax.naming.Name;
 import javax.naming.directory.Attributes;
 import javax.naming.directory.DirContext;
 
@@ -26,7 +27,6 @@ import org.springframework.core.log.LogMessage;
 import org.springframework.ldap.NamingException;
 import org.springframework.ldap.core.DirContextAdapter;
 import org.springframework.ldap.core.DirContextOperations;
-import org.springframework.ldap.core.DistinguishedName;
 import org.springframework.ldap.core.support.BaseLdapPathContextSource;
 import org.springframework.ldap.support.LdapUtils;
 import org.springframework.security.authentication.BadCredentialsException;
@@ -104,9 +104,8 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
 
 	private DirContextOperations bindWithDn(String userDnStr, String username, String password, Attributes attrs) {
 		BaseLdapPathContextSource ctxSource = (BaseLdapPathContextSource) getContextSource();
-		DistinguishedName userDn = new DistinguishedName(userDnStr);
-		DistinguishedName fullDn = new DistinguishedName(userDn);
-		fullDn.prepend(ctxSource.getBaseLdapPath());
+		Name userDn = LdapUtils.newLdapName(userDnStr);
+		Name fullDn = LdapUtils.prepend(userDn, ctxSource.getBaseLdapName());
 		logger.trace(LogMessage.format("Attempting to bind as %s", fullDn));
 		DirContext ctx = null;
 		try {
@@ -116,7 +115,7 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
 			if (attrs == null || attrs.size() == 0) {
 				attrs = ctx.getAttributes(userDn, getUserAttributes());
 			}
-			DirContextAdapter result = new DirContextAdapter(attrs, userDn, ctxSource.getBaseLdapPath());
+			DirContextAdapter result = new DirContextAdapter(attrs, userDn, ctxSource.getBaseLdapName());
 			if (ppolicy != null) {
 				result.setAttributeValue(ppolicy.getID(), ppolicy);
 			}
@@ -161,17 +160,19 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
 	}
 
 	/**
-	 * Set whether javax-based bind exceptions should also be delegated to {@code #handleBindException}
-	 * (only Spring-based bind exceptions are handled by default)
+	 * Set whether javax-based bind exceptions should also be delegated to
+	 * {@code #handleBindException} (only Spring-based bind exceptions are handled by
+	 * default)
 	 *
-	 * <p>For passivity reasons, defaults to {@code false}, though may change to {@code true}
+	 * <p>
+	 * For passivity reasons, defaults to {@code false}, though may change to {@code true}
 	 * in future releases.
-	 *
-	 * @param alsoHandleJavaxNamingBindExceptions - whether to delegate javax-based bind exceptions to
-	 * #handleBindException
+	 * @param alsoHandleJavaxNamingBindExceptions - whether to delegate javax-based bind
+	 * exceptions to #handleBindException
 	 * @since 6.4
 	 */
 	public void setAlsoHandleJavaxNamingBindExceptions(boolean alsoHandleJavaxNamingBindExceptions) {
 		this.alsoHandleJavaxNamingBindExceptions = alsoHandleJavaxNamingBindExceptions;
 	}
+
 }

+ 6 - 2
ldap/src/main/java/org/springframework/security/ldap/authentication/ad/DefaultActiveDirectoryAuthoritiesPopulator.java

@@ -21,11 +21,13 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 
+import javax.naming.ldap.LdapName;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
 import org.springframework.ldap.core.DirContextOperations;
-import org.springframework.ldap.core.DistinguishedName;
+import org.springframework.ldap.support.LdapNameBuilder;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.AuthorityUtils;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
@@ -59,7 +61,9 @@ public final class DefaultActiveDirectoryAuthoritiesPopulator implements LdapAut
 		List<GrantedAuthority> authorities = new ArrayList<>(groups.length);
 
 		for (String group : groups) {
-			authorities.add(new SimpleGrantedAuthority(new DistinguishedName(group).removeLast().getValue()));
+			LdapName name = LdapNameBuilder.newInstance(group).build();
+			String authority = name.getRdn(name.size() - 1).getValue().toString();
+			authorities.add(new SimpleGrantedAuthority(authority));
 		}
 
 		return authorities;

+ 3 - 3
ldap/src/main/java/org/springframework/security/ldap/ppolicy/PasswordPolicyAwareContextSource.java

@@ -47,12 +47,12 @@ public class PasswordPolicyAwareContextSource extends DefaultSpringSecurityConte
 
 	@Override
 	public DirContext getContext(String principal, String credentials) throws PasswordPolicyException {
-		if (principal.equals(this.userDn)) {
+		if (principal.equals(getUserDn())) {
 			return super.getContext(principal, credentials);
 		}
-		this.logger.trace(LogMessage.format("Binding as %s, prior to reconnect as user %s", this.userDn, principal));
+		this.logger.trace(LogMessage.format("Binding as %s, prior to reconnect as user %s", getUserDn(), principal));
 		// First bind as manager user before rebinding as the specific principal.
-		LdapContext ctx = (LdapContext) super.getContext(this.userDn, this.password);
+		LdapContext ctx = (LdapContext) super.getContext(getUserDn(), getPassword());
 		Control[] rctls = { new PasswordPolicyControl(false) };
 		try {
 			ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, principal);

+ 40 - 25
ldap/src/main/java/org/springframework/security/ldap/userdetails/LdapUserDetailsManager.java

@@ -36,6 +36,7 @@ import javax.naming.directory.SearchControls;
 import javax.naming.ldap.ExtendedRequest;
 import javax.naming.ldap.ExtendedResponse;
 import javax.naming.ldap.LdapContext;
+import javax.naming.ldap.LdapName;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -49,6 +50,7 @@ import org.springframework.ldap.core.DirContextAdapter;
 import org.springframework.ldap.core.DistinguishedName;
 import org.springframework.ldap.core.LdapTemplate;
 import org.springframework.ldap.core.SearchExecutor;
+import org.springframework.ldap.support.LdapNameBuilder;
 import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
@@ -93,7 +95,7 @@ public class LdapUserDetailsManager implements UserDetailsManager {
 	LdapUsernameToDnMapper usernameMapper = new DefaultLdapUsernameToDnMapper("cn=users", "uid");
 
 	/** The DN under which groups are stored */
-	private DistinguishedName groupSearchBase = new DistinguishedName("cn=groups");
+	private LdapName groupSearchBase = LdapNameBuilder.newInstance("cn=groups").build();
 
 	/** Password attribute name */
 	private String passwordAttributeName = "userPassword";
@@ -137,14 +139,14 @@ public class LdapUserDetailsManager implements UserDetailsManager {
 
 	@Override
 	public UserDetails loadUserByUsername(String username) {
-		DistinguishedName dn = this.usernameMapper.buildDn(username);
+		LdapName dn = this.usernameMapper.buildLdapName(username);
 		List<GrantedAuthority> authorities = getUserAuthorities(dn, username);
 		this.logger.debug(LogMessage.format("Loading user '%s' with DN '%s'", username, dn));
 		DirContextAdapter userCtx = loadUserAsContext(dn, username);
 		return this.userDetailsMapper.mapUserFromContext(userCtx, username, authorities);
 	}
 
-	private DirContextAdapter loadUserAsContext(final DistinguishedName dn, final String username) {
+	private DirContextAdapter loadUserAsContext(final LdapName dn, final String username) {
 		return (DirContextAdapter) this.template.executeReadOnly((ContextExecutor) (ctx) -> {
 			try {
 				Attributes attrs = ctx.getAttributes(dn, this.attributesToRetrieve);
@@ -188,7 +190,7 @@ public class LdapUserDetailsManager implements UserDetailsManager {
 				"No authentication object found in security context. Can't change current user's password!");
 		String username = authentication.getName();
 		this.logger.debug(LogMessage.format("Changing password for user '%s'", username));
-		DistinguishedName userDn = this.usernameMapper.buildDn(username);
+		LdapName userDn = this.usernameMapper.buildLdapName(username);
 		if (this.usePasswordModifyExtensionOperation) {
 			changePasswordUsingExtensionOperation(userDn, oldPassword, newPassword);
 		}
@@ -204,13 +206,13 @@ public class LdapUserDetailsManager implements UserDetailsManager {
 	 * @return the granted authorities returned by the group search
 	 */
 	@SuppressWarnings("unchecked")
-	List<GrantedAuthority> getUserAuthorities(final DistinguishedName dn, final String username) {
+	List<GrantedAuthority> getUserAuthorities(final LdapName dn, final String username) {
 		SearchExecutor se = (ctx) -> {
-			DistinguishedName fullDn = LdapUtils.getFullDn(dn, ctx);
+			LdapName fullDn = LdapUtils.getFullDn(dn, ctx);
 			SearchControls ctrls = new SearchControls();
 			ctrls.setReturningAttributes(new String[] { this.groupRoleAttributeName });
-			return ctx.search(this.groupSearchBase, this.groupSearchFilter, new String[] { fullDn.toUrl(), username },
-					ctrls);
+			return ctx.search(this.groupSearchBase, this.groupSearchFilter,
+					new String[] { fullDn.toString(), username }, ctrls);
 		};
 		AttributesMapperCallbackHandler roleCollector = new AttributesMapperCallbackHandler(this.roleMapper);
 		this.template.search(se, roleCollector);
@@ -221,7 +223,7 @@ public class LdapUserDetailsManager implements UserDetailsManager {
 	public void createUser(UserDetails user) {
 		DirContextAdapter ctx = new DirContextAdapter();
 		copyToContext(user, ctx);
-		DistinguishedName dn = this.usernameMapper.buildDn(user.getUsername());
+		LdapName dn = this.usernameMapper.buildLdapName(user.getUsername());
 		this.logger.debug(LogMessage.format("Creating new user '%s' with DN '%s'", user.getUsername(), dn));
 		this.template.bind(dn, ctx, null);
 		// Check for any existing authorities which might be set for this
@@ -235,7 +237,7 @@ public class LdapUserDetailsManager implements UserDetailsManager {
 
 	@Override
 	public void updateUser(UserDetails user) {
-		DistinguishedName dn = this.usernameMapper.buildDn(user.getUsername());
+		LdapName dn = this.usernameMapper.buildLdapName(user.getUsername());
 		this.logger.debug(LogMessage.format("Updating new user '%s' with DN '%s'", user.getUsername(), dn));
 		List<GrantedAuthority> authorities = getUserAuthorities(dn, user.getUsername());
 		DirContextAdapter ctx = loadUserAsContext(dn, user.getUsername());
@@ -260,14 +262,14 @@ public class LdapUserDetailsManager implements UserDetailsManager {
 
 	@Override
 	public void deleteUser(String username) {
-		DistinguishedName dn = this.usernameMapper.buildDn(username);
+		LdapName dn = this.usernameMapper.buildLdapName(username);
 		removeAuthorities(dn, getUserAuthorities(dn, username));
 		this.template.unbind(dn);
 	}
 
 	@Override
 	public boolean userExists(String username) {
-		DistinguishedName dn = this.usernameMapper.buildDn(username);
+		LdapName dn = this.usernameMapper.buildLdapName(username);
 		try {
 			Object obj = this.template.lookup(dn);
 			if (obj instanceof Context) {
@@ -285,33 +287,48 @@ public class LdapUserDetailsManager implements UserDetailsManager {
 	 * @param group the name of the group
 	 * @return the DN of the corresponding group, including the groupSearchBase
 	 */
+	@Deprecated
 	protected DistinguishedName buildGroupDn(String group) {
 		DistinguishedName dn = new DistinguishedName(this.groupSearchBase);
 		dn.add(this.groupRoleAttributeName, group.toLowerCase());
 		return dn;
 	}
 
+	protected LdapName buildGroupName(String group) {
+		return LdapNameBuilder.newInstance(buildGroupDn(group)).build();
+	}
+
 	protected void copyToContext(UserDetails user, DirContextAdapter ctx) {
 		this.userDetailsMapper.mapUserToContext(user, ctx);
 	}
 
+	@Deprecated
 	protected void addAuthorities(DistinguishedName userDn, Collection<? extends GrantedAuthority> authorities) {
-		modifyAuthorities(userDn, authorities, DirContext.ADD_ATTRIBUTE);
+		modifyAuthorities(LdapNameBuilder.newInstance(userDn).build(), authorities, DirContext.ADD_ATTRIBUTE);
+	}
+
+	protected void addAuthorities(LdapName userDn, Collection<? extends GrantedAuthority> authorities) {
+		addAuthorities(new DistinguishedName(userDn), authorities);
 	}
 
+	@Deprecated
 	protected void removeAuthorities(DistinguishedName userDn, Collection<? extends GrantedAuthority> authorities) {
-		modifyAuthorities(userDn, authorities, DirContext.REMOVE_ATTRIBUTE);
+		modifyAuthorities(LdapNameBuilder.newInstance(userDn).build(), authorities, DirContext.REMOVE_ATTRIBUTE);
+	}
+
+	protected void removeAuthorities(LdapName userDn, Collection<? extends GrantedAuthority> authorities) {
+		removeAuthorities(new DistinguishedName(userDn), authorities);
 	}
 
-	private void modifyAuthorities(final DistinguishedName userDn,
-			final Collection<? extends GrantedAuthority> authorities, final int modType) {
+	private void modifyAuthorities(final LdapName userDn, final Collection<? extends GrantedAuthority> authorities,
+			final int modType) {
 		this.template.executeReadWrite((ContextExecutor) (ctx) -> {
 			for (GrantedAuthority authority : authorities) {
 				String group = convertAuthorityToGroup(authority);
-				DistinguishedName fullDn = LdapUtils.getFullDn(userDn, ctx);
+				LdapName fullDn = LdapUtils.getFullDn(userDn, ctx);
 				ModificationItem addGroup = new ModificationItem(modType,
-						new BasicAttribute(this.groupMemberAttributeName, fullDn.toUrl()));
-				ctx.modifyAttributes(buildGroupDn(group), new ModificationItem[] { addGroup });
+						new BasicAttribute(this.groupMemberAttributeName, fullDn.toString()));
+				ctx.modifyAttributes(buildGroupName(group), new ModificationItem[] { addGroup });
 			}
 			return null;
 		});
@@ -334,7 +351,7 @@ public class LdapUserDetailsManager implements UserDetailsManager {
 	}
 
 	public void setGroupSearchBase(String groupSearchBase) {
-		this.groupSearchBase = new DistinguishedName(groupSearchBase);
+		this.groupSearchBase = LdapNameBuilder.newInstance(groupSearchBase).build();
 	}
 
 	public void setGroupRoleAttributeName(String groupRoleAttributeName) {
@@ -413,8 +430,7 @@ public class LdapUserDetailsManager implements UserDetailsManager {
 		this.rolePrefix = rolePrefix;
 	}
 
-	private void changePasswordUsingAttributeModification(DistinguishedName userDn, String oldPassword,
-			String newPassword) {
+	private void changePasswordUsingAttributeModification(LdapName userDn, String oldPassword, String newPassword) {
 		ModificationItem[] passwordChange = new ModificationItem[] { new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
 				new BasicAttribute(this.passwordAttributeName, newPassword)) };
 		if (oldPassword == null) {
@@ -438,11 +454,10 @@ public class LdapUserDetailsManager implements UserDetailsManager {
 		});
 	}
 
-	private void changePasswordUsingExtensionOperation(DistinguishedName userDn, String oldPassword,
-			String newPassword) {
+	private void changePasswordUsingExtensionOperation(LdapName userDn, String oldPassword, String newPassword) {
 		this.template.executeReadWrite((dirCtx) -> {
 			LdapContext ctx = (LdapContext) dirCtx;
-			String userIdentity = LdapUtils.getFullDn(userDn, ctx).encode();
+			String userIdentity = LdapUtils.getFullDn(userDn, ctx).toString();
 			PasswordModifyRequest request = new PasswordModifyRequest(userIdentity, oldPassword, newPassword);
 			try {
 				return ctx.extendedOperation(request);

+ 3 - 2
ldap/src/test/java/org/springframework/security/ldap/SpringSecurityLdapTemplateTests.java

@@ -16,6 +16,7 @@
 
 package org.springframework.security.ldap;
 
+import javax.naming.Name;
 import javax.naming.NamingEnumeration;
 import javax.naming.directory.DirContext;
 import javax.naming.directory.SearchControls;
@@ -29,7 +30,6 @@ import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
 
 import org.springframework.ldap.core.DirContextAdapter;
-import org.springframework.ldap.core.DistinguishedName;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
@@ -60,7 +60,8 @@ public class SpringSecurityLdapTemplateTests {
 		String searchResultName = "ldap://example.com/dc=springframework,dc=org";
 		Object[] params = new Object[] {};
 		DirContextAdapter searchResultObject = mock(DirContextAdapter.class);
-		given(this.ctx.search(any(DistinguishedName.class), eq(filter), eq(params), this.searchControls.capture()))
+		given(this.ctx.getNameInNamespace()).willReturn("dc=springframework,dc=org");
+		given(this.ctx.search(any(Name.class), eq(filter), eq(params), this.searchControls.capture()))
 			.willReturn(this.resultsEnum);
 		given(this.resultsEnum.hasMore()).willReturn(true, false);
 		given(this.resultsEnum.next()).willReturn(this.searchResult);

+ 5 - 6
ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java

@@ -36,7 +36,7 @@ import org.mockito.ArgumentCaptor;
 
 import org.springframework.dao.IncorrectResultSizeDataAccessException;
 import org.springframework.ldap.core.DirContextAdapter;
-import org.springframework.ldap.core.DistinguishedName;
+import org.springframework.ldap.support.LdapNameBuilder;
 import org.springframework.security.authentication.AccountExpiredException;
 import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.authentication.CredentialsExpiredException;
@@ -118,8 +118,7 @@ public class ActiveDirectoryLdapAuthenticationProviderTests {
 		customProvider.contextFactory = createContextFactoryReturning(ctx);
 		Authentication result = customProvider.authenticate(this.joe);
 		assertThat(result.isAuthenticated()).isTrue();
-		verify(ctx).search(any(DistinguishedName.class), eq(defaultSearchFilter), any(Object[].class),
-				any(SearchControls.class));
+		verify(ctx).search(any(Name.class), eq(defaultSearchFilter), any(Object[].class), any(SearchControls.class));
 	}
 
 	// SEC-2897,SEC-2224
@@ -158,8 +157,8 @@ public class ActiveDirectoryLdapAuthenticationProviderTests {
 		given(ctx.getNameInNamespace()).willReturn("");
 		DirContextAdapter dca = new DirContextAdapter();
 		SearchResult sr = new SearchResult("CN=Joe Jannsen,CN=Users", dca, dca.getAttributes());
-		given(ctx.search(eq(new DistinguishedName("DC=mydomain,DC=eu")), any(String.class), any(Object[].class),
-				any(SearchControls.class)))
+		given(ctx.search(eq(LdapNameBuilder.newInstance("DC=mydomain,DC=eu").build()), any(String.class),
+				any(Object[].class), any(SearchControls.class)))
 			.willReturn(new MockNamingEnumeration(sr));
 		this.provider.contextFactory = createContextFactoryReturning(ctx);
 		assertThatExceptionOfType(BadCredentialsException.class).isThrownBy(() -> this.provider.authenticate(this.joe));
@@ -363,7 +362,7 @@ public class ActiveDirectoryLdapAuthenticationProviderTests {
 		DirContextAdapter dca = new DirContextAdapter();
 		SearchResult sr = new SearchResult("CN=Joe Jannsen,CN=Users", dca, dca.getAttributes());
 		@SuppressWarnings("deprecation")
-		DistinguishedName searchBaseDn = new DistinguishedName(rootDn);
+		Name searchBaseDn = LdapNameBuilder.newInstance(rootDn).build();
 		given(ctx.search(eq(searchBaseDn), any(String.class), any(Object[].class), any(SearchControls.class)))
 			.willReturn(new MockNamingEnumeration(sr))
 			.willReturn(new MockNamingEnumeration(sr));