You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc
+85-5Lines changed: 85 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,17 +1,97 @@
1
1
[[servlet-saml2login-authenticate-responses]]
2
2
= Authenticating ``<saml2:Response>``s
3
3
4
-
To verify SAML 2.0 Responses, Spring Security uses xref:servlet/saml2/login/overview.adoc#servlet-saml2login-architecture[`OpenSaml4AuthenticationProvider`] by default.
4
+
To verify SAML 2.0 Responses, Spring Security uses xref:servlet/saml2/login/overview.adoc#servlet-saml2login-authentication-saml2authenticationtokenconverter[`Saml2AuthenticationTokenConverter`] to populate the `Authentication` request and xref:servlet/saml2/login/overview.adoc#servlet-saml2login-architecture[`OpenSaml4AuthenticationProvider`] to authenticate it.
5
5
6
6
You can configure this in a number of ways including:
7
7
8
-
1. Setting a clock skew to timestamp validation
9
-
2. Mapping the response to a list of `GrantedAuthority` instances
10
-
3. Customizing the strategy for validating assertions
11
-
4. Customizing the strategy for decrypting response and assertion elements
8
+
1. Changing the way the `RelyingPartyRegistration` is Looked Up
9
+
2. Setting a clock skew to timestamp validation
10
+
3. Mapping the response to a list of `GrantedAuthority` instances
11
+
4. Customizing the strategy for validating assertions
12
+
5. Customizing the strategy for decrypting response and assertion elements
12
13
13
14
To configure these, you'll use the `saml2Login#authenticationManager` method in the DSL.
14
15
16
+
[[relyingpartyregistrationresolver-apply]]
17
+
== Changing `RelyingPartyRegistration` Lookup
18
+
19
+
`RelyingPartyRegistration` lookup is customized xref:servlet/saml2/login/overview.adoc#servlet-saml2login-rpr-relyingpartyregistrationresolver[in a `RelyingPartyRegistrationResolver`].
20
+
21
+
To apply a `RelyingPartyRegistrationResolver` when processing `<saml2:Response>` payloads, you should first publish a `Saml2AuthenticationTokenConverter` bean like so:
image:{icondir}/number_1.png[] When the browser submits a `<saml2:Response>` to the application, it xref:servlet/saml2/login/authentication.adoc#servlet-saml2login-authenticate-responses[delegates to `Saml2WebSsoAuthenticationFilter`].
37
38
This filter calls its configured `AuthenticationConverter` to create a `Saml2AuthenticationToken` by extracting the response from the `HttpServletRequest`.
38
39
This converter additionally resolves the <<servlet-saml2login-relyingpartyregistration, `RelyingPartyRegistration`>> and supplies it to `Saml2AuthenticationToken`.
@@ -640,6 +641,16 @@ which in a deployed application would translate to
640
641
641
642
`+https://rp.example.com/adfs+`
642
643
644
+
The prevailing URI patterns are as follows:
645
+
646
+
* `+/saml2/authenticate/{registrationId}+` - The endpoint that xref:servlet/saml2/login/authentication-requests.adoc[generates a `<saml2:AuthnRequest>`] based on the configurations for that `RelyingPartyRegistration` and sends it to the asserting party
647
+
* `+/saml2/login/sso/{registrationId}+` - The endpoint that xref:servlet/saml2/login/authentication.adoc[authenticates an asserting party's `<saml2:Response>`] based on the configurations for that `RelyingPartyRegistration`
648
+
* `+/saml2/logout/sso+` - The endpoint that xref:servlet/saml2/logout.adoc[processes `<saml2:LogoutRequest>` and `<saml2:LogoutResponse>` payloads]; the `RelyingPartyRegistration` is looked up from previously authenticated state
649
+
* `+/saml2/saml2-service-provider/metadata/{registrationId}+` - The xref:servlet/saml2/metadata.adoc[relying party metadata] for that `RelyingPartyRegistration`
650
+
651
+
Since the `registrationId` is the primary identifier for a `RelyingPartyRegistration`, it is needed in the URL for unauthenticated scenarios.
652
+
If you wish to remove the `registrationId` from the URL for any reason, you can <<servlet-saml2login-rpr-relyingpartyregistrationresolver,specify a `RelyingPartyRegistrationResolver`>> to tell Spring Security how to look up the `registrationId`.
653
+
643
654
[[servlet-saml2login-rpr-credentials]]
644
655
=== Credentials
645
656
@@ -712,56 +723,6 @@ resource.inputStream.use {
712
723
[TIP]
713
724
When you specify the locations of these files as the appropriate Spring Boot properties, then Spring Boot will perform these conversions for you.
As seen so far, Spring Security resolves the `RelyingPartyRegistration` by looking for the registration id in the URI path.
719
-
720
-
There are a number of reasons you may want to customize. Among them:
721
-
722
-
* You may know that you will never be a multi-tenant application and so want to have a simpler URL scheme
723
-
* You may identify tenants in a way other than by the URI path
724
-
725
-
To customize the way that a `RelyingPartyRegistration` is resolved, you can configure a custom `RelyingPartyRegistrationResolver`.
726
-
The default looks up the registration id from the URI's last path element and looks it up in your `RelyingPartyRegistrationRepository`.
727
-
728
-
You can provide a simpler resolver that, for example, always returns the same relying party:
729
-
730
-
====
731
-
.Java
732
-
[source,java,role="primary"]
733
-
----
734
-
public class SingleRelyingPartyRegistrationResolver implements RelyingPartyRegistrationResolver {
735
-
736
-
private final RelyingPartyRegistrationResolver delegate;
737
-
738
-
public SingleRelyingPartyRegistrationResolver(RelyingPartyRegistrationRepository registrations) {
739
-
this.delegate = new DefaultRelyingPartyRegistrationResolver(registrations);
740
-
}
741
-
742
-
@Override
743
-
public RelyingPartyRegistration resolve(HttpServletRequest request, String registrationId) {
744
-
return this.delegate.resolve(request, "single");
745
-
}
746
-
}
747
-
----
748
-
749
-
.Kotlin
750
-
[source,kotlin,role="secondary"]
751
-
----
752
-
class SingleRelyingPartyRegistrationResolver(delegate: RelyingPartyRegistrationResolver) : RelyingPartyRegistrationResolver {
753
-
override fun resolve(request: HttpServletRequest?, registrationId: String?): RelyingPartyRegistration? {
754
-
return this.delegate.resolve(request, "single")
755
-
}
756
-
}
757
-
----
758
-
====
759
-
760
-
Then, you can provide this resolver to the appropriate filters that xref:servlet/saml2/login/authentication-requests.adoc#servlet-saml2login-sp-initiated-factory[produce ``<saml2:AuthnRequest>``s], xref:servlet/saml2/login/authentication.adoc#servlet-saml2login-authenticate-responses[authenticate ``<saml2:Response>``s], and xref:servlet/saml2/metadata.adoc#servlet-saml2login-metadata[produce `<saml2:SPSSODescriptor>` metadata].
761
-
762
-
[NOTE]
763
-
Remember that if you have any placeholders in your `RelyingPartyRegistration`, your resolver implementation should resolve them.
764
-
765
726
[[servlet-saml2login-rpr-duplicated]]
766
727
=== Duplicated Relying Party Configurations
767
728
@@ -856,3 +817,184 @@ open fun relyingPartyRegistrations(): RelyingPartyRegistrationRepository? {
=== Resolving the `RelyingPartyRegistration` from the Request
823
+
824
+
As seen so far, Spring Security resolves the `RelyingPartyRegistration` by looking for the registration id in the URI path.
825
+
826
+
There are a number of reasons you may want to customize that. Among them:
827
+
828
+
* You may already <<relyingpartyregistrationresolver-single, know which `RelyingPartyRegistration` you need>>
829
+
* You may be <<relyingpartyregistrationresolver-entityid, federating many asserting parties>>
830
+
831
+
To customize the way that a `RelyingPartyRegistration` is resolved, you can configure a custom `RelyingPartyRegistrationResolver`.
832
+
The default looks up the registration id from the URI's last path element and looks it up in your `RelyingPartyRegistrationRepository`.
833
+
834
+
[NOTE]
835
+
Remember that if you have any placeholders in your `RelyingPartyRegistration`, your resolver implementation should resolve them.
836
+
837
+
[[relyingpartyregistrationresolver-single]]
838
+
==== Resolving to a Single Consistent `RelyingPartyRegistration`
839
+
840
+
You can provide a resolver that, for example, always returns the same `RelyingPartyRegistration`:
841
+
842
+
====
843
+
.Java
844
+
[source,java,role="primary"]
845
+
----
846
+
public class SingleRelyingPartyRegistrationResolver implements RelyingPartyRegistrationResolver {
847
+
848
+
private final RelyingPartyRegistrationResolver delegate;
849
+
850
+
public SingleRelyingPartyRegistrationResolver(RelyingPartyRegistrationRepository registrations) {
851
+
this.delegate = new DefaultRelyingPartyRegistrationResolver(registrations);
852
+
}
853
+
854
+
@Override
855
+
public RelyingPartyRegistration resolve(HttpServletRequest request, String registrationId) {
856
+
return this.delegate.resolve(request, "single");
857
+
}
858
+
}
859
+
----
860
+
861
+
.Kotlin
862
+
[source,kotlin,role="secondary"]
863
+
----
864
+
class SingleRelyingPartyRegistrationResolver(delegate: RelyingPartyRegistrationResolver) : RelyingPartyRegistrationResolver {
865
+
override fun resolve(request: HttpServletRequest?, registrationId: String?): RelyingPartyRegistration? {
866
+
return this.delegate.resolve(request, "single")
867
+
}
868
+
}
869
+
----
870
+
====
871
+
872
+
[TIP]
873
+
You might next take a look at how to use this resolver to customize xref:servlet/saml2/metadata.adoc#servlet-saml2login-metadata[`<saml2:SPSSODescriptor>` metadata production].
874
+
875
+
[[relyingpartyregistrationresolver-entityid]]
876
+
==== Resolving Based on the `<saml2:Response#Issuer>`
877
+
878
+
When you have one relying party that can accept assertions from multiple asserting parties, you will have as many ``RelyingPartyRegistration``s as asserting parties, with the <<servlet-saml2login-rpr-duplicated, relying party information duplicated across each instance>>.
879
+
880
+
This carries the implication that the assertion consumer service endpoint will be different for each asserting party, which may not be desirable.
881
+
882
+
You can instead resolve the `registrationId` via the `Issuer`.
883
+
A custom implementation of `RelyingPartyRegistrationResolver` that does this may look like:
884
+
885
+
====
886
+
.Java
887
+
[source,java,role="primary"]
888
+
----
889
+
public class SamlResponseIssuerRelyingPartyRegistrationResolver implements RelyingPartyRegistrationResolver {
890
+
private final InMemoryRelyingPartyRegistrationRepository registrations;
You might next take a look at how to use this resolver to customize xref:servlet/saml2/login/authentication.adoc#relyingpartyregistrationresolver-apply[`<saml2:Response>` authentication].
942
+
943
+
[[federating-saml2-login]]
944
+
=== Federating Login
945
+
946
+
One common arrangement with SAML 2.0 is an identity provider that has multiple asserting parties.
947
+
In this case, the identity provider's metadata endpoint returns multiple `<md:IDPSSODescriptor>` elements.
948
+
949
+
These multiple asserting parties can be accessed in a single call to `RelyingPartyRegistrations` like so:
Note that because the registration id is set to a random value, this will change certain SAML 2.0 endpoints to be unpredictable.
980
+
There are several ways to address this; let's focus on a way that suits the specific use case of federation.
981
+
982
+
In many federation cases, all the asserting parties share service provider configuration.
983
+
Given that Spring Security will by default include the `registrationId` in all many of its SAML 2.0 URIs, the next step is often to change these URIs to exclude the `registrationId`.
984
+
985
+
There are two main URIs you will want to change along those lines:
986
+
987
+
* <<relyingpartyregistrationresolver-entityid,Resolve by `<saml2:Response#Issuer>`>>
988
+
* <<relyingpartyregistrationresolver-single,Resolve with a default `RelyingPartyRegistration`>>
989
+
990
+
[NOTE]
991
+
Optionally, you may also want to change the Authentication Request location, but since this is a URI internal to the app and not published to asserting parties, the benefit is often minimal.
992
+
993
+
You can see a completed example of this in {gh-samples-url}/servlet/spring-boot/java/saml2/saml-extension-federation[our `saml-extension-federation` sample].
994
+
995
+
[[using-spring-security-saml-extension-uris]]
996
+
=== Using Spring Security SAML Extension URIs
997
+
998
+
In the event that you are migrating from the Spring Security SAML Extension, there may be some benefit to configuring your application to use the SAML Extension URI defaults.
999
+
1000
+
For more information on this, please see {gh-samples-url}/servlet/spring-boot/java/saml2/custom-urls[our `custom-urls` sample] and {gh-samples-url}/servlet/spring-boot/java/saml2/saml-extension-federation[our `saml-extension-federation` sample].
0 commit comments