From 9a3eb07af81dac24a581065bed08c63ee10866f6 Mon Sep 17 00:00:00 2001 From: Josh Cummings Date: Mon, 9 Mar 2020 18:49:49 -0600 Subject: [PATCH] Add Resource Server XML snippets Fixes gh-8077 --- .../servlet/oauth2/oauth2-resourceserver.adoc | 244 +++++++++++++++++- 1 file changed, 238 insertions(+), 6 deletions(-) diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc index 91e7b9960f..17da165d64 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc @@ -208,6 +208,9 @@ Methods on the `oauth2ResourceServer` DSL will also override or replace auto con For example, the second `@Bean` Spring Boot creates is a `JwtDecoder`, which decodes `String` tokens into validated instances of `Jwt`: + +.JWT Decoder +==== [source,java] ---- @Bean @@ -215,6 +218,7 @@ public JwtDecoder jwtDecoder() { return JwtDecoders.fromIssuerLocation(issuerUri); } ---- +==== [NOTE] Calling `{security-api-url}org/springframework/security/oauth2/jwt/JwtDecoders.html#fromIssuerLocation-java.lang.String-[JwtDecoders#fromIssuerLocation]` is what invokes the Provider Configuration or Authorization Server Metadata endpoint in order to derive the JWK Set Uri. @@ -223,6 +227,39 @@ If the application doesn't expose a `JwtDecoder` bean, then Spring Boot will exp And its configuration can be overridden using `jwkSetUri()` or replaced using `decoder()`. +Or, if you're not using Spring Boot at all, then both of these components - the filter chain and a `JwtDecoder` can be specified in XML. + +The filter chain is specified like so: + +.Default JWT Configuration +==== +.Xml +[source,xml,role="primary"] +---- + + + + + + +---- +==== + +And the `JwtDecoder` like so: + +.JWT Decoder +==== +.Xml +[source,xml,role="primary"] +---- + + + +---- +==== + [[oauth2resourceserver-jwt-jwkseturi-dsl]] ==== Using `jwkSetUri()` @@ -268,6 +305,17 @@ class DirectlyConfiguredJwkSetUri : WebSecurityConfigurerAdapter() { } } ---- + +.Xml +[source,xml,role="secondary"] +---- + + + + + + +---- ==== Using `jwkSetUri()` takes precedence over any configuration property. @@ -317,6 +365,17 @@ class DirectlyConfiguredJwtDecoder : WebSecurityConfigurerAdapter() { } } ---- + +.Xml +[source,xml,role="secondary"] +---- + + + + + + +---- ==== This is handy when deeper configuration, like <>, <>, or <>, is necessary. @@ -541,6 +600,18 @@ class DirectlyConfiguredJwkSetUri : WebSecurityConfigurerAdapter() { } } ---- + +.Xml +[source,xml,role="secondary"] +---- + + + + + + + +---- ==== Or similarly with method security: @@ -616,6 +687,26 @@ class DirectlyConfiguredJwkSetUri : WebSecurityConfigurerAdapter() { } } ---- + +.Xml +[source,xml,role="secondary"] +---- + + + + + + + + + + + + + +---- ==== which is responsible for converting a `Jwt` into an `Authentication`. @@ -1070,6 +1161,40 @@ If the application doesn't expose a `OpaqueTokenIntrospector` bean, then Spring And its configuration can be overridden using `introspectionUri()` and `introspectionClientCredentials()` or replaced using `introspector()`. +Or, if you're not using Spring Boot at all, then both of these components - the filter chain and a `OpaqueTokenIntrospector` can be specified in XML. + +The filter chain is specified like so: + +.Default Opaque Token Configuration +==== +.Xml +[source,xml,role="primary"] +---- + + + + + + +---- +==== + +And the `OpaqueTokenIntrospector` like so: + +.Opaque Token Introspector +==== +.Xml +[source,xml,role="primary"] +---- + + + + + +---- +==== + [[oauth2resourceserver-opaque-introspectionuri-dsl]] ==== Using `introspectionUri()` @@ -1117,6 +1242,17 @@ class DirectlyConfiguredIntrospectionUri : WebSecurityConfigurerAdapter() { } } ---- + +.Xml +[source,xml,role="secondary"] +---- + + + + + +---- ==== Using `introspectionUri()` takes precedence over any configuration property. @@ -1166,6 +1302,17 @@ class DirectlyConfiguredIntrospector : WebSecurityConfigurerAdapter() { } } ---- + +.Xml +[source,xml,role="secondary"] +---- + + + + + + +---- ==== This is handy when deeper configuration, like <>, <>, or <>, is necessary. @@ -1194,7 +1341,11 @@ When this is the case, Resource Server will attempt to coerce these scopes into This means that to protect an endpoint or method with a scope derived from an Opaque Token, the corresponding expressions should include this prefix: -```java +.Authorization Opaque Token Configuration +==== +.Java +[source,java,role="primary"] +---- @EnableWebSecurity public class MappedAuthorities extends WebSecurityConfigurerAdapter { protected void configure(HttpSecurity http) { @@ -1207,7 +1358,20 @@ public class MappedAuthorities extends WebSecurityConfigurerAdapter { .oauth2ResourceServer(OAuth2ResourceServerConfigurer::opaqueToken); } } -``` +---- + +.Xml +[source,xml,role="secondary"] +---- + + + + + + + +---- +==== Or similarly with method security: @@ -1450,7 +1614,10 @@ AuthenticationManagerResolver tokenAuthenticationManagerReso And then specify this `AuthenticationManagerResolver` in the DSL: -[source,java] +.Authentication Manager Resolver +==== +.Java +[source,java,role="primary"] ---- http .authorizeRequests(authorize -> authorize @@ -1461,6 +1628,15 @@ http ); ---- +.Xml +[source,xml,role="secondary"] +---- + + + +---- +==== + [[oauth2resourceserver-multitenancy]] === Multi-tenancy @@ -1478,7 +1654,10 @@ In each case, there are two things that need to be done and trade-offs associate One way to differentiate tenants is by the issuer claim. Since the issuer claim accompanies signed JWTs, this can be done with the `JwtIssuerAuthenticationManagerResolver`, like so: -[source,java] +.Multitenancy Tenant by JWT Claim +==== +.Java +[source,java,role="primary"] ---- JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver ("https://idp.example.org/issuerOne", "https://idp.example.org/issuerTwo"); @@ -1492,6 +1671,25 @@ http ); ---- +.Xml +[source,xml,role="secondary"] +---- + + + + + + + + https://idp.example.org/issuerOne + https://idp.example.org/issuerTwo + + + +---- +==== + This is nice because the issuer endpoints are loaded lazily. In fact, the corresponding `JwtAuthenticationProvider` is instantiated only when the first request with the corresponding issuer is sent. This allows for an application startup that is independent from those authorization servers being up and available. @@ -1667,7 +1865,10 @@ This, however, can be customized in a couple of ways. For example, you may have a need to read the bearer token from a custom header. To achieve this, you can wire a `HeaderBearerTokenResolver` instance into the DSL, as you can see in the following example: -[source,java] +.Custom Bearer Token Header +==== +.Java +[source,java,role="primary"] ---- http .oauth2ResourceServer(oauth2 -> oauth2 @@ -1675,11 +1876,28 @@ http ); ---- +.Xml +[source,xml,role="secondary"] +---- + + + + + + + +---- +==== + ==== Reading the Bearer Token from a Form Parameter Or, you may wish to read the token from a form parameter, which you can do by configuring the `DefaultBearerTokenResolver`, as you can see below: -[source,java] +.Form Parameter Bearer Token +==== +.Java +[source,java,role="primary"] ---- DefaultBearerTokenResolver resolver = new DefaultBearerTokenResolver(); resolver.setAllowFormEncodedBodyParameter(true); @@ -1689,6 +1907,20 @@ http ); ---- +.Xml +[source,xml,role="secondary"] +---- + + + + + + + +---- +==== + === Bearer Token Propagation Now that you're in possession of a bearer token, it might be handy to pass that to downstream services.