Browse Source

Add Figures to Resource Server Docs

Fixes gh-8182
Josh Cummings 5 years ago
parent
commit
e62b8a7585

+ 1 - 0
docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/basic.adoc

@@ -23,6 +23,7 @@ The `RequestCache` is typically a `NullRequestCache` that does not save the requ
 When a client receives the WWW-Authenticate header it knows it should retry with a username and password.
 Below is the flow for the username and password being processed.
 
+[[servlet-authentication-basicauthenticationfilter]]
 .Authenticating Username and Password
 image::{figures}/basicauthenticationfilter.png[]
 

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

@@ -1,5 +1,7 @@
 [[oauth2resourceserver]]
 == OAuth 2.0 Resource Server
+:figures: images/servlet/oauth2
+:icondir: images/icons
 
 Spring Security supports protecting endpoints using two forms of OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]:
 
@@ -9,12 +11,54 @@ Spring Security supports protecting endpoints using two forms of OAuth 2.0 https
 This is handy in circumstances where an application has delegated its authority management to an https://tools.ietf.org/html/rfc6749[authorization server] (for example, Okta or Ping Identity).
 This authorization server can be consulted by resource servers to authorize requests.
 
+This section provides details on how Spring Security provides support for OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens].
+
 [NOTE]
 ====
 Working samples for both {gh-samples-url}/boot/oauth2resourceserver[JWTs] and {gh-samples-url}/boot/oauth2resourceserver-opaque[Opaque Tokens] are available in the {gh-samples-url}[Spring Security repository].
 ====
 
-=== Dependencies
+Let's take a look at how Bearer Token Authentication works within Spring Security.
+First, we see that, like <<servlet-authentication-basic,Basic Authentication>>, the https://tools.ietf.org/html/rfc7235#section-4.1[WWW-Authenticate] header is sent back to an unauthenticated client.
+
+.Sending WWW-Authenticate Header
+image::{figures}/bearerauthenticationentrypoint.png[]
+
+The figure above builds off our <<servlet-securityfilterchain,`SecurityFilterChain`>> diagram.
+
+image:{icondir}/number_1.png[] First, a user makes an unauthenticated request to the resource `/private` for which it is not authorized.
+
+image:{icondir}/number_2.png[] Spring Security's <<servlet-authorization-filtersecurityinterceptor,`FilterSecurityInterceptor`>> indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`.
+
+image:{icondir}/number_3.png[] Since the user is not authenticated, <<servlet-exceptiontranslationfilter,`ExceptionTranslationFilter`>> initiates __Start Authentication__.
+The configured <<servlet-authentication-authenticationentrypoint,`AuthenticationEntryPoint`>> is an instance of {security-api-url}org/springframework/security/oauth2/server/resource/authentication/BearerTokenAuthenticationEntryPoint.html[`BearerTokenAuthenticationEntryPoint`] which sends a WWW-Authenticate header.
+The `RequestCache` is typically a `NullRequestCache` that does not save the request since the client is capable of replaying the requests it originally requested.
+
+When a client receives the `WWW-Authenticate: Bearer` header, it knows it should retry with a bearer token.
+Below is the flow for the bearer token being processed.
+
+[[oauth2resourceserver-authentication-bearertokenauthenticationfilter]]
+.Authenticating Bearer Token
+image::{figures}/bearertokenauthenticationfilter.png[]
+
+The figure builds off our <<servlet-securityfilterchain,`SecurityFilterChain`>> diagram.
+
+image:{icondir}/number_1.png[] When the user submits their bearer token, the `BearerTokenAuthenticationFilter` creates a `BearerTokenAuthenticationToken` which is a type of <<servlet-authentication-authentication,`Authentication`>> by extracting the token from the `HttpServletRequest`.
+
+image:{icondir}/number_2.png[] Next, the `HttpServletRequest` is passed to the `AuthenticationManagerResolver`, which selects the `AuthenticationManager`. The `BearerTokenAuthenticationToken` is passed into the `AuthenticationManager` to be authenticated.
+The details of what `AuthenticationManager` looks like depends on whether you're configured for <<oauth2resourceserver-jwt-minimalconfiguration,JWT>> or <<oauth2resourceserver-opaque-minimalconfiguration,opaque token>>.
+
+image:{icondir}/number_3.png[] If authentication fails, then __Failure__
+
+* The <<servlet-authentication-securitycontextholder>> is cleared out.
+* The `AuthenticationEntryPoint` is invoked to trigger the WWW-Authenticate header to be sent again.
+
+image:{icondir}/number_4.png[] If authentication is successful, then __Success__.
+
+* The <<servlet-authentication-authentication>> is set on the <<servlet-authentication-securitycontextholder>>.
+* The `BearerTokenAuthenticationFilter` invokes `FilterChain.doFilter(request,response)` to continue with the rest of the application logic.
+
+=== Dependencies for JWT
 
 Most Resource Server support is collected into `spring-security-oauth2-resource-server`.
 However, the support for decoding and verifying JWTs is in `spring-security-oauth2-jose`, meaning that both are necessary in order to have a working resource server that supports JWT-encoded Bearer Tokens.
@@ -88,9 +132,35 @@ The resulting `Authentication#getPrincipal`, by default, is a Spring Security `J
 
 From here, consider jumping to:
 
-<<oauth2resourceserver-jwt-jwkseturi,How to Configure without Tying Resource Server startup to an authorization server's availability>>
+* <<oauth2resourceserver-jwt-architecture,How JWT Authentication Works>>
+* <<oauth2resourceserver-jwt-jwkseturi,How to Configure without tying Resource Server startup to an authorization server's availability>>
+* <<oauth2resourceserver-jwt-sansboot,How to Configure without Spring Boot>>
+
+[[oauth2resourceserver-jwt-architecture]]
+=== How JWT Authentication Works
 
-<<oauth2resourceserver-jwt-sansboot,How to Configure without Spring Boot>>
+Next, let's see the architectural components that Spring Security uses to support https://tools.ietf.org/html/rfc7519[JWT] Authentication in servlet-based applications, like the one we just saw.
+
+{security-api-url}org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProvider.html[`JwtAuthenticationProvider`] is an <<servlet-authentication-authenticationprovider,`AuthenticationProvider`>> implementation that leverages a <<oauth2resourceserver-jwt-decoder,`JwtDecoder`>> and <<oauth2resourceserver-jwt-authorization-extraction,`JwtAuthenticationConverter`>> to authenticate a JWT.
+
+Let's take a look at how `JwtAuthenticationProvider` works within Spring Security.
+The figure explains details of how the <<servlet-authentication-authenticationmanager,`AuthenticationManager`>> in figures from <<oauth2resourceserver-authentication-bearertokenauthenticationfilter,Reading the Bearer Token>> works.
+
+.`JwtAuthenticationProvider` Usage
+image::{figures}/jwtauthenticationprovider.png[]
+
+image:{icondir}/number_1.png[] The authentication `Filter` from <<oauth2resourceserver-authentication-bearertokenauthenticationfilter,Reading the Bearer Token>> passes a `BearerTokenAuthenticationToken` to the `AuthenticationManager` which is implemented by <<servlet-authentication-providermanager,`ProviderManager`>>.
+
+image:{icondir}/number_2.png[] The `ProviderManager` is configured to use an <<servlet-authentication-authenticationprovider>> of type `JwtAuthenticationProvider`.
+
+[[oauth2resourceserver-jwt-architecture-jwtdecoder]]
+image:{icondir}/number_3.png[] `JwtAuthenticationProvider` decodes, verifies, and validates the `Jwt` using a <<oauth2resourceserver-jwt-decoder,`JwtDecoder`>>.
+
+[[oauth2resourceserver-jwt-architecture-jwtauthenticationconverter]]
+image:{icondir}/number_4.png[] `JwtAuthenticationProvider` then uses the <<oauth2resourceserver-jwt-authorization-extraction,`JwtAuthenticationConverter`>> to convert the `Jwt` into a `Collection` of granted authorities.
+
+image:{icondir}/number_5.png[] When authentication is successful, the <<servlet-authentication-authentication,`Authentication`>> that is returned is of type `JwtAuthenticationToken` and has a principal that is the `Jwt` returned by the configured `JwtDecoder`.
+Ultimately, the returned `JwtAuthenticationToken` will be set on the <<servlet-authentication-securitycontextholder,`SecurityContextHolder`>> by the authentication `Filter`.
 
 [[oauth2resourceserver-jwt-jwkseturi]]
 === Specifying the Authorization Server JWK Set Uri Directly
@@ -206,8 +276,8 @@ The above requires the scope of `message:read` for any URL that starts with `/me
 
 Methods on the `oauth2ResourceServer` DSL will also override or replace auto configuration.
 
-For example, the second `@Bean` Spring Boot creates is a `JwtDecoder`, which decodes `String` tokens into validated instances of `Jwt`:
-
+[[oauth2resourceserver-jwt-decoder]]
+For example, the second `@Bean` Spring Boot creates is a `JwtDecoder`, which <<oauth2resourceserver-jwt-architecture-jwtdecoder,decodes `String` tokens into validated instances of `Jwt`>>:
 
 .JWT Decoder
 ====
@@ -323,7 +393,7 @@ Using `jwkSetUri()` takes precedence over any configuration property.
 [[oauth2resourceserver-jwt-decoder-dsl]]
 ==== Using `decoder()`
 
-More powerful than `jwkSetUri()` is `decoder()`, which will completely replace any Boot auto configuration of `JwtDecoder`:
+More powerful than `jwkSetUri()` is `decoder()`, which will completely replace any Boot auto configuration of <<oauth2resourceserver-jwt-architecture-jwtdecoder,`JwtDecoder`>>:
 
 .JWT Decoder Configuration
 ====
@@ -383,7 +453,7 @@ This is handy when deeper configuration, like <<oauth2resourceserver-jwt-validat
 [[oauth2resourceserver-jwt-decoder-bean]]
 ==== Exposing a `JwtDecoder` `@Bean`
 
-Or, exposing a `JwtDecoder` `@Bean` has the same effect as `decoder()`:
+Or, exposing a <<oauth2resourceserver-jwt-architecture-jwtdecoder,`JwtDecoder`>> `@Bean` has the same effect as `decoder()`:
 
 [source,java]
 ----
@@ -629,11 +699,11 @@ 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()`, which is responsible for converting a `Jwt` into an `Authentication`.
+To this end, the DSL exposes `jwtAuthenticationConverter()`, which is responsible for <<oauth2resourceserver-jwt-architecture-jwtauthenticationconverter,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.
 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:
+In that case, you can configure the claim that <<oauth2resourceserver-jwt-architecture-jwtauthenticationconverter,`JwtAuthenticationConverter`>> should inspect, like so:
 
 .Authorities Claim Configuration
 ====
@@ -817,7 +887,7 @@ OAuth2TokenValidator<Jwt> audienceValidator() {
 }
 ----
 
-Then, to add into a resource server, it's a matter of specifying the `JwtDecoder` instance:
+Then, to add into a resource server, it's a matter of specifying the <<oauth2resourceserver-jwt-architecture-jwtdecoder,`JwtDecoder`>> instance:
 
 [source,java]
 ----
@@ -1017,10 +1087,33 @@ The resulting `Authentication#getPrincipal`, by default, is a Spring Security `{
 
 From here, you may want to jump to:
 
+* <<oauth2resourceserver-opaque-architecture>>
 * <<oauth2resourceserver-opaque-attributes,Looking Up Attributes Post-Authentication>>
 * <<oauth2resourceserver-opaque-authorization-extraction,Extracting Authorities Manually>>
 * <<oauth2resourceserver-opaque-jwt-introspector,Using Introspection with JWTs>>
 
+[[oauth2resourceserver-opaque-architecture]]
+=== How Opaque Token Authentication Works
+
+Next, let's see the architectural components that Spring Security uses to support https://tools.ietf.org/html/rfc7662[opaque token] Authentication in servlet-based applications, like the one we just saw.
+
+{security-api-url}org/springframework/security/oauth2/server/resource/authentication/OpaqueTokenAuthenticationProvider.html[`OpaqueTokenAuthenticationProvider`] is an <<servlet-authentication-authenticationprovider,`AuthenticationProvider`>> implementation that leverages a <<oauth2resourceserver-opaque-introspector,`OpaqueTokenIntrospector`>> to authenticate an opaque token.
+
+Let's take a look at how `OpaqueTokenAuthenticationProvider` works within Spring Security.
+The figure explains details of how the <<servlet-authentication-authenticationmanager,`AuthenticationManager`>> in figures from <<oauth2resourceserver-authentication-bearertokenauthenticationfilter,Reading the Bearer Token>> works.
+
+.`OpaqueTokenAuthenticationProvider` Usage
+image::{figures}/opaquetokenauthenticationprovider.png[]
+
+image:{icondir}/number_1.png[] The authentication `Filter` from <<oauth2resourceserver-authentication-bearertokenauthenticationfilter,Reading the Bearer Token>> passes a `BearerTokenAuthenticationToken` to the `AuthenticationManager` which is implemented by <<servlet-authentication-providermanager,`ProviderManager`>>.
+
+image:{icondir}/number_2.png[] The `ProviderManager` is configured to use an <<servlet-authentication-authenticationprovider>> of type `OpaqueTokenAuthenticationProvider`.
+
+[[oauth2resourceserver-opaque-architecture-introspector]]
+image:{icondir}/number_3.png[] `OpaqueTokenAuthenticationProvider` introspects the opaque token and adds granted authorities using an <<oauth2resourceserver-opaque-introspector,`OpaqueTokenIntrospector`>>.
+When authentication is successful, the <<servlet-authentication-authentication,`Authentication`>> that is returned is of type `BearerTokenAuthentication` and has a principal that is the `OAuth2AuthenticatedPrincipal` returned by the configured <<oauth2resourceserver-opaque-introspector,`OpaqueTokenIntrospector`>>.
+Ultimately, the returned `BearerTokenAuthentication` will be set on the <<servlet-authentication-securitycontextholder,`SecurityContextHolder`>> by the authentication `Filter`.
+
 [[oauth2resourceserver-opaque-attributes]]
 === Looking Up Attributes Post-Authentication
 
@@ -1149,7 +1242,8 @@ The above requires the scope of `message:read` for any URL that starts with `/me
 
 Methods on the `oauth2ResourceServer` DSL will also override or replace auto configuration.
 
-For example, the second `@Bean` Spring Boot creates is an `OpaqueTokenIntrospector`, which decodes `String` tokens into validated instances of `OAuth2AuthenticatedPrincipal`:
+[[oauth2resourceserver-opaque-introspector]]
+For example, the second `@Bean` Spring Boot creates is an `OpaqueTokenIntrospector`, <<oauth2resourceserver-opaque-architecture-introspector,which decodes `String` tokens into validated instances of `OAuth2AuthenticatedPrincipal`>>:
 
 [source,java]
 ----
@@ -1159,11 +1253,11 @@ public OpaqueTokenIntrospector introspector() {
 }
 ----
 
-If the application doesn't expose a `OpaqueTokenIntrospector` bean, then Spring Boot will expose the above default one.
+If the application doesn't expose a <<oauth2resourceserver-opaque-architecture-introspector,`OpaqueTokenIntrospector`>> bean, then Spring Boot will expose the above default one.
 
 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.
+Or, if you're not using Spring Boot at all, then both of these components - the filter chain and a <<oauth2resourceserver-opaque-architecture-introspector,`OpaqueTokenIntrospector`>> can be specified in XML.
 
 The filter chain is specified like so:
 
@@ -1181,7 +1275,7 @@ The filter chain is specified like so:
 ----
 ====
 
-And the `OpaqueTokenIntrospector` like so:
+And the <<oauth2resourceserver-opaque-architecture-introspector,`OpaqueTokenIntrospector`>> like so:
 
 .Opaque Token Introspector
 ====
@@ -1262,7 +1356,7 @@ Using `introspectionUri()` takes precedence over any configuration property.
 [[oauth2resourceserver-opaque-introspector-dsl]]
 ==== Using `introspector()`
 
-More powerful than `introspectionUri()` is `introspector()`, which will completely replace any Boot auto configuration of `OpaqueTokenIntrospector`:
+More powerful than `introspectionUri()` is `introspector()`, which will completely replace any Boot auto configuration of <<oauth2resourceserver-opaque-architecture-introspector,`OpaqueTokenIntrospector`>>:
 
 .Introspector Configuration
 ====
@@ -1322,7 +1416,7 @@ This is handy when deeper configuration, like <<oauth2resourceserver-opaque-auth
 [[oauth2resourceserver-opaque-introspector-bean]]
 ==== Exposing a `OpaqueTokenIntrospector` `@Bean`
 
-Or, exposing a `OpaqueTokenIntrospector` `@Bean` has the same effect as `introspector()`:
+Or, exposing a <<oauth2resourceserver-opaque-architecture-introspector,`OpaqueTokenIntrospector`>> `@Bean` has the same effect as `introspector()`:
 
 [source,java]
 ----
@@ -1399,7 +1493,7 @@ For example, if the introspection response were:
 
 Then Resource Server would generate an `Authentication` with two authorities, one for `message:read` and the other for `message:write`.
 
-This can, of course, be customized using a custom `OpaqueTokenIntrospector` that takes a look at the attribute set and converts in its own way:
+This can, of course, be customized using a custom <<oauth2resourceserver-opaque-architecture-introspector,`OpaqueTokenIntrospector`>> that takes a look at the attribute set and converts in its own way:
 
 [source,java]
 ----
@@ -1483,7 +1577,7 @@ Any attributes in the corresponding `OAuth2AuthenticatedPrincipal` would be what
 But, let's say that, oddly enough, the introspection endpoint only returns whether or not the token is active.
 Now what?
 
-In this case, you can create a custom `OpaqueTokenIntrospector` that still hits the endpoint, but then updates the returned principal to have the JWTs claims as the attributes:
+In this case, you can create a custom <<oauth2resourceserver-opaque-architecture-introspector,`OpaqueTokenIntrospector`>> that still hits the endpoint, but then updates the returned principal to have the JWTs claims as the attributes:
 
 [source,java]
 ----
@@ -1528,7 +1622,7 @@ Generally speaking, a Resource Server doesn't care about the underlying user, bu
 
 That said, at times it can be valuable to tie the authorization statement back to a user.
 
-If an application is also using `spring-security-oauth2-client`, having set up the appropriate `ClientRegistrationRepository`, then this is quite simple with a custom `OpaqueTokenIntrospector`.
+If an application is also using `spring-security-oauth2-client`, having set up the appropriate `ClientRegistrationRepository`, then this is quite simple with a custom <<oauth2resourceserver-opaque-architecture-introspector,`OpaqueTokenIntrospector`>>.
 This implementation below does three things:
 
 * Delegates to the introspection endpoint, to affirm the token's validity
@@ -1577,7 +1671,7 @@ public class UserInfoOpaqueTokenIntrospector implements OpaqueTokenIntrospector
 }
 ----
 
-Either way, having created your `OpaqueTokenIntrospector`, you should publish it as a `@Bean` to override the defaults:
+Either way, having created your <<oauth2resourceserver-opaque-architecture-introspector,`OpaqueTokenIntrospector`>>, you should publish it as a `@Bean` to override the defaults:
 
 [source,java]
 ----
@@ -1732,9 +1826,9 @@ The issuer should be one that the code can verify from a trusted source like a w
 
 ===== Parsing the Claim Only Once
 
-You may have observed that this strategy, while simple, comes with the trade-off that the JWT is parsed once by the `AuthenticationManagerResolver` and then again by the `JwtDecoder` later on in the request.
+You may have observed that this strategy, while simple, comes with the trade-off that the JWT is parsed once by the `AuthenticationManagerResolver` and then again by the <<oauth2resourceserver-jwt-architecture-jwtdecoder,`JwtDecoder`>> later on in the request.
 
-This extra parsing can be alleviated by configuring the `JwtDecoder` directly with a `JWTClaimSetAwareJWSKeySelector` from Nimbus:
+This extra parsing can be alleviated by configuring the <<oauth2resourceserver-jwt-architecture-jwtdecoder,`JwtDecoder`>> directly with a `JWTClaimSetAwareJWSKeySelector` from Nimbus:
 
 [source,java]
 ----
@@ -1836,7 +1930,7 @@ public class TenantJwtIssuerValidator implements OAuth2TokenValidator<Jwt> {
 }
 ----
 
-Now that we have a tenant-aware processor and a tenant-aware validator, we can proceed with creating our `JwtDecoder`:
+Now that we have a tenant-aware processor and a tenant-aware validator, we can proceed with creating our <<oauth2resourceserver-jwt-architecture-jwtdecoder,`JwtDecoder`>>:
 
 [source,java]
 ----

BIN
docs/manual/src/docs/asciidoc/images/servlet/oauth2/beareraccessdeniedhandler.odg


BIN
docs/manual/src/docs/asciidoc/images/servlet/oauth2/bearerauthenticationentrypoint.odg


BIN
docs/manual/src/docs/asciidoc/images/servlet/oauth2/bearerauthenticationentrypoint.png


BIN
docs/manual/src/docs/asciidoc/images/servlet/oauth2/bearertokenauthenticationfilter.odg


BIN
docs/manual/src/docs/asciidoc/images/servlet/oauth2/bearertokenauthenticationfilter.png


BIN
docs/manual/src/docs/asciidoc/images/servlet/oauth2/jwtauthenticationprovider.odg


BIN
docs/manual/src/docs/asciidoc/images/servlet/oauth2/jwtauthenticationprovider.png


BIN
docs/manual/src/docs/asciidoc/images/servlet/oauth2/opaquetokenauthenticationprovider.odg


BIN
docs/manual/src/docs/asciidoc/images/servlet/oauth2/opaquetokenauthenticationprovider.png