Add setter for authority prefix in JwtGrantedAuthoritiesConverter

Prior to this change mapped authorities are always prefixed
with default value 'SCOPE_'. 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
authority prefix like e.g. 'ROLE_'. Without specifying a custom prefix
the default prefix still remains 'SCOPE_'.
This way existing authorization checks using the standard 'ROLE_'
prefix can be reused without lots of effort.

Fixes gh-7101
This commit is contained in:
Andreas Falk 2019-08-13 22:23:39 +02:00 committed by Josh Cummings
parent abc90280e0
commit b45e57cc40
2 changed files with 58 additions and 12 deletions

View File

@ -25,6 +25,7 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
@ -40,6 +41,8 @@ public final class JwtGrantedAuthoritiesConverter implements Converter<Jwt, Coll
private static final Collection<String> WELL_KNOWN_AUTHORITIES_CLAIM_NAMES =
Arrays.asList("scope", "scp");
private String authorityPrefix = DEFAULT_AUTHORITY_PREFIX;
/**
* Extract {@link GrantedAuthority}s from the given {@link Jwt}.
*
@ -50,11 +53,23 @@ public final class JwtGrantedAuthoritiesConverter implements Converter<Jwt, Coll
public Collection<GrantedAuthority> convert(Jwt jwt) {
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>();
for (String authority : getAuthorities(jwt)) {
grantedAuthorities.add(new SimpleGrantedAuthority(DEFAULT_AUTHORITY_PREFIX + authority));
grantedAuthorities.add(new SimpleGrantedAuthority(this.authorityPrefix + authority));
}
return grantedAuthorities;
}
/**
* Sets the prefix to use for {@link GrantedAuthority authorities} mapped by this converter.
* Defaults to {@link JwtGrantedAuthoritiesConverter#DEFAULT_AUTHORITY_PREFIX}.
*
* @param authorityPrefix The authority prefix
* @since 5.2
*/
public void setAuthorityPrefix(String authorityPrefix) {
Assert.hasText(authorityPrefix, "authorityPrefix cannot be empty");
this.authorityPrefix = authorityPrefix;
}
private String getAuthoritiesClaimName(Jwt jwt) {
for (String claimName : WELL_KNOWN_AUTHORITIES_CLAIM_NAMES) {
if (jwt.containsClaim(claimName)) {

View File

@ -40,46 +40,75 @@ import org.springframework.security.oauth2.jwt.Jwt;
* @since 5.2
*/
public class JwtGrantedAuthoritiesConverterTests {
private JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
@Test
public void convertWhenTokenHasScopeAttributeThenTranslatedToAuthorities() {
Jwt jwt = this.jwt(Collections.singletonMap("scope", "message:read message:write"));
Collection<GrantedAuthority> authorities = this.jwtGrantedAuthoritiesConverter.convert(jwt);
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).containsExactly(
new SimpleGrantedAuthority("SCOPE_message:read"),
new SimpleGrantedAuthority("SCOPE_message:write"));
}
@Test
public void convertWithCustomAuthorityPrefixWhenTokenHasScopeAttributeThenTranslatedToAuthorities() {
Jwt jwt = this.jwt(Collections.singletonMap("scope", "message:read message:write"));
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtGrantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).containsExactly(
new SimpleGrantedAuthority("ROLE_message:read"),
new SimpleGrantedAuthority("ROLE_message:write"));
}
@Test
public void convertWhenTokenHasEmptyScopeAttributeThenTranslatedToNoAuthorities() {
Jwt jwt = this.jwt(Collections.singletonMap("scope", ""));
Collection<GrantedAuthority> authorities = this.jwtGrantedAuthoritiesConverter.convert(jwt);
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).containsExactly();
assertThat(authorities).isEmpty();
}
@Test
public void convertWhenTokenHasScpAttributeThenTranslatedToAuthorities() {
Jwt jwt = this.jwt(Collections.singletonMap("scp", Arrays.asList("message:read", "message:write")));
Collection<GrantedAuthority> authorities = this.jwtGrantedAuthoritiesConverter.convert(jwt);
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).containsExactly(
new SimpleGrantedAuthority("SCOPE_message:read"),
new SimpleGrantedAuthority("SCOPE_message:write"));
}
@Test
public void convertWithCustomAuthorityPrefixWhenTokenHasScpAttributeThenTranslatedToAuthorities() {
Jwt jwt = this.jwt(Collections.singletonMap("scp", Arrays.asList("message:read", "message:write")));
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtGrantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).containsExactly(
new SimpleGrantedAuthority("ROLE_message:read"),
new SimpleGrantedAuthority("ROLE_message:write"));
}
@Test
public void convertWhenTokenHasEmptyScpAttributeThenTranslatedToNoAuthorities() {
Jwt jwt = this.jwt(Maps.newHashMap("scp", Arrays.asList()));
Jwt jwt = this.jwt(Maps.newHashMap("scp", Collections.emptyList()));
Collection<GrantedAuthority> authorities = this.jwtGrantedAuthoritiesConverter.convert(jwt);
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).containsExactly();
assertThat(authorities).isEmpty();
}
@Test
@ -89,7 +118,8 @@ public class JwtGrantedAuthoritiesConverterTests {
claims.put("scope", "missive:read missive:write");
Jwt jwt = this.jwt(claims);
Collection<GrantedAuthority> authorities = this.jwtGrantedAuthoritiesConverter.convert(jwt);
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).containsExactly(
new SimpleGrantedAuthority("SCOPE_missive:read"),
@ -103,9 +133,10 @@ public class JwtGrantedAuthoritiesConverterTests {
claims.put("scope", "");
Jwt jwt = this.jwt(claims);
Collection<GrantedAuthority> authorities = this.jwtGrantedAuthoritiesConverter.convert(jwt);
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).containsExactly();
assertThat(authorities).isEmpty();
}
private Jwt jwt(Map<String, Object> claims) {