Skip to content

Commit

Permalink
Document new features for OAuth Client
Browse files Browse the repository at this point in the history
  • Loading branch information
jgrandja committed Oct 12, 2018
1 parent a26eadc commit 26fcde6
Show file tree
Hide file tree
Showing 4 changed files with 895 additions and 671 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@


[[oauth2login-advanced]]
== OAuth 2.0 Login -- Advanced Configuration

`HttpSecurity.oauth2Login()` provides a number of configuration options for customizing OAuth 2.0 Login.
The main configuration options are grouped into their protocol endpoint counterparts.

For example, `oauth2Login().authorizationEndpoint()` allows configuring the _Authorization Endpoint_,
whereas `oauth2Login().tokenEndpoint()` allows configuring the _Token Endpoint_.
For example, `oauth2Login().authorizationEndpoint()` allows configuring the _Authorization Endpoint_, whereas `oauth2Login().tokenEndpoint()` allows configuring the _Token Endpoint_.

The following code shows an example:

Expand Down Expand Up @@ -43,14 +40,12 @@ The authorization process utilizes two authorization server endpoints (HTTP reso

As well as one client endpoint:

* Redirection Endpoint: Used by the authorization server to return responses
containing authorization credentials to the client via the resource owner user-agent.
* Redirection Endpoint: Used by the authorization server to return responses containing authorization credentials to the client via the resource owner user-agent.

The OpenID Connect Core 1.0 specification defines the http://openid.net/specs/openid-connect-core-1_0.html#UserInfo[UserInfo Endpoint] as follows:

The UserInfo Endpoint is an OAuth 2.0 Protected Resource that returns claims about the authenticated end-user.
To obtain the requested claims about the end-user, the client makes a request to the UserInfo Endpoint
by using an access token obtained through OpenID Connect Authentication.
To obtain the requested claims about the end-user, the client makes a request to the UserInfo Endpoint by using an access token obtained through OpenID Connect Authentication.
These claims are normally represented by a JSON object that contains a collection of name-value pairs for the claims.

The following code shows the complete configuration options available for the `oauth2Login()` DSL:
Expand All @@ -65,11 +60,13 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
http
.oauth2Login()
.clientRegistrationRepository(this.clientRegistrationRepository())
.authorizedClientRepository(this.authorizedClientRepository())
.authorizedClientService(this.authorizedClientService())
.loginPage("/login")
.authorizationEndpoint()
.baseUri(this.authorizationRequestBaseUri())
.authorizationRequestRepository(this.authorizationRequestRepository())
.authorizationRequestResolver(this.authorizationRequestResolver())
.and()
.redirectionEndpoint()
.baseUri(this.authorizationResponseBaseUri())
Expand All @@ -86,21 +83,18 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
}
----

The sections to follow go into more detail on each of the configuration options available:
The following sections go into more detail on each of the configuration options available:

* <<oauth2login-advanced-login-page>>
* <<oauth2login-advanced-authorization-endpoint>>
* <<oauth2login-advanced-redirection-endpoint>>
* <<oauth2login-advanced-token-endpoint>>
* <<oauth2login-advanced-userinfo-endpoint>>


[[oauth2login-advanced-login-page]]
=== OAuth 2.0 Login Page

By default, the OAuth 2.0 Login Page is auto-generated by the `DefaultLoginPageGeneratingFilter`.
The default login page shows each configured OAuth Client with its `ClientRegistration.clientName`
as a link, which is capable of initiating the Authorization Request (or OAuth 2.0 Login).
The default login page shows each configured OAuth Client with its `ClientRegistration.clientName` as a link, which is capable of initiating the Authorization Request (or OAuth 2.0 Login).

The link's destination for each OAuth Client defaults to the following:

Expand All @@ -113,8 +107,7 @@ The following line shows an example:
<a href="/oauth2/authorization/google">Google</a>
----

To override the default login page,
configure `oauth2Login().loginPage()` and (optionally) `oauth2Login().authorizationEndpoint().baseUri()`.
To override the default login page, configure `oauth2Login().loginPage()` and (optionally) `oauth2Login().authorizationEndpoint().baseUri()`.

The following listing shows an example:

Expand Down Expand Up @@ -152,52 +145,11 @@ The following line shows an example:
----
====

[[oauth2login-advanced-authorization-endpoint]]
=== Authorization Endpoint


[[oauth2login-advanced-authorization-request-repository]]
==== `AuthorizationRequestRepository`

`AuthorizationRequestRepository` is responsible for the persistence of the `OAuth2AuthorizationRequest`
from the time the Authorization Request is initiated to the time the Authorization Response
is received (the callback).

[TIP]
The `OAuth2AuthorizationRequest` is used to correlate and validate the Authorization Response.

The default implementation of `AuthorizationRequestRepository` is `HttpSessionOAuth2AuthorizationRequestRepository`,
which stores the `OAuth2AuthorizationRequest` in the `HttpSession`.

If you would like to provide a custom implementation of `AuthorizationRequestRepository`
that stores the attributes of `OAuth2AuthorizationRequest` in a `Cookie`,
configure it as shown in the following example:

[source,java]
----
@EnableWebSecurity
public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.oauth2Login()
.authorizationEndpoint()
.authorizationRequestRepository(this.cookieAuthorizationRequestRepository())
...
}
private AuthorizationRequestRepository<OAuth2AuthorizationRequest> cookieAuthorizationRequestRepository() {
return new HttpCookieOAuth2AuthorizationRequestRepository();
}
}
----

[[oauth2login-advanced-redirection-endpoint]]
=== Redirection Endpoint

The Redirection Endpoint is used by the Authorization Server for returning the Authorization Response
(which contains the authorization credentials) to the client via the Resource Owner user-agent.
The Redirection Endpoint is used by the Authorization Server for returning the Authorization Response (which contains the authorization credentials) to the client via the Resource Owner user-agent.

[TIP]
OAuth 2.0 Login leverages the Authorization Code Grant.
Expand Down Expand Up @@ -239,74 +191,34 @@ return CommonOAuth2Provider.GOOGLE.getBuilder("google")
----
====

[[oauth2login-advanced-token-endpoint]]
=== Token Endpoint


[[oauth2login-advanced-token-client]]
==== OAuth2AccessTokenResponseClient

`OAuth2AccessTokenResponseClient` is responsible for exchanging an authorization grant credential
for an access token credential at the Authorization Server's Token Endpoint.

The default implementation of `OAuth2AccessTokenResponseClient` is `NimbusAuthorizationCodeTokenResponseClient`,
which exchanges an authorization code for an access token at the Token Endpoint.

[NOTE]
`NimbusAuthorizationCodeTokenResponseClient` uses the https://connect2id.com/products/nimbus-oauth-openid-connect-sdk[Nimbus OAuth 2.0 SDK] internally.

If you would like to provide a custom implementation of `OAuth2AccessTokenResponseClient`
that uses Spring Framework 5 reactive `WebClient` for initiating requests to the Token Endpoint,
configure it as shown in the following example:

[source,java]
----
@EnableWebSecurity
public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.oauth2Login()
.tokenEndpoint()
.accessTokenResponseClient(this.accessTokenResponseClient())
...
}
private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient() {
return new SpringWebClientAuthorizationCodeTokenResponseClient();
}
}
----

[[oauth2login-advanced-userinfo-endpoint]]
=== UserInfo Endpoint

The UserInfo Endpoint includes a number of configuration options, as described in the following sub-sections:

* <<oauth2login-advanced-map-authorities>>
* <<oauth2login-advanced-custom-user>>
* <<oauth2login-advanced-oauth2-user-service>>
* <<oauth2login-advanced-oidc-user-service>>
* <<oauth2login-advanced-map-authorities, Mapping User Authorities>>
* <<oauth2login-advanced-custom-user, Configuring a Custom OAuth2User>>
* <<oauth2login-advanced-oauth2-user-service, OAuth 2.0 UserService>>
* <<oauth2login-advanced-oidc-user-service, OpenID Connect 1.0 UserService>>


[[oauth2login-advanced-map-authorities]]
==== Mapping User Authorities

After the user successfully authenticates with the OAuth 2.0 Provider,
the `OAuth2User.getAuthorities()` (or `OidcUser.getAuthorities()`) may be mapped to a new set of `GrantedAuthority` instances,
which will be supplied to `OAuth2AuthenticationToken` when completing the authentication.
After the user successfully authenticates with the OAuth 2.0 Provider, the `OAuth2User.getAuthorities()` (or `OidcUser.getAuthorities()`) may be mapped to a new set of `GrantedAuthority` instances, which will be supplied to `OAuth2AuthenticationToken` when completing the authentication.

[TIP]
`OAuth2AuthenticationToken.getAuthorities()` is used for authorizing requests, such as in `hasRole('USER')` or `hasRole('ADMIN')`.

There are a couple of options to choose from when mapping user authorities:

* <<oauth2login-advanced-map-authorities-grantedauthoritiesmapper,Using a `GrantedAuthoritiesMapper`>>
* <<oauth2login-advanced-map-authorities-oauth2userservice,Delegation-based strategy with `OAuth2UserService`>>
* <<oauth2login-advanced-map-authorities-grantedauthoritiesmapper, Using a GrantedAuthoritiesMapper>>
* <<oauth2login-advanced-map-authorities-oauth2userservice, Delegation-based strategy with OAuth2UserService>>


[[oauth2login-advanced-map-authorities-grantedauthoritiesmapper]]
===== Using a `GrantedAuthoritiesMapper`
===== Using a GrantedAuthoritiesMapper

Provide an implementation of `GrantedAuthoritiesMapper` and configure it as shown in the following example:

Expand Down Expand Up @@ -374,16 +286,13 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
}
----


[[oauth2login-advanced-map-authorities-oauth2userservice]]
===== Delegation-based strategy with `OAuth2UserService`
===== Delegation-based strategy with OAuth2UserService

This strategy is advanced compared to using a `GrantedAuthoritiesMapper`, however, it's also more flexible
as it gives you access to the `OAuth2UserRequest` and `OAuth2User` (when using an OAuth 2.0 UserService)
or `OidcUserRequest` and `OidcUser` (when using an OpenID Connect 1.0 UserService).
This strategy is advanced compared to using a `GrantedAuthoritiesMapper`, however, it's also more flexible as it gives you access to the `OAuth2UserRequest` and `OAuth2User` (when using an OAuth 2.0 UserService) or `OidcUserRequest` and `OidcUser` (when using an OpenID Connect 1.0 UserService).

The `OAuth2UserRequest` (and `OidcUserRequest`) provides you access to the associated `OAuth2AccessToken`,
which is very useful in the cases where the _delegator_ needs to fetch authority information
from a protected resource before it can map the custom authorities for the user.
The `OAuth2UserRequest` (and `OidcUserRequest`) provides you access to the associated `OAuth2AccessToken`, which is very useful in the cases where the _delegator_ needs to fetch authority information from a protected resource before it can map the custom authorities for the user.

The following example shows how to implement and configure a delegation-based strategy using an OpenID Connect 1.0 UserService:

Expand Down Expand Up @@ -424,14 +333,13 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
}
----


[[oauth2login-advanced-custom-user]]
==== Configuring a Custom OAuth2User

`CustomUserTypesOAuth2UserService` is an implementation of an `OAuth2UserService`
that provides support for custom `OAuth2User` types.
`CustomUserTypesOAuth2UserService` is an implementation of an `OAuth2UserService` that provides support for custom `OAuth2User` types.

If the default implementation (`DefaultOAuth2User`) does not suit your needs,
you can define your own implementation of `OAuth2User`.
If the default implementation (`DefaultOAuth2User`) does not suit your needs, you can define your own implementation of `OAuth2User`.

The following code demonstrates how you would register a custom `OAuth2User` type for GitHub:

Expand Down Expand Up @@ -521,22 +429,33 @@ public class GitHubOAuth2User implements OAuth2User {
For detailed information returned from the UserInfo Endpoint, see the API documentation
for https://developer.github.com/v3/users/#get-the-authenticated-user["Get the authenticated user"].


[[oauth2login-advanced-oauth2-user-service]]
==== OAuth 2.0 UserService

`DefaultOAuth2UserService` is an implementation of an `OAuth2UserService`
that supports standard OAuth 2.0 Provider's.
`DefaultOAuth2UserService` is an implementation of an `OAuth2UserService` that supports standard OAuth 2.0 Provider's.

[NOTE]
`OAuth2UserService` obtains the user attributes
of the end-user (the resource owner) from the UserInfo Endpoint (by using the
access token granted to the client during the authorization flow)
and returns an `AuthenticatedPrincipal` in the form of an `OAuth2User`.
`OAuth2UserService` obtains the user attributes of the end-user (the resource owner) from the UserInfo Endpoint (by using the access token granted to the client during the authorization flow) and returns an `AuthenticatedPrincipal` in the form of an `OAuth2User`.

`DefaultOAuth2UserService` uses a `RestOperations` when requesting the user attributes at the UserInfo Endpoint.

If you need to customize the pre-processing of the UserInfo Request, you can provide `DefaultOAuth2UserService.setRequestEntityConverter()` with a custom `Converter<OAuth2UserRequest, RequestEntity<?>>`.
The default implementation `OAuth2UserRequestEntityConverter` builds a `RequestEntity` representation of a UserInfo Request that sets the `OAuth2AccessToken` in the `Authorization` header by default.

On the other end, if you need to customize the post-handling of the UserInfo Response, you will need to provide `DefaultOAuth2UserService.setRestOperations()` with a custom configured `RestOperations`.
The default `RestOperations` is configured as follows:

If the default implementation does not suit your needs, you can define your own implementation of `OAuth2UserService`
for standard OAuth 2.0 Provider's.
[source,java]
----
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
----

`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error (400 Bad Request).
It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`.

The following configuration demonstrates how to configure a custom `OAuth2UserService`:
Whether you customize `DefaultOAuth2UserService` or provide your own implementation of `OAuth2UserService`, you'll need to configure it as shown in the following example:

[source,java]
----
Expand All @@ -553,27 +472,22 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
}
private OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService() {
return new CustomOAuth2UserService();
...
}
}
----


[[oauth2login-advanced-oidc-user-service]]
==== OpenID Connect 1.0 UserService

`OidcUserService` is an implementation of an `OAuth2UserService`
that supports OpenID Connect 1.0 Provider's.
`OidcUserService` is an implementation of an `OAuth2UserService` that supports OpenID Connect 1.0 Provider's.

[NOTE]
`OAuth2UserService` is responsible for obtaining the user attributes
of the end user (the resource owner) from the UserInfo Endpoint (by using the
access token granted to the client during the authorization flow)
and return an `AuthenticatedPrincipal` in the form of an `OidcUser`.
The `OidcUserService` leverages the `DefaultOAuth2UserService` when requesting the user attributes at the UserInfo Endpoint.

If the default implementation does not suit your needs, you can define your own implementation of `OAuth2UserService`
for OpenID Connect 1.0 Provider's.
If you need to customize the pre-processing of the UserInfo Request and/or the post-handling of the UserInfo Response, you will need to provide `OidcUserService.setOauth2UserService()` with a custom configured `DefaultOAuth2UserService`.

The following configuration demonstrates how to configure a custom OpenID Connect 1.0 `OAuth2UserService`:
Whether you customize `OidcUserService` or provide your own implementation of `OAuth2UserService` for OpenID Connect 1.0 Provider's, you'll need to configure it as shown in the following example:

[source,java]
----
Expand All @@ -590,7 +504,7 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
}
private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
return new CustomOidcUserService();
...
}
}
----
Loading

0 comments on commit 26fcde6

Please sign in to comment.