Add configurable mapping function to map authorities

This commit is contained in:
Giovanni Lovato 2018-10-11 18:28:17 +02:00 committed by Eleftheria Stein-Kousathana
parent 2d26be9446
commit 63607ee213
2 changed files with 63 additions and 14 deletions

View File

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

View File

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