Skip to content

Commit 1ebb738

Browse files
committed
Document JwtGrantedAuthoritiesConverter Features
Fixes gh-8176
1 parent 044c30c commit 1ebb738

File tree

1 file changed

+58
-56
lines changed

1 file changed

+58
-56
lines changed

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

+58-56
Original file line numberDiff line numberDiff line change
@@ -629,65 +629,42 @@ However, there are a number of circumstances where this default is insufficient.
629629
For example, some authorization servers don't use the `scope` attribute, but instead have their own custom attribute.
630630
Or, at other times, the resource server may need to adapt the attribute or a composition of attributes into internalized authorities.
631631

632-
To this end, the DSL exposes `jwtAuthenticationConverter()`:
632+
To this end, the DSL exposes `jwtAuthenticationConverter()`, which is responsible for converting a `Jwt` into an `Authentication`.
633633

634-
.Authorities Extractor Configuration
634+
As part of its configuration, we can supply a subsidiary converter to go from `Jwt` to a `Collection` of granted authorities.
635+
Let's say that that your authorization server communicates authorities in a custom claim called `authorities`.
636+
In that case, you can configure the claim that `JwtAuthenticationConverter` should inspect, like so:
637+
638+
.Authorities Claim Configuration
635639
====
636640
.Java
637641
[source,java,role="primary"]
638642
----
639643
@EnableWebSecurity
640-
public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter {
644+
public class CustomAuthoritiesClaimName extends WebSecurityConfigurerAdapter {
641645
protected void configure(HttpSecurity http) {
642646
http
643647
.authorizeRequests(authorize -> authorize
644648
.anyRequest().authenticated()
645649
)
646650
.oauth2ResourceServer(oauth2 -> oauth2
647651
.jwt(jwt -> jwt
648-
.jwtAuthenticationConverter(grantedAuthoritiesExtractor())
652+
.jwtAuthenticationConverter(jwtAuthenticationConverter())
649653
)
650654
);
651655
}
652656
}
653657
654-
Converter<Jwt, AbstractAuthenticationToken> grantedAuthoritiesExtractor() {
655-
JwtAuthenticationConverter jwtAuthenticationConverter =
656-
new JwtAuthenticationConverter();
657-
658-
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter
659-
(new GrantedAuthoritiesExtractor());
658+
JwtAuthenticationConverter jwtAuthenticationConverter() {
659+
JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
660+
grantedAuthoritiesConverter.setAuthoritiesClaimName("authorities");
660661
662+
JwtAuthenticationConverter authenticationConverter = new JwtAuthenticationConverter();
663+
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(authoritiesConverter);
661664
return jwtAuthenticationConverter;
662665
}
663666
----
664667
665-
.Kotlin
666-
[source,kotlin,role="secondary"]
667-
----
668-
@EnableWebSecurity
669-
class DirectlyConfiguredJwkSetUri : WebSecurityConfigurerAdapter() {
670-
override fun configure(http: HttpSecurity) {
671-
http {
672-
authorizeRequests {
673-
authorize(anyRequest, authenticated)
674-
}
675-
oauth2ResourceServer {
676-
jwt {
677-
jwtAuthenticationConverter = grantedAuthoritiesExtractor()
678-
}
679-
}
680-
}
681-
}
682-
683-
private fun grantedAuthoritiesExtractor(): JwtAuthenticationConverter {
684-
val jwtAuthenticationConverter = JwtAuthenticationConverter()
685-
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(GrantedAuthoritiesExtractor())
686-
return jwtAuthenticationConverter
687-
}
688-
}
689-
----
690-
691668
.Xml
692669
[source,xml,role="secondary"]
693670
----
@@ -696,40 +673,65 @@ class DirectlyConfiguredJwkSetUri : WebSecurityConfigurerAdapter() {
696673
<intercept-uri pattern="/messages/**" access="hasAuthority('SCOPE_messages')"/>
697674
<oauth2-resource-server>
698675
<jwt jwk-set-uri="https://idp.example.org/.well-known/jwks.json"
699-
jwt-authentication-converter-ref="grantedAuthoritiesExtractor"/>
676+
jwt-authentication-converter-ref="jwtAuthenticationConverter"/>
700677
</oauth2-resource-server>
701678
</http>
702679
703-
<bean id="grantedAuthoritiesExtractor"
680+
<bean id="jwtAuthenticationConverter"
704681
class="org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter">
705-
<property name="jwtGrantedAuthoritiesConverter">
706-
<bean class="my.custom.GrantedAuthoritiesConverter"/>
707-
</property>
682+
<property name="jwtGrantedAuthoritiesConverter" ref="jwtGrantedAuthoritiesConverter"/>
683+
</bean>
684+
685+
<bean id="jwtGrantedAuthoritiesConverter"
686+
class="org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter">
687+
<property name="authoritiesClaimName" value="authorities"/>
708688
</bean>
709689
----
710690
====
711691

712-
which is responsible for converting a `Jwt` into an `Authentication`.
713-
As part of its configuration, we can supply a subsidiary converter to go from `Jwt` to a `Collection` of granted authorities.
692+
You can also configure the authority prefix to be different as well.
693+
Instead of prefixing each authority with `SCOPE_`, you can change it to `ROLE_` like so:
714694

715-
That final converter might be something like `GrantedAuthoritiesExtractor` below:
695+
.Authorities Prefix Configuration
696+
====
697+
.Java
698+
[source,java,role="primary"]
699+
----
700+
JwtAuthenticationConverter jwtAuthenticationConverter() {
701+
JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
702+
grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
716703
717-
[source,java]
704+
JwtAuthenticationConverter authenticationConverter = new JwtAuthenticationConverter();
705+
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(authoritiesConverter);
706+
return jwtAuthenticationConverter;
707+
}
718708
----
719-
static class GrantedAuthoritiesExtractor
720-
implements Converter<Jwt, Collection<GrantedAuthority>> {
721709
722-
public Collection<GrantedAuthority> convert(Jwt jwt) {
723-
Collection<?> authorities = (Collection<?>)
724-
jwt.getClaims().getOrDefault("mycustomclaim", Collections.emptyList());
710+
.Xml
711+
[source,xml,role="secondary"]
712+
----
713+
<http>
714+
<intercept-uri pattern="/contacts/**" access="hasAuthority('SCOPE_contacts')"/>
715+
<intercept-uri pattern="/messages/**" access="hasAuthority('SCOPE_messages')"/>
716+
<oauth2-resource-server>
717+
<jwt jwk-set-uri="https://idp.example.org/.well-known/jwks.json"
718+
jwt-authentication-converter-ref="jwtAuthenticationConverter"/>
719+
</oauth2-resource-server>
720+
</http>
725721
726-
return authorities.stream()
727-
.map(Object::toString)
728-
.map(SimpleGrantedAuthority::new)
729-
.collect(Collectors.toList());
730-
}
731-
}
722+
<bean id="jwtAuthenticationConverter"
723+
class="org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter">
724+
<property name="jwtGrantedAuthoritiesConverter" ref="jwtGrantedAuthoritiesConverter"/>
725+
</bean>
726+
727+
<bean id="jwtGrantedAuthoritiesConverter"
728+
class="org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter">
729+
<property name="authorityPrefix" value="ROLE_"/>
730+
</bean>
732731
----
732+
====
733+
734+
Or, you can remove the prefix altogether by calling `JwtGrantedAuthoritiesConverter#setAuthorityPrefix("")`.
733735

734736
For more flexibility, the DSL supports entirely replacing the converter with any class that implements `Converter<Jwt, AbstractAuthenticationToken>`:
735737

0 commit comments

Comments
 (0)