parent
caad3d57e2
commit
f39d272a86
|
@ -63,6 +63,9 @@
|
|||
**** xref:servlet/oauth2/resource-server/multitenancy.adoc[Multitenancy]
|
||||
**** xref:servlet/oauth2/resource-server/bearer-tokens.adoc[Bearer Tokens]
|
||||
** xref:servlet/saml2/index.adoc[SAML2]
|
||||
*** xref:servlet/saml2/login.adoc[SAML2 Log In]
|
||||
*** xref:servlet/saml2/logout.adoc[SAML2 Logout]
|
||||
*** xref:servlet/saml2/metadata.adoc[SAML2 Metadata]
|
||||
** xref:servlet/exploits/index.adoc[Protection Against Exploits]
|
||||
*** xref:servlet/exploits/csrf.adoc[]
|
||||
*** xref:servlet/exploits/headers.adoc[]
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,5 @@
|
|||
|
||||
|
||||
[[servlet-saml2login]]
|
||||
== SAML 2.0 Login
|
||||
= SAML 2.0 Login
|
||||
:figures: images/servlet/saml2
|
||||
:icondir: images/icons
|
||||
|
||||
|
@ -69,21 +67,21 @@ image:{icondir}/number_4.png[] If authentication is successful, then __Success__
|
|||
* The `Saml2WebSsoAuthenticationFilter` invokes `FilterChain#doFilter(request,response)` to continue with the rest of the application logic.
|
||||
|
||||
[[servlet-saml2login-minimaldependencies]]
|
||||
=== Minimal Dependencies
|
||||
== Minimal Dependencies
|
||||
|
||||
SAML 2.0 service provider support resides in `spring-security-saml2-service-provider`.
|
||||
It builds off of the OpenSAML library.
|
||||
|
||||
[[servlet-saml2login-minimalconfiguration]]
|
||||
=== Minimal Configuration
|
||||
== Minimal Configuration
|
||||
|
||||
When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a service provider consists of two basic steps.
|
||||
First, include the needed dependencies and second, indicate the necessary asserting party metadata.
|
||||
|
||||
[NOTE]
|
||||
Also, this presupposes that you've already <<servlet-saml2login-metadata, registered the relying party with your asserting party>>.
|
||||
Also, this presupposes that you've already xref:servlet/saml2/metadata.adoc#servlet-saml2login-metadata[registered the relying party with your asserting party].
|
||||
|
||||
==== Specifying Identity Provider Metadata
|
||||
=== Specifying Identity Provider Metadata
|
||||
|
||||
In a Spring Boot application, to specify an identity provider's metadata, simply do:
|
||||
|
||||
|
@ -116,7 +114,7 @@ And that's it!
|
|||
Identity Provider and Asserting Party are synonymous, as are Service Provider and Relying Party.
|
||||
These are frequently abbreviated as AP and RP, respectively.
|
||||
|
||||
==== Runtime Expectations
|
||||
=== Runtime Expectations
|
||||
|
||||
As configured above, the application processes any `+POST /login/saml2/sso/{registrationId}+` request containing a `SAMLResponse` parameter:
|
||||
|
||||
|
@ -141,7 +139,7 @@ From here, consider jumping to:
|
|||
* <<servlet-saml2login-sansboot,How to Override or Replace Spring Boot's Auto Configuration>>
|
||||
|
||||
[[servlet-saml2login-architecture]]
|
||||
=== How SAML 2.0 Login Integrates with OpenSAML
|
||||
== How SAML 2.0 Login Integrates with OpenSAML
|
||||
|
||||
Spring Security's SAML 2.0 support has a couple of design goals:
|
||||
|
||||
|
@ -201,7 +199,7 @@ The resulting `Authentication#getPrincipal` is a Spring Security `Saml2Authentic
|
|||
`Saml2AuthenticatedPrincipal#getRelyingPartyRegistrationId` holds the <<servlet-saml2login-relyingpartyregistrationid,identifier to the associated `RelyingPartyRegistration`>>.
|
||||
|
||||
[[servlet-saml2login-opensaml-customization]]
|
||||
==== Customizing OpenSAML Configuration
|
||||
=== Customizing OpenSAML Configuration
|
||||
|
||||
Any class that uses both Spring Security and OpenSAML should statically initialize `OpenSamlInitializationService` at the beginning of the class, like so:
|
||||
|
||||
|
@ -293,7 +291,7 @@ companion object {
|
|||
The `requireInitialize` method may only be called once per application instance.
|
||||
|
||||
[[servlet-saml2login-sansboot]]
|
||||
=== Overriding or Replacing Boot Auto Configuration
|
||||
== Overriding or Replacing Boot Auto Configuration
|
||||
|
||||
There are two ``@Bean``s that Spring Boot generates for a relying party.
|
||||
|
||||
|
@ -524,7 +522,7 @@ class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() {
|
|||
A relying party can be multi-tenant by registering more than one relying party in the `RelyingPartyRegistrationRepository`.
|
||||
|
||||
[[servlet-saml2login-relyingpartyregistration]]
|
||||
=== RelyingPartyRegistration
|
||||
== RelyingPartyRegistration
|
||||
A {security-api-url}org/springframework/security/saml2/provider/service/registration/RelyingPartyRegistration.html[`RelyingPartyRegistration`]
|
||||
instance represents a link between an relying party and assering party's metadata.
|
||||
|
||||
|
@ -618,7 +616,7 @@ The default for the `assertionConsumerServiceLocation` is `+/login/saml2/sso/{re
|
|||
It's mapped by default to <<servlet-saml2login-authentication-saml2webssoauthenticationfilter,`Saml2WebSsoAuthenticationFilter`>> in the filter chain.
|
||||
|
||||
[[servlet-saml2login-rpr-uripatterns]]
|
||||
==== URI Patterns
|
||||
=== URI Patterns
|
||||
|
||||
You probably noticed in the above examples the `+{baseUrl}+` and `+{registrationId}+` placeholders.
|
||||
|
||||
|
@ -647,7 +645,7 @@ which in a deployed application would translate to
|
|||
`+https://rp.example.com/adfs+`
|
||||
|
||||
[[servlet-saml2login-rpr-credentials]]
|
||||
==== Credentials
|
||||
=== Credentials
|
||||
|
||||
You also likely noticed the credential that was used.
|
||||
|
||||
|
@ -719,7 +717,7 @@ resource.inputStream.use {
|
|||
When you specify the locations of these files as the appropriate Spring Boot properties, then Spring Boot will perform these conversions for you.
|
||||
|
||||
[[servlet-saml2login-rpr-relyingpartyregistrationresolver]]
|
||||
==== Resolving the Relying Party from the Request
|
||||
=== Resolving the Relying Party from the Request
|
||||
|
||||
As seen so far, Spring Security resolves the `RelyingPartyRegistration` by looking for the registration id in the URI path.
|
||||
|
||||
|
@ -763,13 +761,13 @@ class SingleRelyingPartyRegistrationResolver(delegate: RelyingPartyRegistrationR
|
|||
----
|
||||
====
|
||||
|
||||
Then, you can provide this resolver to the appropriate filters that <<servlet-saml2login-sp-initiated-factory, produce ``<saml2:AuthnRequest>``s>>, <<servlet-saml2login-authenticate-responses, authenticate ``<saml2:Response>``s>>, and <<servlet-saml2login-metadata, produce `<saml2:SPSSODescriptor>` metadata>>.
|
||||
Then, you can provide this resolver to the appropriate filters that <<servlet-saml2login-sp-initiated-factory, produce ``<saml2:AuthnRequest>``s>>, <<servlet-saml2login-authenticate-responses, authenticate ``<saml2:Response>``s>>, and xref:servlet/saml2/metadata.adoc#servlet-saml2login-metadata[produce `<saml2:SPSSODescriptor>` metadata].
|
||||
|
||||
[NOTE]
|
||||
Remember that if you have any placeholders in your `RelyingPartyRegistration`, your resolver implementation should resolve them.
|
||||
|
||||
[[servlet-saml2login-rpr-duplicated]]
|
||||
==== Duplicated Relying Party Configurations
|
||||
=== Duplicated Relying Party Configurations
|
||||
|
||||
When an application uses multiple asserting parties, some configuration is duplicated between `RelyingPartyRegistration` instances:
|
||||
|
||||
|
@ -864,7 +862,7 @@ open fun relyingPartyRegistrations(): RelyingPartyRegistrationRepository? {
|
|||
====
|
||||
|
||||
[[servlet-saml2login-sp-initiated-factory]]
|
||||
=== Producing ``<saml2:AuthnRequest>``s
|
||||
== Producing ``<saml2:AuthnRequest>``s
|
||||
|
||||
As stated earlier, Spring Security's SAML 2.0 support produces a `<saml2:AuthnRequest>` to commence authentication with the asserting party.
|
||||
|
||||
|
@ -878,7 +876,7 @@ For example, if you were deployed to `https://rp.example.com` and you gave your
|
|||
and the result would be a redirect that included a `SAMLRequest` parameter containing the signed, deflated, and encoded `<saml2:AuthnRequest>`.
|
||||
|
||||
[[servlet-saml2login-store-authn-request]]
|
||||
==== Changing How the `<saml2:AuthnRequest>` Gets Stored
|
||||
=== Changing How the `<saml2:AuthnRequest>` Gets Stored
|
||||
|
||||
`Saml2WebSsoAuthenticationRequestFilter` uses an `Saml2AuthenticationRequestRepository` to persist an `AbstractSaml2AuthenticationRequest` instance before <<servlet-saml2login-sp-initiated-factory,sending the `<saml2:AuthnRequest>`>> to the asserting party.
|
||||
|
||||
|
@ -909,7 +907,7 @@ open fun authenticationRequestRepository(): Saml2AuthenticationRequestRepository
|
|||
====
|
||||
|
||||
[[servlet-saml2login-sp-initiated-factory-signing]]
|
||||
==== Changing How the `<saml2:AuthnRequest>` Gets Sent
|
||||
=== Changing How the `<saml2:AuthnRequest>` Gets Sent
|
||||
|
||||
By default, Spring Security signs each `<saml2:AuthnRequest>` and send it as a GET to the asserting party.
|
||||
|
||||
|
@ -1036,7 +1034,7 @@ var relyingPartyRegistration: RelyingPartyRegistration? =
|
|||
====
|
||||
|
||||
[[servlet-saml2login-sp-initiated-factory-custom-authnrequest]]
|
||||
==== Customizing OpenSAML's `AuthnRequest` Instance
|
||||
=== Customizing OpenSAML's `AuthnRequest` Instance
|
||||
|
||||
There are a number of reasons that you may want to adjust an `AuthnRequest`.
|
||||
For example, you may want `ForceAuthN` to be set to `true`, which Spring Security sets to `false` by default.
|
||||
|
@ -1157,7 +1155,7 @@ open fun authenticationRequestFactory(
|
|||
====
|
||||
|
||||
[[servlet-saml2login-authenticate-responses]]
|
||||
=== Authenticating ``<saml2:Response>``s
|
||||
== Authenticating ``<saml2:Response>``s
|
||||
|
||||
To verify SAML 2.0 Responses, Spring Security uses <<servlet-saml2login-architecture,`OpenSaml4AuthenticationProvider`>> by default.
|
||||
|
||||
|
@ -1171,7 +1169,7 @@ You can configure this in a number of ways including:
|
|||
To configure these, you'll use the `saml2Login#authenticationManager` method in the DSL.
|
||||
|
||||
[[servlet-saml2login-opensamlauthenticationprovider-clockskew]]
|
||||
==== Setting a Clock Skew
|
||||
=== Setting a Clock Skew
|
||||
|
||||
It's not uncommon for the asserting and relying parties to have system clocks that aren't perfectly synchronized.
|
||||
For that reason, you can configure `OpenSaml4AuthenticationProvider` 's default assertion validator with some tolerance:
|
||||
|
@ -1236,7 +1234,7 @@ open class SecurityConfig : WebSecurityConfigurerAdapter() {
|
|||
====
|
||||
|
||||
[[servlet-saml2login-opensamlauthenticationprovider-userdetailsservice]]
|
||||
==== Coordinating with a `UserDetailsService`
|
||||
=== Coordinating with a `UserDetailsService`
|
||||
|
||||
Or, perhaps you would like to include user details from a legacy `UserDetailsService`.
|
||||
In that case, the response authentication converter can come in handy, as can be seen below:
|
||||
|
@ -1314,7 +1312,7 @@ It's not required to call `OpenSaml4AuthenticationProvider` 's default authentic
|
|||
It returns a `Saml2AuthenticatedPrincipal` containing the attributes it extracted from ``AttributeStatement``s as well as the single `ROLE_USER` authority.
|
||||
|
||||
[[servlet-saml2login-opensamlauthenticationprovider-additionalvalidation]]
|
||||
==== Performing Additional Response Validation
|
||||
=== Performing Additional Response Validation
|
||||
|
||||
`OpenSaml4AuthenticationProvider` validates the `Issuer` and `Destination` values right after decrypting the `Response`.
|
||||
You can customize the validation by extending the default validator concatenating with your own response validator, or you can replace it entirely with yours.
|
||||
|
@ -1336,7 +1334,7 @@ provider.setResponseValidator((responseToken) -> {
|
|||
});
|
||||
----
|
||||
|
||||
==== Performing Additional Assertion Validation
|
||||
=== Performing Additional Assertion Validation
|
||||
`OpenSaml4AuthenticationProvider` performs minimal validation on SAML 2.0 Assertions.
|
||||
After verifying the signature, it will:
|
||||
|
||||
|
@ -1362,7 +1360,7 @@ provider.setAssertionValidator(assertionToken -> {
|
|||
OneTimeUse oneTimeUse = assertion.getConditions().getOneTimeUse();
|
||||
ValidationContext context = new ValidationContext();
|
||||
try {
|
||||
if (validator.validate(oneTimeUse, assertion, context) == ValidationResult.VALID) {
|
||||
if (validator.validate(oneTimeUse, assertion, context) = ValidationResult.VALID) {
|
||||
return result;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -1385,7 +1383,7 @@ provider.setAssertionValidator { assertionToken ->
|
|||
val oneTimeUse: OneTimeUse = assertion.conditions.oneTimeUse
|
||||
val context = ValidationContext()
|
||||
try {
|
||||
if (validator.validate(oneTimeUse, assertion, context) == ValidationResult.VALID) {
|
||||
if (validator.validate(oneTimeUse, assertion, context) = ValidationResult.VALID) {
|
||||
return@setAssertionValidator result
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
@ -1401,7 +1399,7 @@ While recommended, it's not necessary to call `OpenSaml4AuthenticationProvider`
|
|||
A circumstance where you would skip it would be if you don't need it to check the `<AudienceRestriction>` or the `<SubjectConfirmation>` since you are doing those yourself.
|
||||
|
||||
[[servlet-saml2login-opensamlauthenticationprovider-decryption]]
|
||||
==== Customizing Decryption
|
||||
=== Customizing Decryption
|
||||
|
||||
Spring Security decrypts `<saml2:EncryptedAssertion>`, `<saml2:EncryptedAttribute>`, and `<saml2:EncryptedID>` elements automatically by using the decryption <<servlet-saml2login-rpr-credentials,`Saml2X509Credential` instances>> registered in the <<servlet-saml2login-relyingpartyregistration,`RelyingPartyRegistration`>>.
|
||||
|
||||
|
@ -1451,7 +1449,7 @@ Trying to decrypt a signed assertion's elements before signature verification ma
|
|||
If your asserting party signs the response only, then it's safe to decrypt all elements using only the response decrypter.
|
||||
|
||||
[[servlet-saml2login-authenticationmanager-custom]]
|
||||
==== Using a Custom Authentication Manager
|
||||
=== Using a Custom Authentication Manager
|
||||
|
||||
[[servlet-saml2login-opensamlauthenticationprovider-authenticationmanager]]
|
||||
Of course, the `authenticationManager` DSL method can be also used to perform a completely custom SAML 2.0 authentication.
|
||||
|
@ -1500,7 +1498,7 @@ open class SecurityConfig : WebSecurityConfigurerAdapter() {
|
|||
====
|
||||
|
||||
[[servlet-saml2login-authenticatedprincipal]]
|
||||
=== Using `Saml2AuthenticatedPrincipal`
|
||||
== Using `Saml2AuthenticatedPrincipal`
|
||||
|
||||
With the relying party correctly configured for a given asserting party, it's ready to accept assertions.
|
||||
Once the relying party validates an assertion, the result is a `Saml2Authentication` with a `Saml2AuthenticatedPrincipal`.
|
||||
|
@ -1540,356 +1538,3 @@ class MainController {
|
|||
[TIP]
|
||||
Because the SAML 2.0 specification allows for each attribute to have multiple values, you can either call `getAttribute` to get the list of attributes or `getFirstAttribute` to get the first in the list.
|
||||
`getFirstAttribute` is quite handy when you know that there is only one value.
|
||||
|
||||
[[servlet-saml2login-metadata]]
|
||||
=== Producing `<saml2:SPSSODescriptor>` Metadata
|
||||
|
||||
You can publish a metadata endpoint by adding the `Saml2MetadataFilter` to the filter chain, as you'll see below:
|
||||
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
DefaultRelyingPartyRegistrationResolver relyingPartyRegistrationResolver =
|
||||
new DefaultRelyingPartyRegistrationResolver(this.relyingPartyRegistrationRepository);
|
||||
Saml2MetadataFilter filter = new Saml2MetadataFilter(
|
||||
relyingPartyRegistrationResolver,
|
||||
new OpenSamlMetadataResolver());
|
||||
|
||||
http
|
||||
// ...
|
||||
.saml2Login(withDefaults())
|
||||
.addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class);
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
val relyingPartyRegistrationResolver: Converter<HttpServletRequest, RelyingPartyRegistration> =
|
||||
DefaultRelyingPartyRegistrationResolver(this.relyingPartyRegistrationRepository)
|
||||
val filter = Saml2MetadataFilter(
|
||||
relyingPartyRegistrationResolver,
|
||||
OpenSamlMetadataResolver()
|
||||
)
|
||||
|
||||
http {
|
||||
//...
|
||||
saml2Login { }
|
||||
addFilterBefore<Saml2WebSsoAuthenticationFilter>(filter)
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
You can use this metadata endpoint to register your relying party with your asserting party.
|
||||
This is often as simple as finding the correct form field to supply the metadata endpoint.
|
||||
|
||||
By default, the metadata endpoint is `+/saml2/service-provider-metadata/{registrationId}+`.
|
||||
You can change this by calling the `setRequestMatcher` method on the filter:
|
||||
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
filter.setRequestMatcher(new AntPathRequestMatcher("/saml2/metadata/{registrationId}", "GET"));
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
filter.setRequestMatcher(AntPathRequestMatcher("/saml2/metadata/{registrationId}", "GET"))
|
||||
----
|
||||
====
|
||||
|
||||
Or, if you have registered a custom relying party registration resolver in the constructor, then you can specify a path without a `registrationId` hint, like so:
|
||||
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
filter.setRequestMatcher(new AntPathRequestMatcher("/saml2/metadata", "GET"));
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
filter.setRequestMatcher(AntPathRequestMatcher("/saml2/metadata", "GET"))
|
||||
----
|
||||
====
|
||||
|
||||
[[servlet-saml2login-logout]]
|
||||
=== Performing Single Logout
|
||||
|
||||
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
|
||||
|
||||
You can begin from the initial minimal example and add the following configuration:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Value("${private.key}") RSAPrivateKey key;
|
||||
@Value("${public.certificate}") X509Certificate certificate;
|
||||
|
||||
@Bean
|
||||
RelyingPartyRegistrationRepository registrations() {
|
||||
Saml2X509Credential credential = Saml2X509Credential.signing(key, certificate);
|
||||
RelyingPartyRegistration registration = RelyingPartyRegistrations
|
||||
.fromMetadataLocation("https://ap.example.org/metadata")
|
||||
.registrationId("id")
|
||||
.signingX509Credentials((signing) -> signing.add(credential)) <1>
|
||||
.build();
|
||||
return new InMemoryRelyingPartyRegistrationRepository(registration);
|
||||
}
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain web(HttpSecurity http, RelyingPartyRegistrationRepository registrations) throws Exception {
|
||||
http
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.saml2Login(withDefaults())
|
||||
.saml2Logout(withDefaults()); <2>
|
||||
|
||||
return http.build();
|
||||
}
|
||||
----
|
||||
<1> - First, add your signing key to the `RelyingPartyRegistration` instance or to <<servlet-saml2login-rpr-duplicated,multiple instances>>
|
||||
<2> - Second, indicate that your application wants to use SAML SLO to logout the end user
|
||||
|
||||
==== Runtime Expectations
|
||||
|
||||
Given the above configuration any logged in user can send a `POST /logout` to your application to perform RP-initiated SLO.
|
||||
Your application will then do the following:
|
||||
|
||||
1. Logout the user and invalidate the session
|
||||
2. Use a `Saml2LogoutRequestResolver` to create, sign, and serialize a `<saml2:LogoutRequest>` based on the <<servlet-saml2login-relyingpartyregistration,`RelyingPartyRegistration`>> associated with the currently logged-in user.
|
||||
3. Send a redirect or post to the asserting party based on the <<servlet-saml2login-relyingpartyregistration,`RelyingPartyRegistration`>>
|
||||
4. Deserialize, verify, and process the `<saml2:LogoutResponse>` sent by the asserting party
|
||||
5. Redirect to any configured successful logout endpoint
|
||||
|
||||
Also, your application can participate in an AP-initiated logout when the asserting party sends a `<saml2:LogoutRequest>` to `/logout/saml2/slo`:
|
||||
|
||||
1. Use a `Saml2LogoutRequestHandler` to deserialize, verify, and process the `<saml2:LogoutRequest>` sent by the asserting party
|
||||
2. Logout the user and invalidate the session
|
||||
3. Create, sign, and serialize a `<saml2:LogoutResponse>` based on the <<servlet-saml2login-relyingpartyregistration,`RelyingPartyRegistration`>> associated with the just logged-out user
|
||||
4. Send a redirect or post to the asserting party based on the <<servlet-saml2login-relyingpartyregistration,`RelyingPartyRegistration`>>
|
||||
|
||||
=== Configuring Logout Endpoints
|
||||
|
||||
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:
|
||||
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
http
|
||||
.saml2Logout((saml2) -> saml2
|
||||
.logoutRequest((request) -> request.logoutUrl("/SLOService.saml2"))
|
||||
.logoutResponse((response) -> response.logoutUrl("/SLOService.saml2"))
|
||||
);
|
||||
----
|
||||
====
|
||||
|
||||
You should also configure these endpoints in your `RelyingPartyRegistration`.
|
||||
|
||||
=== Customizing `<saml2:LogoutRequest>` Resolution
|
||||
|
||||
It's common to need to set other values in the `<saml2:LogoutRequest>` than the defaults that Spring Security provides.
|
||||
|
||||
By default, Spring Security will issue a `<saml2:LogoutRequest>` and supply:
|
||||
|
||||
* The `Destination` attribute - from `RelyingPartyRegistration#getAssertingPartyDetails#getSingleLogoutServiceLocation`
|
||||
* The `ID` attribute - a GUID
|
||||
* The `<Issuer>` element - from `RelyingPartyRegistration#getEntityId`
|
||||
* The `<NameID>` element - from `Authentication#getName`
|
||||
|
||||
To add other values, you can use delegation, like so:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
Saml2LogoutRequestResolver logoutRequestResolver(RelyingPartyRegistrationResolver registrationResolver) {
|
||||
OpenSaml4LogoutRequestResolver logoutRequestResolver
|
||||
new OpenSaml4LogoutRequestResolver(registrationResolver);
|
||||
logoutRequestResolver.setParametersConsumer((parameters) -> {
|
||||
String name = ((Saml2AuthenticatedPrincipal) parameters.getAuthentication().getPrincipal()).getFirstAttribute("CustomAttribute");
|
||||
String format = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient";
|
||||
LogoutRequest logoutRequest = parameters.getLogoutRequest();
|
||||
NameID nameId = logoutRequest.getNameID();
|
||||
nameId.setValue(name);
|
||||
nameId.setFormat(format);
|
||||
});
|
||||
return logoutRequestResolver;
|
||||
}
|
||||
----
|
||||
|
||||
Then, you can supply your custom `Saml2LogoutRequestResolver` in the DSL as follows:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
http
|
||||
.saml2Logout((saml2) -> saml2
|
||||
.logoutRequest((request) -> request
|
||||
.logoutRequestResolver(this.logoutRequestResolver)
|
||||
)
|
||||
);
|
||||
----
|
||||
|
||||
=== Customizing `<saml2:LogoutResponse>` Resolution
|
||||
|
||||
It's common to need to set other values in the `<saml2:LogoutResponse>` than the defaults that Spring Security provides.
|
||||
|
||||
By default, Spring Security will issue a `<saml2:LogoutResponse>` and supply:
|
||||
|
||||
* The `Destination` attribute - from `RelyingPartyRegistration#getAssertingPartyDetails#getSingleLogoutServiceResponseLocation`
|
||||
* The `ID` attribute - a GUID
|
||||
* The `<Issuer>` element - from `RelyingPartyRegistration#getEntityId`
|
||||
* The `<Status>` element - `SUCCESS`
|
||||
|
||||
To add other values, you can use delegation, like so:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
public Saml2LogoutResponseResolver logoutResponseResolver(RelyingPartyRegistrationResolver registrationResolver) {
|
||||
OpenSaml4LogoutResponseResolver logoutRequestResolver =
|
||||
new OpenSaml3LogoutResponseResolver(relyingPartyRegistrationResolver);
|
||||
logoutRequestResolver.setParametersConsumer((parameters) -> {
|
||||
if (checkOtherPrevailingConditions(parameters.getRequest())) {
|
||||
parameters.getLogoutRequest().getStatus().getStatusCode().setCode(StatusCode.PARTIAL_LOGOUT);
|
||||
}
|
||||
});
|
||||
return logoutRequestResolver;
|
||||
}
|
||||
----
|
||||
|
||||
Then, you can supply your custom `Saml2LogoutResponseResolver` in the DSL as follows:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
http
|
||||
.saml2Logout((saml2) -> saml2
|
||||
.logoutRequest((request) -> request
|
||||
.logoutRequestResolver(this.logoutRequestResolver)
|
||||
)
|
||||
);
|
||||
----
|
||||
|
||||
=== Customizing `<saml2:LogoutRequest>` Authentication
|
||||
|
||||
To customize validation, you can implement your own `Saml2LogoutRequestValidator`.
|
||||
At this point, the validation is minimal, so you may be able to first delegate to the default `Saml2LogoutRequestValidator` like so:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Component
|
||||
public class MyOpenSamlLogoutRequestValidator implements Saml2LogoutRequestValidator {
|
||||
private final Saml2LogoutRequestValidator delegate = new OpenSamlLogoutRequestValidator();
|
||||
|
||||
@Override
|
||||
public Saml2LogoutRequestValidator logout(Saml2LogoutRequestValidatorParameters parameters) {
|
||||
// verify signature, issuer, destination, and principal name
|
||||
Saml2LogoutValidatorResult result = delegate.authenticate(authentication);
|
||||
|
||||
LogoutRequest logoutRequest = // ... parse using OpenSAML
|
||||
// perform custom validation
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Then, you can supply your custom `Saml2LogoutRequestValidator` in the DSL as follows:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
http
|
||||
.saml2Logout((saml2) -> saml2
|
||||
.logoutRequest((request) -> request
|
||||
.logoutRequestAuthenticator(myOpenSamlLogoutRequestAuthenticator)
|
||||
)
|
||||
);
|
||||
----
|
||||
|
||||
=== Customizing `<saml2:LogoutResponse>` Authentication
|
||||
|
||||
To customize validation, you can implement your own `Saml2LogoutResponseValidator`.
|
||||
At this point, the validation is minimal, so you may be able to first delegate to the default `Saml2LogoutResponseValidator` like so:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Component
|
||||
public class MyOpenSamlLogoutResponseValidator implements Saml2LogoutResponseValidator {
|
||||
private final Saml2LogoutResponseValidator delegate = new OpenSamlLogoutResponseValidator();
|
||||
|
||||
@Override
|
||||
public Saml2LogoutValidatorResult logout(Saml2LogoutResponseValidatorParameters parameters) {
|
||||
// verify signature, issuer, destination, and status
|
||||
Saml2LogoutValidatorResult result = delegate.authenticate(parameters);
|
||||
|
||||
LogoutResponse logoutResponse = // ... parse using OpenSAML
|
||||
// perform custom validation
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Then, you can supply your custom `Saml2LogoutResponseValidator` in the DSL as follows:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
http
|
||||
.saml2Logout((saml2) -> saml2
|
||||
.logoutResponse((response) -> response
|
||||
.logoutResponseAuthenticator(myOpenSamlLogoutResponseAuthenticator)
|
||||
)
|
||||
);
|
||||
----
|
||||
|
||||
=== Customizing `<saml2:LogoutRequest>` storage
|
||||
|
||||
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:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
http
|
||||
.saml2Logout((saml2) -> saml2
|
||||
.logoutRequest((request) -> request
|
||||
.logoutRequestRepository(myCustomLogoutRequestRepository)
|
||||
)
|
||||
);
|
||||
----
|
|
@ -0,0 +1,277 @@
|
|||
[[servlet-saml2login-logout]]
|
||||
= Performing Single Logout
|
||||
|
||||
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
|
||||
|
||||
You can begin from the initial minimal example and add the following configuration:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Value("${private.key}") RSAPrivateKey key;
|
||||
@Value("${public.certificate}") X509Certificate certificate;
|
||||
|
||||
@Bean
|
||||
RelyingPartyRegistrationRepository registrations() {
|
||||
Saml2X509Credential credential = Saml2X509Credential.signing(key, certificate);
|
||||
RelyingPartyRegistration registration = RelyingPartyRegistrations
|
||||
.fromMetadataLocation("https://ap.example.org/metadata")
|
||||
.registrationId("id")
|
||||
.signingX509Credentials((signing) -> signing.add(credential)) <1>
|
||||
.build();
|
||||
return new InMemoryRelyingPartyRegistrationRepository(registration);
|
||||
}
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain web(HttpSecurity http, RelyingPartyRegistrationRepository registrations) throws Exception {
|
||||
http
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.saml2Login(withDefaults())
|
||||
.saml2Logout(withDefaults()); <2>
|
||||
|
||||
return http.build();
|
||||
}
|
||||
----
|
||||
<1> - First, add your signing key to the `RelyingPartyRegistration` instance or to xref:servlet/saml2/login.adoc#servlet-saml2login-rpr-duplicated[multiple instances]
|
||||
<2> - Second, indicate that your application wants to use SAML SLO to logout the end user
|
||||
|
||||
=== Runtime Expectations
|
||||
|
||||
Given the above configuration any logged in user can send a `POST /logout` to your application to perform RP-initiated SLO.
|
||||
Your application will then do the following:
|
||||
|
||||
1. Logout the user and invalidate the session
|
||||
2. Use a `Saml2LogoutRequestResolver` to create, sign, and serialize a `<saml2:LogoutRequest>` based on the xref:servlet/saml2/login.adoc#servlet-saml2login-relyingpartyregistration[`RelyingPartyRegistration`] associated with the currently logged-in user.
|
||||
3. Send a redirect or post to the asserting party based on the xref:servlet/saml2/login.adoc#servlet-saml2login-relyingpartyregistration[`RelyingPartyRegistration`]
|
||||
4. Deserialize, verify, and process the `<saml2:LogoutResponse>` sent by the asserting party
|
||||
5. Redirect to any configured successful logout endpoint
|
||||
|
||||
Also, your application can participate in an AP-initiated logout when the asserting party sends a `<saml2:LogoutRequest>` to `/logout/saml2/slo`:
|
||||
|
||||
1. Use a `Saml2LogoutRequestHandler` to deserialize, verify, and process the `<saml2:LogoutRequest>` sent by the asserting party
|
||||
2. Logout the user and invalidate the session
|
||||
3. Create, sign, and serialize a `<saml2:LogoutResponse>` based on the xref:servlet/saml2/login.adoc#servlet-saml2login-relyingpartyregistration[`RelyingPartyRegistration`] associated with the just logged-out user
|
||||
4. Send a redirect or post to the asserting party based on the xref:servlet/saml2/login.adoc#servlet-saml2login-relyingpartyregistration[`RelyingPartyRegistration`]
|
||||
|
||||
== Configuring Logout Endpoints
|
||||
|
||||
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:
|
||||
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
http
|
||||
.saml2Logout((saml2) -> saml2
|
||||
.logoutRequest((request) -> request.logoutUrl("/SLOService.saml2"))
|
||||
.logoutResponse((response) -> response.logoutUrl("/SLOService.saml2"))
|
||||
);
|
||||
----
|
||||
====
|
||||
|
||||
You should also configure these endpoints in your `RelyingPartyRegistration`.
|
||||
|
||||
== Customizing `<saml2:LogoutRequest>` Resolution
|
||||
|
||||
It's common to need to set other values in the `<saml2:LogoutRequest>` than the defaults that Spring Security provides.
|
||||
|
||||
By default, Spring Security will issue a `<saml2:LogoutRequest>` and supply:
|
||||
|
||||
* The `Destination` attribute - from `RelyingPartyRegistration#getAssertingPartyDetails#getSingleLogoutServiceLocation`
|
||||
* The `ID` attribute - a GUID
|
||||
* The `<Issuer>` element - from `RelyingPartyRegistration#getEntityId`
|
||||
* The `<NameID>` element - from `Authentication#getName`
|
||||
|
||||
To add other values, you can use delegation, like so:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
Saml2LogoutRequestResolver logoutRequestResolver(RelyingPartyRegistrationResolver registrationResolver) {
|
||||
OpenSaml4LogoutRequestResolver logoutRequestResolver
|
||||
new OpenSaml4LogoutRequestResolver(registrationResolver);
|
||||
logoutRequestResolver.setParametersConsumer((parameters) -> {
|
||||
String name = ((Saml2AuthenticatedPrincipal) parameters.getAuthentication().getPrincipal()).getFirstAttribute("CustomAttribute");
|
||||
String format = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient";
|
||||
LogoutRequest logoutRequest = parameters.getLogoutRequest();
|
||||
NameID nameId = logoutRequest.getNameID();
|
||||
nameId.setValue(name);
|
||||
nameId.setFormat(format);
|
||||
});
|
||||
return logoutRequestResolver;
|
||||
}
|
||||
----
|
||||
|
||||
Then, you can supply your custom `Saml2LogoutRequestResolver` in the DSL as follows:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
http
|
||||
.saml2Logout((saml2) -> saml2
|
||||
.logoutRequest((request) -> request
|
||||
.logoutRequestResolver(this.logoutRequestResolver)
|
||||
)
|
||||
);
|
||||
----
|
||||
|
||||
== Customizing `<saml2:LogoutResponse>` Resolution
|
||||
|
||||
It's common to need to set other values in the `<saml2:LogoutResponse>` than the defaults that Spring Security provides.
|
||||
|
||||
By default, Spring Security will issue a `<saml2:LogoutResponse>` and supply:
|
||||
|
||||
* The `Destination` attribute - from `RelyingPartyRegistration#getAssertingPartyDetails#getSingleLogoutServiceResponseLocation`
|
||||
* The `ID` attribute - a GUID
|
||||
* The `<Issuer>` element - from `RelyingPartyRegistration#getEntityId`
|
||||
* The `<Status>` element - `SUCCESS`
|
||||
|
||||
To add other values, you can use delegation, like so:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
public Saml2LogoutResponseResolver logoutResponseResolver(RelyingPartyRegistrationResolver registrationResolver) {
|
||||
OpenSaml4LogoutResponseResolver logoutRequestResolver =
|
||||
new OpenSaml3LogoutResponseResolver(relyingPartyRegistrationResolver);
|
||||
logoutRequestResolver.setParametersConsumer((parameters) -> {
|
||||
if (checkOtherPrevailingConditions(parameters.getRequest())) {
|
||||
parameters.getLogoutRequest().getStatus().getStatusCode().setCode(StatusCode.PARTIAL_LOGOUT);
|
||||
}
|
||||
});
|
||||
return logoutRequestResolver;
|
||||
}
|
||||
----
|
||||
|
||||
Then, you can supply your custom `Saml2LogoutResponseResolver` in the DSL as follows:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
http
|
||||
.saml2Logout((saml2) -> saml2
|
||||
.logoutRequest((request) -> request
|
||||
.logoutRequestResolver(this.logoutRequestResolver)
|
||||
)
|
||||
);
|
||||
----
|
||||
|
||||
== Customizing `<saml2:LogoutRequest>` Authentication
|
||||
|
||||
To customize validation, you can implement your own `Saml2LogoutRequestValidator`.
|
||||
At this point, the validation is minimal, so you may be able to first delegate to the default `Saml2LogoutRequestValidator` like so:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Component
|
||||
public class MyOpenSamlLogoutRequestValidator implements Saml2LogoutRequestValidator {
|
||||
private final Saml2LogoutRequestValidator delegate = new OpenSamlLogoutRequestValidator();
|
||||
|
||||
@Override
|
||||
public Saml2LogoutRequestValidator logout(Saml2LogoutRequestValidatorParameters parameters) {
|
||||
// verify signature, issuer, destination, and principal name
|
||||
Saml2LogoutValidatorResult result = delegate.authenticate(authentication);
|
||||
|
||||
LogoutRequest logoutRequest = // ... parse using OpenSAML
|
||||
// perform custom validation
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Then, you can supply your custom `Saml2LogoutRequestValidator` in the DSL as follows:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
http
|
||||
.saml2Logout((saml2) -> saml2
|
||||
.logoutRequest((request) -> request
|
||||
.logoutRequestAuthenticator(myOpenSamlLogoutRequestAuthenticator)
|
||||
)
|
||||
);
|
||||
----
|
||||
|
||||
== Customizing `<saml2:LogoutResponse>` Authentication
|
||||
|
||||
To customize validation, you can implement your own `Saml2LogoutResponseValidator`.
|
||||
At this point, the validation is minimal, so you may be able to first delegate to the default `Saml2LogoutResponseValidator` like so:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Component
|
||||
public class MyOpenSamlLogoutResponseValidator implements Saml2LogoutResponseValidator {
|
||||
private final Saml2LogoutResponseValidator delegate = new OpenSamlLogoutResponseValidator();
|
||||
|
||||
@Override
|
||||
public Saml2LogoutValidatorResult logout(Saml2LogoutResponseValidatorParameters parameters) {
|
||||
// verify signature, issuer, destination, and status
|
||||
Saml2LogoutValidatorResult result = delegate.authenticate(parameters);
|
||||
|
||||
LogoutResponse logoutResponse = // ... parse using OpenSAML
|
||||
// perform custom validation
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Then, you can supply your custom `Saml2LogoutResponseValidator` in the DSL as follows:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
http
|
||||
.saml2Logout((saml2) -> saml2
|
||||
.logoutResponse((response) -> response
|
||||
.logoutResponseAuthenticator(myOpenSamlLogoutResponseAuthenticator)
|
||||
)
|
||||
);
|
||||
----
|
||||
|
||||
== Customizing `<saml2:LogoutRequest>` storage
|
||||
|
||||
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:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
http
|
||||
.saml2Logout((saml2) -> saml2
|
||||
.logoutRequest((request) -> request
|
||||
.logoutRequestRepository(myCustomLogoutRequestRepository)
|
||||
)
|
||||
);
|
||||
----
|
|
@ -0,0 +1,74 @@
|
|||
[[servlet-saml2login-metadata]]
|
||||
= Producing `<saml2:SPSSODescriptor>` Metadata
|
||||
|
||||
You can publish a metadata endpoint by adding the `Saml2MetadataFilter` to the filter chain, as you'll see below:
|
||||
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
DefaultRelyingPartyRegistrationResolver relyingPartyRegistrationResolver =
|
||||
new DefaultRelyingPartyRegistrationResolver(this.relyingPartyRegistrationRepository);
|
||||
Saml2MetadataFilter filter = new Saml2MetadataFilter(
|
||||
relyingPartyRegistrationResolver,
|
||||
new OpenSamlMetadataResolver());
|
||||
|
||||
http
|
||||
// ...
|
||||
.saml2Login(withDefaults())
|
||||
.addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class);
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
val relyingPartyRegistrationResolver: Converter<HttpServletRequest, RelyingPartyRegistration> =
|
||||
DefaultRelyingPartyRegistrationResolver(this.relyingPartyRegistrationRepository)
|
||||
val filter = Saml2MetadataFilter(
|
||||
relyingPartyRegistrationResolver,
|
||||
OpenSamlMetadataResolver()
|
||||
)
|
||||
|
||||
http {
|
||||
//...
|
||||
saml2Login { }
|
||||
addFilterBefore<Saml2WebSsoAuthenticationFilter>(filter)
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
You can use this metadata endpoint to register your relying party with your asserting party.
|
||||
This is often as simple as finding the correct form field to supply the metadata endpoint.
|
||||
|
||||
By default, the metadata endpoint is `+/saml2/service-provider-metadata/{registrationId}+`.
|
||||
You can change this by calling the `setRequestMatcher` method on the filter:
|
||||
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
filter.setRequestMatcher(new AntPathRequestMatcher("/saml2/metadata/{registrationId}", "GET"));
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
filter.setRequestMatcher(AntPathRequestMatcher("/saml2/metadata/{registrationId}", "GET"))
|
||||
----
|
||||
====
|
||||
|
||||
Or, if you have registered a custom relying party registration resolver in the constructor, then you can specify a path without a `registrationId` hint, like so:
|
||||
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
filter.setRequestMatcher(new AntPathRequestMatcher("/saml2/metadata", "GET"));
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
filter.setRequestMatcher(AntPathRequestMatcher("/saml2/metadata", "GET"))
|
||||
----
|
||||
====
|
Loading…
Reference in New Issue