Browse Source

Document JwtGrantedAuthoritiesConverter Features

Fixes gh-8176
Josh Cummings 5 years ago
parent
commit
933104d2d6

+ 58 - 56
docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc

@@ -629,15 +629,19 @@ However, there are a number of circumstances where this default is insufficient.
 For example, some authorization servers don't use the `scope` attribute, but instead have their own custom attribute.
 Or, at other times, the resource server may need to adapt the attribute or a composition of attributes into internalized authorities.
 
-To this end, the DSL exposes `jwtAuthenticationConverter()`:
+To this end, the DSL exposes `jwtAuthenticationConverter()`, which is responsible for converting a `Jwt` into an `Authentication`.
 
-.Authorities Extractor Configuration
+As part of its configuration, we can supply a subsidiary converter to go from `Jwt` to a `Collection` of granted authorities.
+Let's say that that your authorization server communicates authorities in a custom claim called `authorities`.
+In that case, you can configure the claim that `JwtAuthenticationConverter` should inspect, like so:
+
+.Authorities Claim Configuration
 ====
 .Java
 [source,java,role="primary"]
 ----
 @EnableWebSecurity
-public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter {
+public class CustomAuthoritiesClaimName extends WebSecurityConfigurerAdapter {
     protected void configure(HttpSecurity http) {
         http
             .authorizeRequests(authorize -> authorize
@@ -645,49 +649,22 @@ public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter {
             )
             .oauth2ResourceServer(oauth2 -> oauth2
                 .jwt(jwt -> jwt
-                    .jwtAuthenticationConverter(grantedAuthoritiesExtractor())
+                    .jwtAuthenticationConverter(jwtAuthenticationConverter())
                 )
             );
     }
 }
 
-Converter<Jwt, AbstractAuthenticationToken> grantedAuthoritiesExtractor() {
-    JwtAuthenticationConverter jwtAuthenticationConverter =
-            new JwtAuthenticationConverter();
-
-    jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter
-            (new GrantedAuthoritiesExtractor());
+JwtAuthenticationConverter jwtAuthenticationConverter() {
+    JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
+    grantedAuthoritiesConverter.setAuthoritiesClaimName("authorities");
 
+    JwtAuthenticationConverter authenticationConverter = new JwtAuthenticationConverter();
+    jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(authoritiesConverter);
     return jwtAuthenticationConverter;
 }
 ----
 
-.Kotlin
-[source,kotlin,role="secondary"]
-----
-@EnableWebSecurity
-class DirectlyConfiguredJwkSetUri : WebSecurityConfigurerAdapter() {
-    override fun configure(http: HttpSecurity) {
-        http {
-            authorizeRequests {
-                authorize(anyRequest, authenticated)
-            }
-            oauth2ResourceServer {
-                jwt {
-                    jwtAuthenticationConverter = grantedAuthoritiesExtractor()
-                }
-            }
-        }
-    }
-
-    private fun grantedAuthoritiesExtractor(): JwtAuthenticationConverter {
-        val jwtAuthenticationConverter = JwtAuthenticationConverter()
-        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(GrantedAuthoritiesExtractor())
-        return jwtAuthenticationConverter
-    }
-}
-----
-
 .Xml
 [source,xml,role="secondary"]
 ----
@@ -696,40 +673,65 @@ class DirectlyConfiguredJwkSetUri : WebSecurityConfigurerAdapter() {
     <intercept-uri pattern="/messages/**" access="hasAuthority('SCOPE_messages')"/>
     <oauth2-resource-server>
         <jwt jwk-set-uri="https://idp.example.org/.well-known/jwks.json"
-                jwt-authentication-converter-ref="grantedAuthoritiesExtractor"/>
+                jwt-authentication-converter-ref="jwtAuthenticationConverter"/>
     </oauth2-resource-server>
 </http>
 
-<bean id="grantedAuthoritiesExtractor"
+<bean id="jwtAuthenticationConverter"
         class="org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter">
-    <property name="jwtGrantedAuthoritiesConverter">
-        <bean class="my.custom.GrantedAuthoritiesConverter"/>
-    </property>
+    <property name="jwtGrantedAuthoritiesConverter" ref="jwtGrantedAuthoritiesConverter"/>
+</bean>
+
+<bean id="jwtGrantedAuthoritiesConverter"
+        class="org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter">
+    <property name="authoritiesClaimName" value="authorities"/>
 </bean>
 ----
 ====
 
-which is responsible for converting a `Jwt` into an `Authentication`.
-As part of its configuration, we can supply a subsidiary converter to go from `Jwt` to a `Collection` of granted authorities.
+You can also configure the authority prefix to be different as well.
+Instead of prefixing each authority with `SCOPE_`, you can change it to `ROLE_` like so:
 
-That final converter might be something like `GrantedAuthoritiesExtractor` below:
+.Authorities Prefix Configuration
+====
+.Java
+[source,java,role="primary"]
+----
+JwtAuthenticationConverter jwtAuthenticationConverter() {
+    JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
+    grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
 
-[source,java]
+    JwtAuthenticationConverter authenticationConverter = new JwtAuthenticationConverter();
+    jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(authoritiesConverter);
+    return jwtAuthenticationConverter;
+}
 ----
-static class GrantedAuthoritiesExtractor
-        implements Converter<Jwt, Collection<GrantedAuthority>> {
 
-    public Collection<GrantedAuthority> convert(Jwt jwt) {
-        Collection<?> authorities = (Collection<?>)
-                jwt.getClaims().getOrDefault("mycustomclaim", Collections.emptyList());
+.Xml
+[source,xml,role="secondary"]
+----
+<http>
+    <intercept-uri pattern="/contacts/**" access="hasAuthority('SCOPE_contacts')"/>
+    <intercept-uri pattern="/messages/**" access="hasAuthority('SCOPE_messages')"/>
+    <oauth2-resource-server>
+        <jwt jwk-set-uri="https://idp.example.org/.well-known/jwks.json"
+                jwt-authentication-converter-ref="jwtAuthenticationConverter"/>
+    </oauth2-resource-server>
+</http>
 
-        return authorities.stream()
-                .map(Object::toString)
-                .map(SimpleGrantedAuthority::new)
-                .collect(Collectors.toList());
-    }
-}
+<bean id="jwtAuthenticationConverter"
+        class="org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter">
+    <property name="jwtGrantedAuthoritiesConverter" ref="jwtGrantedAuthoritiesConverter"/>
+</bean>
+
+<bean id="jwtGrantedAuthoritiesConverter"
+        class="org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter">
+    <property name="authorityPrefix" value="ROLE_"/>
+</bean>
 ----
+====
+
+Or, you can remove the prefix altogether by calling `JwtGrantedAuthoritiesConverter#setAuthorityPrefix("")`.
 
 For more flexibility, the DSL supports entirely replacing the converter with any class that implements `Converter<Jwt, AbstractAuthenticationToken>`: