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
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`.
@@ -712,56 +713,6 @@ resource.inputStream.use {
712
713
[TIP]
713
714
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
716
[[servlet-saml2login-rpr-duplicated]]
766
717
=== Duplicated Relying Party Configurations
767
718
@@ -856,3 +807,184 @@ open fun relyingPartyRegistrations(): RelyingPartyRegistrationRepository? {
=== Resolving the `RelyingPartyRegistration` from the Request
813
+
814
+
As seen so far, Spring Security resolves the `RelyingPartyRegistration` by looking for the registration id in the URI path.
815
+
816
+
There are a number of reasons you may want to customize that. Among them:
817
+
818
+
* You may already <<relyingpartyregistrationresolver-single, know which `RelyingPartyRegistration` you need>>
819
+
* You may be <<relyingpartyregistrationresolver-entityid, federating many asserting parties>>
820
+
821
+
To customize the way that a `RelyingPartyRegistration` is resolved, you can configure a custom `RelyingPartyRegistrationResolver`.
822
+
The default looks up the registration id from the URI's last path element and looks it up in your `RelyingPartyRegistrationRepository`.
823
+
824
+
[NOTE]
825
+
Remember that if you have any placeholders in your `RelyingPartyRegistration`, your resolver implementation should resolve them.
826
+
827
+
[[relyingpartyregistrationresolver-single]]
828
+
==== Resolving to a Single Consistent `RelyingPartyRegistration`
829
+
830
+
You can provide a resolver that, for example, always returns the same `RelyingPartyRegistration`:
831
+
832
+
====
833
+
.Java
834
+
[source,java,role="primary"]
835
+
----
836
+
public class SingleRelyingPartyRegistrationResolver implements RelyingPartyRegistrationResolver {
837
+
838
+
private final RelyingPartyRegistrationResolver delegate;
839
+
840
+
public SingleRelyingPartyRegistrationResolver(RelyingPartyRegistrationRepository registrations) {
841
+
this.delegate = new DefaultRelyingPartyRegistrationResolver(registrations);
842
+
}
843
+
844
+
@Override
845
+
public RelyingPartyRegistration resolve(HttpServletRequest request, String registrationId) {
846
+
return this.delegate.resolve(request, "single");
847
+
}
848
+
}
849
+
----
850
+
851
+
.Kotlin
852
+
[source,kotlin,role="secondary"]
853
+
----
854
+
class SingleRelyingPartyRegistrationResolver(delegate: RelyingPartyRegistrationResolver) : RelyingPartyRegistrationResolver {
855
+
override fun resolve(request: HttpServletRequest?, registrationId: String?): RelyingPartyRegistration? {
856
+
return this.delegate.resolve(request, "single")
857
+
}
858
+
}
859
+
----
860
+
====
861
+
862
+
[TIP]
863
+
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].
864
+
865
+
[[relyingpartyregistrationresolver-entityid]]
866
+
==== Resolving Based on the `<saml2:Response#Issuer>`
867
+
868
+
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>>.
869
+
870
+
This carries the implication that the assertion consumer service endpoint will be different for each asserting party, which may not be desirable.
871
+
872
+
You can instead resolve the `registrationId` via the `Issuer`.
873
+
A custom implementation of `RelyingPartyRegistrationResolver` that does this may look like:
874
+
875
+
====
876
+
.Java
877
+
[source,java,role="primary"]
878
+
----
879
+
public class SamlResponseIssuerRelyingPartyRegistrationResolver implements RelyingPartyRegistrationResolver {
880
+
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].
932
+
933
+
[[federating-saml2-login]]
934
+
=== Federating Login
935
+
936
+
One common arrangement with SAML 2.0 is an identity provider that has multiple asserting parties.
937
+
In this case, the identity provider's metadata endpoint returns multiple `<md:IDPSSODescriptor>` elements.
938
+
939
+
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.
970
+
There are several ways to address this; let's focus on a way that suits the specific use case of federation.
971
+
972
+
In many federation cases, all the asserting parties share service provider configuration.
973
+
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`.
974
+
975
+
There are two main URIs you will want to change along those lines:
976
+
977
+
* <<relyingpartyregistrationresolver-entityid,Resolve by `<saml2:Response#Issuer>`>>
978
+
* <<relyingpartyregistrationresolver-single,Resolve with a default `RelyingPartyRegistration`>>
979
+
980
+
[NOTE]
981
+
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.
982
+
983
+
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].
984
+
985
+
[[using-spring-security-saml-extension-uris]]
986
+
=== Using Spring Security SAML Extension URIs
987
+
988
+
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.
989
+
990
+
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].
In the event that you are applying a `RelyingPartyRegistrationResolver` to remove the `registrationId` from the URI, you must also change the URI in the filter like so:
0 commit comments