resultsEnum = ctx.search(searchBaseDn, filter, params,
buildControls(searchControls));
logger.trace(LogMessage.format("Searching for entry under DN '%s', base = '%s', filter = '%s'", ctxBaseDn,
diff --git a/ldap/src/main/java/org/springframework/security/ldap/authentication/BindAuthenticator.java b/ldap/src/main/java/org/springframework/security/ldap/authentication/BindAuthenticator.java
index d37dc0748f..1847f932c2 100644
--- a/ldap/src/main/java/org/springframework/security/ldap/authentication/BindAuthenticator.java
+++ b/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)
*
- * For passivity reasons, defaults to {@code false}, though may change to {@code true}
+ *
+ * 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;
}
+
}
diff --git a/ldap/src/main/java/org/springframework/security/ldap/authentication/ad/DefaultActiveDirectoryAuthoritiesPopulator.java b/ldap/src/main/java/org/springframework/security/ldap/authentication/ad/DefaultActiveDirectoryAuthoritiesPopulator.java
index 1f51b4de10..1ba3549150 100644
--- a/ldap/src/main/java/org/springframework/security/ldap/authentication/ad/DefaultActiveDirectoryAuthoritiesPopulator.java
+++ b/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 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;
diff --git a/ldap/src/main/java/org/springframework/security/ldap/ppolicy/PasswordPolicyAwareContextSource.java b/ldap/src/main/java/org/springframework/security/ldap/ppolicy/PasswordPolicyAwareContextSource.java
index 9b5d299881..9c4ee19ecf 100755
--- a/ldap/src/main/java/org/springframework/security/ldap/ppolicy/PasswordPolicyAwareContextSource.java
+++ b/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);
diff --git a/ldap/src/main/java/org/springframework/security/ldap/userdetails/LdapUserDetailsManager.java b/ldap/src/main/java/org/springframework/security/ldap/userdetails/LdapUserDetailsManager.java
index cb3d4c3ff0..3ace03ebe8 100644
--- a/ldap/src/main/java/org/springframework/security/ldap/userdetails/LdapUserDetailsManager.java
+++ b/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 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 getUserAuthorities(final DistinguishedName dn, final String username) {
+ List 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 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);
}
- private void modifyAuthorities(final DistinguishedName userDn,
- final Collection extends GrantedAuthority> authorities, final int modType) {
+ protected void removeAuthorities(LdapName userDn, Collection extends GrantedAuthority> authorities) {
+ removeAuthorities(new DistinguishedName(userDn), authorities);
+ }
+
+ 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);
diff --git a/ldap/src/test/java/org/springframework/security/ldap/SpringSecurityLdapTemplateTests.java b/ldap/src/test/java/org/springframework/security/ldap/SpringSecurityLdapTemplateTests.java
index 51d43be1e8..cfe4fc3c32 100644
--- a/ldap/src/test/java/org/springframework/security/ldap/SpringSecurityLdapTemplateTests.java
+++ b/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);
diff --git a/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java b/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java
index 92205144f6..4668d37174 100644
--- a/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java
+++ b/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java
@@ -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));