Kaynağa Gözat

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
Andreas Falk 6 yıl önce
ebeveyn
işleme
b45e57cc40

+ 16 - 1
oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtGrantedAuthoritiesConverter.java

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

+ 42 - 11
oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtGrantedAuthoritiesConverterTests.java

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