diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtGrantedAuthoritiesConverter.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtGrantedAuthoritiesConverter.java index a2827dc0c96..341f7fb1b03 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtGrantedAuthoritiesConverter.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtGrantedAuthoritiesConverter.java @@ -25,6 +25,7 @@ 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 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 convert(Jwt jwt) { Collection 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)) { diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtGrantedAuthoritiesConverterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtGrantedAuthoritiesConverterTests.java index 385ac278832..cb76a7bbc62 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtGrantedAuthoritiesConverterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtGrantedAuthoritiesConverterTests.java @@ -40,46 +40,75 @@ * @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 authorities = this.jwtGrantedAuthoritiesConverter.convert(jwt); + JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); + Collection 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 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 authorities = this.jwtGrantedAuthoritiesConverter.convert(jwt); + JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); + Collection 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 authorities = this.jwtGrantedAuthoritiesConverter.convert(jwt); + JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); + Collection 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 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 authorities = this.jwtGrantedAuthoritiesConverter.convert(jwt); + JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); + Collection authorities = jwtGrantedAuthoritiesConverter.convert(jwt); - assertThat(authorities).containsExactly(); + assertThat(authorities).isEmpty(); } @Test @@ -89,7 +118,8 @@ public void convertWhenTokenHasBothScopeAndScpThenScopeAttributeIsTranslatedToAu claims.put("scope", "missive:read missive:write"); Jwt jwt = this.jwt(claims); - Collection authorities = this.jwtGrantedAuthoritiesConverter.convert(jwt); + JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); + Collection authorities = jwtGrantedAuthoritiesConverter.convert(jwt); assertThat(authorities).containsExactly( new SimpleGrantedAuthority("SCOPE_missive:read"), @@ -103,9 +133,10 @@ public void convertWhenTokenHasEmptyScopeAndNonEmptyScpThenScopeAttributeIsTrans claims.put("scope", ""); Jwt jwt = this.jwt(claims); - Collection authorities = this.jwtGrantedAuthoritiesConverter.convert(jwt); + JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); + Collection authorities = jwtGrantedAuthoritiesConverter.convert(jwt); - assertThat(authorities).containsExactly(); + assertThat(authorities).isEmpty(); } private Jwt jwt(Map claims) {