Among its xref:servlet/authentication/logout.adoc[other logout mechanisms], Spring Security ships with support for RP- and AP-initiated SAML 2.0 Single Logout.
Briefly, there are two use cases Spring Security supports:
* **RP-Initiated** - Your application has an endpoint that, when POSTed to, will logout the user and send a `saml2:LogoutRequest` to the asserting party.
Thereafter, the asserting party will send back a `saml2:LogoutResponse` and allow your application to respond
* **AP-Initiated** - Your application has an endpoint that will receive a `saml2:LogoutRequest` from the asserting party.
Your application will complete its logout at that point and then send a `saml2:LogoutResponse` to the asserting party.
[NOTE]
In the **AP-Initiated** scenario, any local redirection that your application would do post-logout is rendered moot.
Once your application sends a `saml2:LogoutResponse`, it no longer has control of the browser.
== Minimal Configuration for Single Logout
To use Spring Security's SAML 2.0 Single Logout feature, you will need the following things:
* First, the asserting party must support SAML 2.0 Single Logout
* Second, the asserting party should be configured to sign and POST `saml2:LogoutRequest` s and `saml2:LogoutResponse` s your application's `/logout/saml2/slo` endpoint
* Third, your application must have a PKCS#8 private key and X.509 certificate for signing `saml2:LogoutRequest` s and `saml2:LogoutResponse` s
* Storing `<saml2:LogoutRequests>` somewhere <<_customizing_storage, other than the session>>
=== Startup Expectations
When these properties are used, in addition to login, SAML 2.0 Service Provider will automatically configure itself facilitate logout by way of ``<saml2:LogoutRequest>``s and ``<saml2:LogoutResponse>``s using either RP- or AP-initiated logout.
It achieves this through a deterministic startup process:
1. Query the Identity Server Metadata endpoint for the `<SingleLogoutService>` element
2. Scan the metadata and cache any public signature verification keys
3. Prepare the appropriate endpoints
A consequence of this process is that the identity server must be up and receiving requests in order for Service Provider to successfully start up.
[NOTE]
If the identity server is down when Service Provider queries it (given appropriate timeouts), then startup will fail.
2. Produce a `<saml2:LogoutRequest>` and POST it to the associated asserting party's SLO endpoint
3. Then, if the asserting party responds with a `<saml2:LogoutResponse>`, the application with verify it and redirect to the configured success endpoint
fun web(http: HttpSecurity): SecurityFilterChain {
http {
authorizeHttpRequests {
anyRequest = authenticated
}
saml2Login {
}
saml2Logout { <4>
}
}
return http.build()
}
}
----
======
<1> - The metadata URI of the IDP, which will indicate to your application its support of SLO
<2> - The SLO endpoint in your application
<3> - The signing credentials to sign ``<saml2:LogoutRequest>``s and ``<saml2:LogoutResponse>``s, which you can also add to xref:servlet/saml2/login/overview.adoc#servlet-saml2login-rpr-duplicated[multiple relying parties]
<4> - Second, indicate that your application wants to use SAML SLO to logout the end user
[NOTE]
Adding `saml2Logout` adds the capability for logout to your service provider as a whole.
Next, let's see the architectural components that Spring Security uses to support https://docs.oasis-open.org/security/saml/v2.0/saml-profiles-2.0-os.pdf#page=37[SAML 2.0 Logout] in servlet-based applications, like the one we just saw.
image:{icondir}/number_1.png[] Spring Security executes its xref:servlet/authentication/logout.adoc#logout-architecture[logout flow], calling its ``LogoutHandler``s to invalidate the session and perform other cleanup.
It then invokes the {security-api-url}org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2RelyingPartyInitiatedLogoutSuccessHandler.html[`Saml2RelyingPartyInitiatedLogoutSuccessHandler`].
image:{icondir}/number_2.png[] The logout success handler uses an instance of
{security-api-url}org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestResolver.html[`Saml2LogoutRequestResolver`] to create, sign, and serialize a `<saml2:LogoutRequest>`.
It uses the keys and configuration from the xref:servlet/saml2/login/overview.adoc#servlet-saml2login-relyingpartyregistration[`RelyingPartyRegistration`] that is associated with the current `Saml2AuthenticatedPrincipal`.
Then, it redirect-POSTs the `<saml2:LogoutRequest>` to the asserting party SLO endpoint
The browser hands control over to the asserting party.
If the asserting party redirects back (which it may not), then the application proceeds to step image:{icondir}/number_3.png[].
image:{icondir}/number_3.png[] The {security-api-url}org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutResponseFilter.html[`Saml2LogoutResponseFilter`] deserializes, verifies, and processes the `<saml2:LogoutResponse>` with its {security-api-url}org/springframework/security/saml2/provider/service/authentication/logout/Saml2LogoutResponseValidator.html[`Saml2LogoutResponseValidator`].
image:{icondir}/number_4.png[] If valid, then it completes the local logout flow by redirecting to `/login?logout`, or whatever has been configured.
If invalid, then it responds with a 400.
For AP-initiated logout:
image:{icondir}/number_1.png[] The {security-api-url}org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.html[`Saml2LogoutRequestFilter`] deserializes, verifies, and processes the `<saml2:LogoutRequest>` with its {security-api-url}org/springframework/security/saml2/provider/service/authentication/logout/Saml2LogoutRequestValidator.html[`Saml2LogoutRequestValidator`].
image:{icondir}/number_2.png[] If valid, then the filter calls the configured ``LogoutHandler``s, invalidating the session and performing other cleanup.
image:{icondir}/number_3.png[] It uses a {security-api-url}org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutResponseResolver.html[`Saml2LogoutResponseResolver`] to create, sign and serialize a `<saml2:LogoutResponse>`.
It uses the keys and configuration from the xref:servlet/saml2/login/overview.adoc#servlet-saml2login-relyingpartyregistration[`RelyingPartyRegistration`] derived from the endpoint or from the contents of the `<saml2:LogoutRequest>`.
Then, it redirect-POSTs the `<saml2:LogoutResponse>` to the asserting party SLO endpoint.
The browser hands control over to the asserting party.
image:{icondir}/number_4.png[] If invalid, then it https://github.com/spring-projects/spring-security/pull/14676[responds with a 400].
There are three behaviors that can be triggered by different endpoints:
* RP-initiated logout, which allows an authenticated user to `POST` and trigger the logout process by sending the asserting party a `<saml2:LogoutRequest>`
* AP-initiated logout, which allows an asserting party to send a `<saml2:LogoutRequest>` to the application
* AP logout response, which allows an asserting party to send a `<saml2:LogoutResponse>` in response to the RP-initiated `<saml2:LogoutRequest>`
The first is triggered by performing normal `POST /logout` when the principal is of type `Saml2AuthenticatedPrincipal`.
The second is triggered by POSTing to the `/logout/saml2/slo` endpoint with a `SAMLRequest` signed by the asserting party.
The third is triggered by POSTing to the `/logout/saml2/slo` endpoint with a `SAMLResponse` signed by the asserting party.
Because the user is already logged in or the original Logout Request is known, the `registrationId` is already known.
For this reason, `+{registrationId}+` is not part of these URLs by default.
This URL is customizable in the DSL.
For example, if you are migrating your existing relying party over to Spring Security, your asserting party may already be pointing to `GET /SLOService.saml2`.
To reduce changes in configuration for the asserting party, you can configure the filter in the DSL like so:
When your application sends a `<saml2:LogoutRequest>`, the value is stored in the session so that the `RelayState` parameter and the `InResponseTo` attribute in the `<saml2:LogoutResponse>` can be verified.
If you want to store logout requests in some place other than the session, you can supply your custom implementation in the DSL, like so: