Add setter for authorities claim name in JwtGrantedAuthoritiesConverter

Prior to this change authorities are always mapped using well known
claim names ('scope' or 'scp'). To change this default behaviour the
converter had to be replaced completely with a custom one.
This commit adds an additional setter to configure a custom
claim name like e.g. 'roles'. Without specifying a custom claim name
the default claims to be used still remains to the well known ones.
This way the authorities can be mapped according to customized
token claims.

Fixes gh-7100
This commit is contained in:
Andreas Falk 2019-08-18 16:40:34 +02:00 committed by Josh Cummings
parent 95caa4715f
commit 0a058c973a
2 changed files with 62 additions and 0 deletions

View File

@ -43,6 +43,8 @@ public final class JwtGrantedAuthoritiesConverter implements Converter<Jwt, Coll
private String authorityPrefix = DEFAULT_AUTHORITY_PREFIX;
private String authoritiesClaimName;
/**
* Extract {@link GrantedAuthority}s from the given {@link Jwt}.
*
@ -70,7 +72,24 @@ public final class JwtGrantedAuthoritiesConverter implements Converter<Jwt, Coll
this.authorityPrefix = authorityPrefix;
}
/**
* Sets the name of token claim to use for mapping {@link GrantedAuthority authorities} by this converter.
* Defaults to {@link JwtGrantedAuthoritiesConverter#WELL_KNOWN_AUTHORITIES_CLAIM_NAMES}.
*
* @param authoritiesClaimName The token claim name to map authorities
* @since 5.2
*/
public void setAuthoritiesClaimName(String authoritiesClaimName) {
Assert.hasText(authoritiesClaimName, "authoritiesClaimName cannot be empty");
this.authoritiesClaimName = authoritiesClaimName;
}
private String getAuthoritiesClaimName(Jwt jwt) {
if (this.authoritiesClaimName != null) {
return this.authoritiesClaimName;
}
for (String claimName : WELL_KNOWN_AUTHORITIES_CLAIM_NAMES) {
if (jwt.containsClaim(claimName)) {
return claimName;

View File

@ -139,6 +139,49 @@ public class JwtGrantedAuthoritiesConverterTests {
assertThat(authorities).isEmpty();
}
@Test
public void convertWhenTokenHasCustomClaimNameThenCustomClaimNameAttributeIsTranslatedToAuthorities() {
Map<String, Object> claims = new HashMap<>();
claims.put("roles", Arrays.asList("message:read", "message:write"));
claims.put("scope", "missive:read missive:write");
Jwt jwt = this.jwt(claims);
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).containsExactly(
new SimpleGrantedAuthority("SCOPE_message:read"),
new SimpleGrantedAuthority("SCOPE_message:write"));
}
@Test
public void convertWhenTokenHasEmptyCustomClaimNameThenCustomClaimNameAttributeIsTranslatedToNoAuthorities() {
Map<String, Object> claims = new HashMap<>();
claims.put("roles", Collections.emptyList());
claims.put("scope", "missive:read missive:write");
Jwt jwt = this.jwt(claims);
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).isEmpty();
}
@Test
public void convertWhenTokenHasNoCustomClaimNameThenCustomClaimNameAttributeIsTranslatedToNoAuthorities() {
Map<String, Object> claims = new HashMap<>();
claims.put("scope", "missive:read missive:write");
Jwt jwt = this.jwt(claims);
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).isEmpty();
}
private Jwt jwt(Map<String, Object> claims) {
Map<String, Object> headers = new HashMap<>();
headers.put("alg", JwsAlgorithms.RS256);