Add configurable mapping function to map authorities
This commit is contained in:
parent
2d26be9446
commit
63607ee213
|
@ -18,9 +18,12 @@ package org.springframework.security.ldap.userdetails;
|
|||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.*;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.ldap.core.ContextSource;
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
|
@ -29,11 +32,10 @@ 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.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
|
@ -185,4 +187,25 @@ public class DefaultLdapAuthoritiesPopulatorTests {
|
|||
assertThat(authorities).as("Should have 1 role").hasSize(1);
|
||||
assertThat(authorities.contains("ROLE_MANAGER")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customAuthoritiesMappingFunction() {
|
||||
populator.setAuthorityMapper(record -> {
|
||||
String dn = record.get(SpringSecurityLdapTemplate.DN_KEY).get(0);
|
||||
String role = record.get(populator.getGroupRoleAttribute()).get(0);
|
||||
return new LdapAuthority(role, dn);
|
||||
});
|
||||
|
||||
DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName(
|
||||
"cn=mouse\\, jerry,ou=people,dc=springframework,dc=org"));
|
||||
|
||||
Collection<GrantedAuthority> authorities = populator.getGrantedAuthorities(ctx, "notused");
|
||||
|
||||
assertThat(authorities).allMatch(LdapAuthority.class::isInstance);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void customAuthoritiesMappingFunctionThrowsIfNull() {
|
||||
populator.setAuthorityMapper(null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,13 +20,14 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.naming.directory.SearchControls;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.ldap.core.ContextSource;
|
||||
import org.springframework.ldap.core.DirContextOperations;
|
||||
import org.springframework.ldap.core.LdapTemplate;
|
||||
|
@ -137,15 +138,22 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
|||
* The pattern to be used for the user search. {0} is the user's DN
|
||||
*/
|
||||
private String groupSearchFilter = "(member={0})";
|
||||
|
||||
/**
|
||||
* The role prefix that will be prepended to each role name
|
||||
*/
|
||||
private String rolePrefix = "ROLE_";
|
||||
|
||||
/**
|
||||
* Should we convert the role name to uppercase
|
||||
*/
|
||||
private boolean convertToUpperCase = true;
|
||||
|
||||
/**
|
||||
* The mapping function to be used to populate authorities.
|
||||
*/
|
||||
private Function<Map<String, List<String>>, GrantedAuthority> authorityMapper;
|
||||
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
|
@ -171,6 +179,16 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
|||
logger.info(
|
||||
"groupSearchBase is empty. Searches will be performed from the context source base");
|
||||
}
|
||||
|
||||
this.authorityMapper = record -> {
|
||||
String role = record.get(this.groupRoleAttribute).get(0);
|
||||
|
||||
if (this.convertToUpperCase) {
|
||||
role = role.toUpperCase();
|
||||
}
|
||||
|
||||
return new SimpleGrantedAuthority(this.rolePrefix + role);
|
||||
};
|
||||
}
|
||||
|
||||
// ~ Methods
|
||||
|
@ -238,21 +256,18 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
|||
+ " in search base '" + getGroupSearchBase() + "'");
|
||||
}
|
||||
|
||||
Set<String> userRoles = getLdapTemplate().searchForSingleAttributeValues(
|
||||
getGroupSearchBase(), this.groupSearchFilter,
|
||||
new String[] { userDn, username }, this.groupRoleAttribute);
|
||||
Set<Map<String, List<String>>> userRoles = getLdapTemplate()
|
||||
.searchForMultipleAttributeValues(getGroupSearchBase(),
|
||||
this.groupSearchFilter,
|
||||
new String[] { userDn, username },
|
||||
new String[] { this.groupRoleAttribute });
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Roles from search: " + userRoles);
|
||||
}
|
||||
|
||||
for (String role : userRoles) {
|
||||
|
||||
if (this.convertToUpperCase) {
|
||||
role = role.toUpperCase();
|
||||
}
|
||||
|
||||
authorities.add(new SimpleGrantedAuthority(this.rolePrefix + role));
|
||||
for (Map<String, List<String>> role : userRoles) {
|
||||
authorities.add(authorityMapper.apply(role));
|
||||
}
|
||||
|
||||
return authorities;
|
||||
|
@ -325,6 +340,17 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
|||
getLdapTemplate().setIgnorePartialResultException(ignore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the mapping function which will be used to create instances of {@link GrantedAuthority}
|
||||
* given the context record.
|
||||
*
|
||||
* @param authorityMapper the mapping function
|
||||
*/
|
||||
public void setAuthorityMapper(Function<Map<String, List<String>>, GrantedAuthority> authorityMapper) {
|
||||
Assert.notNull(authorityMapper, "authorityMapper must not be null");
|
||||
this.authorityMapper = authorityMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current LDAP template. Method available so that classes extending this
|
||||
* can override the template used
|
||||
|
|
Loading…
Reference in New Issue