diff --git a/docs/src/docs/asciidoc/configuration-model.adoc b/docs/src/docs/asciidoc/configuration-model.adoc index 908db7dd..1afa75d2 100644 --- a/docs/src/docs/asciidoc/configuration-model.adoc +++ b/docs/src/docs/asciidoc/configuration-model.adoc @@ -70,6 +70,7 @@ public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity h In addition to the default protocol endpoints, the OAuth2 authorization server `SecurityFilterChain` `@Bean` is configured with the following OpenID Connect 1.0 protocol endpoints: * xref:protocol-endpoints.adoc#oidc-provider-configuration-endpoint[OpenID Connect 1.0 Provider Configuration endpoint] +* xref:protocol-endpoints.adoc#oidc-logout-endpoint[OpenID Connect 1.0 Logout endpoint] * xref:protocol-endpoints.adoc#oidc-user-info-endpoint[OpenID Connect 1.0 UserInfo endpoint] [NOTE] @@ -123,8 +124,9 @@ public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity h .authorizationServerMetadataEndpoint(authorizationServerMetadataEndpoint -> { }) <13> .oidc(oidc -> oidc .providerConfigurationEndpoint(providerConfigurationEndpoint -> { }) <14> - .userInfoEndpoint(userInfoEndpoint -> { }) <15> - .clientRegistrationEndpoint(clientRegistrationEndpoint -> { }) <16> + .logoutEndpoint(logoutEndpoint -> { }) <15> + .userInfoEndpoint(userInfoEndpoint -> { }) <16> + .clientRegistrationEndpoint(clientRegistrationEndpoint -> { }) <17> ); return http.build(); @@ -144,8 +146,9 @@ public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity h <12> `tokenRevocationEndpoint()`: The configurer for the xref:protocol-endpoints.adoc#oauth2-token-revocation-endpoint[OAuth2 Token Revocation endpoint]. <13> `authorizationServerMetadataEndpoint()`: The configurer for the xref:protocol-endpoints.adoc#oauth2-authorization-server-metadata-endpoint[OAuth2 Authorization Server Metadata endpoint]. <14> `providerConfigurationEndpoint()`: The configurer for the xref:protocol-endpoints.adoc#oidc-provider-configuration-endpoint[OpenID Connect 1.0 Provider Configuration endpoint]. -<15> `userInfoEndpoint()`: The configurer for the xref:protocol-endpoints.adoc#oidc-user-info-endpoint[OpenID Connect 1.0 UserInfo endpoint]. -<16> `clientRegistrationEndpoint()`: The configurer for the xref:protocol-endpoints.adoc#oidc-client-registration-endpoint[OpenID Connect 1.0 Client Registration endpoint]. +<15> `logoutEndpoint()`: The configurer for the xref:protocol-endpoints.adoc#oidc-logout-endpoint[OpenID Connect 1.0 Logout endpoint]. +<16> `userInfoEndpoint()`: The configurer for the xref:protocol-endpoints.adoc#oidc-user-info-endpoint[OpenID Connect 1.0 UserInfo endpoint]. +<17> `clientRegistrationEndpoint()`: The configurer for the xref:protocol-endpoints.adoc#oidc-client-registration-endpoint[OpenID Connect 1.0 Client Registration endpoint]. [[configuring-authorization-server-settings]] == Configuring Authorization Server Settings @@ -169,6 +172,7 @@ public final class AuthorizationServerSettings extends AbstractSettings { .tokenIntrospectionEndpoint("/oauth2/introspect") .tokenRevocationEndpoint("/oauth2/revoke") .jwkSetEndpoint("/oauth2/jwks") + .oidcLogoutEndpoint("/connect/logout") .oidcUserInfoEndpoint("/userinfo") .oidcClientRegistrationEndpoint("/connect/register"); } @@ -199,6 +203,7 @@ public AuthorizationServerSettings authorizationServerSettings() { .tokenIntrospectionEndpoint("/oauth2/v1/introspect") .tokenRevocationEndpoint("/oauth2/v1/revoke") .jwkSetEndpoint("/oauth2/v1/jwks") + .oidcLogoutEndpoint("/connect/v1/logout") .oidcUserInfoEndpoint("/connect/v1/userinfo") .oidcClientRegistrationEndpoint("/connect/v1/register") .build(); diff --git a/docs/src/docs/asciidoc/core-model-components.adoc b/docs/src/docs/asciidoc/core-model-components.adoc index a345a78b..755148e1 100644 --- a/docs/src/docs/asciidoc/core-model-components.adoc +++ b/docs/src/docs/asciidoc/core-model-components.adoc @@ -69,9 +69,10 @@ public class RegisteredClient implements Serializable { private Set clientAuthenticationMethods; <7> private Set authorizationGrantTypes; <8> private Set redirectUris; <9> - private Set scopes; <10> - private ClientSettings clientSettings; <11> - private TokenSettings tokenSettings; <12> + private Set postLogoutRedirectUris; <10> + private Set scopes; <11> + private ClientSettings clientSettings; <12> + private TokenSettings tokenSettings; <13> ... @@ -86,9 +87,10 @@ public class RegisteredClient implements Serializable { <7> `clientAuthenticationMethods`: The authentication method(s) that the client may use. The supported values are `client_secret_basic`, `client_secret_post`, https://datatracker.ietf.org/doc/html/rfc7523[`private_key_jwt`], `client_secret_jwt`, and `none` https://datatracker.ietf.org/doc/html/rfc7636[(public clients)]. <8> `authorizationGrantTypes`: The https://datatracker.ietf.org/doc/html/rfc6749#section-1.3[authorization grant type(s)] that the client can use. The supported values are `authorization_code`, `client_credentials`, `refresh_token`, and `urn:ietf:params:oauth:grant-type:device_code`. <9> `redirectUris`: The registered https://datatracker.ietf.org/doc/html/rfc6749#section-3.1.2[redirect URI(s)] that the client may use in redirect-based flows – for example, `authorization_code` grant. -<10> `scopes`: The scope(s) that the client is allowed to request. -<11> `clientSettings`: The custom settings for the client – for example, require https://datatracker.ietf.org/doc/html/rfc7636[PKCE], require authorization consent, and others. -<12> `tokenSettings`: The custom settings for the OAuth2 tokens issued to the client – for example, access/refresh token time-to-live, reuse refresh tokens, and others. +<10> `postLogoutRedirectUris`: The post logout redirect URI(s) that the client may use for logout. +<11> `scopes`: The scope(s) that the client is allowed to request. +<12> `clientSettings`: The custom settings for the client – for example, require https://datatracker.ietf.org/doc/html/rfc7636[PKCE], require authorization consent, and others. +<13> `tokenSettings`: The custom settings for the OAuth2 tokens issued to the client – for example, access/refresh token time-to-live, reuse refresh tokens, and others. [[registered-client-repository]] == RegisteredClientRepository @@ -491,3 +493,34 @@ If the `OAuth2TokenGenerator` is not provided as a `@Bean` or is not configured [TIP] For an example showing how you can xref:guides/how-to-userinfo.adoc#customize-id-token[customize the ID token], see the guide xref:guides/how-to-userinfo.adoc#how-to-userinfo[How-to: Customize the OpenID Connect 1.0 UserInfo response]. + +[[session-registry]] +== SessionRegistry + +If OpenID Connect 1.0 is enabled, a `SessionRegistry` instance is used to track authenticated sessions. +The `SessionRegistry` is used by the default implementation of `SessionAuthenticationStrategy` associated to the xref:protocol-endpoints.adoc#oauth2-authorization-endpoint[OAuth2 Authorization Endpoint] for registering new authenticated sessions. + +[NOTE] +If a `SessionRegistry` `@Bean` is not registered, the default implementation `SessionRegistryImpl` will be used. + +[IMPORTANT] +If a `SessionRegistry` `@Bean` is registered and is an instance of `SessionRegistryImpl`, a `HttpSessionEventPublisher` `@Bean` *SHOULD* also be registered as it's responsible for notifying `SessionRegistryImpl` of session lifecycle events, for example, `SessionDestroyedEvent`, to provide the ability to remove the `SessionInformation` instance. + +When a logout is requested by an End-User, the xref:protocol-endpoints.adoc#oidc-logout-endpoint[OpenID Connect 1.0 Logout Endpoint] uses the `SessionRegistry` to lookup the `SessionInformation` associated to the authenticated End-User to perform the logout. + +If Spring Security's {spring-security-reference-base-url}/servlet/authentication/session-management.html#ns-concurrent-sessions[Concurrent Session Control] feature is being used, it is *RECOMMENDED* to register a `SessionRegistry` `@Bean` to ensure it's shared between Spring Security's Concurrent Session Control and Spring Authorization Server's Logout feature. + +The following example shows how to register a `SessionRegistry` `@Bean` and `HttpSessionEventPublisher` `@Bean` (required by `SessionRegistryImpl`): + +[source,java] +---- +@Bean +public SessionRegistry sessionRegistry() { + return new SessionRegistryImpl(); +} + +@Bean +public HttpSessionEventPublisher httpSessionEventPublisher() { + return new HttpSessionEventPublisher(); +} +---- diff --git a/docs/src/docs/asciidoc/examples/src/main/java/sample/gettingStarted/SecurityConfig.java b/docs/src/docs/asciidoc/examples/src/main/java/sample/gettingStarted/SecurityConfig.java index 5f92ddf3..bd7e9d1a 100644 --- a/docs/src/docs/asciidoc/examples/src/main/java/sample/gettingStarted/SecurityConfig.java +++ b/docs/src/docs/asciidoc/examples/src/main/java/sample/gettingStarted/SecurityConfig.java @@ -119,6 +119,7 @@ public class SecurityConfig { .authorizationGrantType(AuthorizationGrantType.DEVICE_CODE) .redirectUri("http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc") .redirectUri("http://127.0.0.1:8080/authorized") + .postLogoutRedirectUri("http://127.0.0.1:8080/index") .scope(OidcScopes.OPENID) .scope(OidcScopes.PROFILE) .scope("message.read") diff --git a/docs/src/docs/asciidoc/overview.adoc b/docs/src/docs/asciidoc/overview.adoc index 5b68d83a..2853bb4a 100644 --- a/docs/src/docs/asciidoc/overview.adoc +++ b/docs/src/docs/asciidoc/overview.adoc @@ -68,6 +68,7 @@ Spring Authorization Server supports the following features: * xref:protocol-endpoints.adoc#oauth2-authorization-server-metadata-endpoint[OAuth2 Authorization Server Metadata Endpoint] * xref:protocol-endpoints.adoc#jwk-set-endpoint[JWK Set Endpoint] * xref:protocol-endpoints.adoc#oidc-provider-configuration-endpoint[OpenID Connect 1.0 Provider Configuration Endpoint] +* xref:protocol-endpoints.adoc#oidc-logout-endpoint[OpenID Connect 1.0 Logout Endpoint] * xref:protocol-endpoints.adoc#oidc-user-info-endpoint[OpenID Connect 1.0 UserInfo Endpoint] * xref:protocol-endpoints.adoc#oidc-client-registration-endpoint[OpenID Connect 1.0 Client Registration Endpoint] | @@ -83,6 +84,8 @@ Spring Authorization Server supports the following features: * JSON Web Key (JWK) (https://tools.ietf.org/html/rfc7517[RFC 7517]) * OpenID Connect Discovery 1.0 (https://openid.net/specs/openid-connect-discovery-1_0.html[spec]) ** https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Provider Configuration Endpoint] +* OpenID Connect RP-Initiated Logout 1.0 (https://openid.net/specs/openid-connect-rpinitiated-1_0.html[spec]) +** https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout[Logout Endpoint] * OpenID Connect Core 1.0 (https://openid.net/specs/openid-connect-core-1_0.html[spec]) ** https://openid.net/specs/openid-connect-core-1_0.html#UserInfo[UserInfo Endpoint] * OpenID Connect Dynamic Client Registration 1.0 (https://openid.net/specs/openid-connect-registration-1_0.html[spec]) diff --git a/docs/src/docs/asciidoc/protocol-endpoints.adoc b/docs/src/docs/asciidoc/protocol-endpoints.adoc index 9640ba2e..87874b2f 100644 --- a/docs/src/docs/asciidoc/protocol-endpoints.adoc +++ b/docs/src/docs/asciidoc/protocol-endpoints.adoc @@ -433,6 +433,62 @@ public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity h `OidcProviderConfigurationEndpointConfigurer` configures the `OidcProviderConfigurationEndpointFilter` and registers it with the OAuth2 authorization server `SecurityFilterChain` `@Bean`. `OidcProviderConfigurationEndpointFilter` is the `Filter` that returns the https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse[OidcProviderConfiguration response]. +[[oidc-logout-endpoint]] +== OpenID Connect 1.0 Logout Endpoint + +`OidcLogoutEndpointConfigurer` provides the ability to customize the https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout[OpenID Connect 1.0 Logout endpoint]. +It defines extension points that let you customize the pre-processing, main processing, and post-processing logic for RP-Initiated Logout requests. + +`OidcLogoutEndpointConfigurer` provides the following configuration options: + +[source,java] +---- +@Bean +public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception { + OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = + new OAuth2AuthorizationServerConfigurer(); + http.apply(authorizationServerConfigurer); + + authorizationServerConfigurer + .oidc(oidc -> + oidc + .logoutEndpoint(logoutEndpoint -> + logoutEndpoint + .logoutRequestConverter(logoutRequestConverter) <1> + .logoutRequestConverters(logoutRequestConvertersConsumer) <2> + .authenticationProvider(authenticationProvider) <3> + .authenticationProviders(authenticationProvidersConsumer) <4> + .logoutResponseHandler(logoutResponseHandler) <5> + .errorResponseHandler(errorResponseHandler) <6> + ) + ); + + return http.build(); +} +---- +<1> `logoutRequestConverter()`: Adds an `AuthenticationConverter` (_pre-processor_) used when attempting to extract a https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout[Logout request] from `HttpServletRequest` to an instance of `OidcLogoutAuthenticationToken`. +<2> `logoutRequestConverters()`: Sets the `Consumer` providing access to the `List` of default and (optionally) added ``AuthenticationConverter``'s allowing the ability to add, remove, or customize a specific `AuthenticationConverter`. +<3> `authenticationProvider()`: Adds an `AuthenticationProvider` (_main processor_) used for authenticating the `OidcLogoutAuthenticationToken`. +<4> `authenticationProviders()`: Sets the `Consumer` providing access to the `List` of default and (optionally) added ``AuthenticationProvider``'s allowing the ability to add, remove, or customize a specific `AuthenticationProvider`. +<5> `logoutResponseHandler()`: The `AuthenticationSuccessHandler` (_post-processor_) used for handling an "`authenticated`" `OidcLogoutAuthenticationToken` and performing the logout. +<6> `errorResponseHandler()`: The `AuthenticationFailureHandler` (_post-processor_) used for handling an `OAuth2AuthenticationException` and returning the error response. + +`OidcLogoutEndpointConfigurer` configures the `OidcLogoutEndpointFilter` and registers it with the OAuth2 authorization server `SecurityFilterChain` `@Bean`. +`OidcLogoutEndpointFilter` is the `Filter` that processes https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout[RP-Initiated Logout requests] and performs the logout of the End-User. + +`OidcLogoutEndpointFilter` is configured with the following defaults: + +* `*AuthenticationConverter*` -- An `OidcLogoutAuthenticationConverter`. +* `*AuthenticationManager*` -- An `AuthenticationManager` composed of `OidcLogoutAuthenticationProvider`. +* `*AuthenticationSuccessHandler*` -- An internal implementation that handles an "`authenticated`" `OidcLogoutAuthenticationToken` and performs the logout. +* `*AuthenticationFailureHandler*` -- An internal implementation that uses the `OAuth2Error` associated with the `OAuth2AuthenticationException` and returns the `OAuth2Error` response. + +[NOTE] +`OidcLogoutAuthenticationProvider` uses a xref:core-model-components.adoc#session-registry[`SessionRegistry`] to look up the `SessionInformation` instance associated to the End-User requesting to be logged out. + +[TIP] +`OidcClientInitiatedLogoutSuccessHandler` is the corresponding configuration in Spring Security’s OAuth2 Client support for configuring {spring-security-reference-base-url}/servlet/oauth2/login/advanced.html#oauth2login-advanced-oidc-logout[OpenID Connect 1.0 RP-Initiated Logout]. + [[oidc-user-info-endpoint]] == OpenID Connect 1.0 UserInfo Endpoint