Skip to content

Commit c6bba38

Browse files
committed
Update SAML 2.0 Migration Steps
1 parent 45b453f commit c6bba38

File tree

1 file changed

+239
-0
lines changed

1 file changed

+239
-0
lines changed

docs/modules/ROOT/pages/migration-7/saml2.adoc

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
= Saml 2.0 Migrations
22

3+
== Use OpenSAML 5 By Default
4+
5+
OpenSAML 4.x is no longer supported by the OpenSAML team.
6+
As such, Spring Security will default to using its `OpenSaml5` components in all cases.
7+
8+
If you want to see how well your application will respond to this, do the following:
9+
10+
1. Update your OpenSAML dependencies to 5.x
11+
2. If you are constructing an `OpenSaml4XXX` Spring Security component, change it to `OpenSaml5`.
12+
13+
If you cannot opt-in, then add the `opensaml-saml-api` and `opensaml-saml-impl` 4.x dependencies and exclude the 5.x dependencies from `spring-security-saml2-service-provider`.
14+
315
== Continue Filter Chain When No Relying Party Found
416

517
In Spring Security 6, `Saml2WebSsoAuthenticationFilter` throws an exception when the request URI matches, but no relying party registration is found.
@@ -163,3 +175,230 @@ val responseValidator = ResponseValidator.withDefaults { responseToken: Response
163175
provider.setResponseValidator(responseValidator)
164176
----
165177
======
178+
179+
== `RelyingPartyRegistration` Improvements
180+
181+
`RelyingPartyRegistration` links metadata from a relying party to metadata from an asserting party.
182+
183+
To prepare for some improvements to the API, please take the following steps:
184+
185+
1. If you are mutating a registration by using `RelyingPartyRegistration#withRelyingPartyRegistration`, instead call `RelyingPartyRegistration#mutate`
186+
2. If you are providing or retrieving `AssertingPartyDetails`, use `getAssertingPartyMetadata` or `withAssertingPartyMetadata` instead.
187+
188+
== `OpenSaml5AuthenticationProvider` Improvements
189+
190+
Spring Security 7 will remove a handful of static factories from `OpenSaml5AuthenticationProvider` in favor of inner classes.
191+
These inner classes simplify customization of the response validator, the assertion validator, and the response authentication converter.
192+
193+
=== Response Validation
194+
195+
Instead of doing:
196+
197+
[tabs]
198+
======
199+
Java::
200+
+
201+
[source,java,role="primary"]
202+
----
203+
@Bean
204+
OpenSaml5AuthenticationProvider saml2AuthenticationProvider() {
205+
OpenSaml5AuthenticationProvider saml2 = new OpenSaml5AuthenticationProvider();
206+
saml2.setResponseValidator((responseToken) -> OpenSamlAuthenticationProvider.createDefaultResponseValidator()
207+
.andThen((result) -> result
208+
.concat(myCustomValidator.convert(responseToken))
209+
));
210+
return saml2;
211+
}
212+
----
213+
214+
Kotlin::
215+
+
216+
[source,kotlin,role="secondary"]
217+
----
218+
@Bean
219+
fun saml2AuthenticationProvider(): OpenSaml5AuthenticationProvider {
220+
val saml2 = OpenSaml5AuthenticationProvider()
221+
saml2.setResponseValidator { responseToken -> OpenSamlAuthenticationProvider.createDefaultResponseValidator()
222+
.andThen { result -> result
223+
.concat(myCustomValidator.convert(responseToken))
224+
}
225+
}
226+
return saml2
227+
}
228+
----
229+
======
230+
231+
use `OpenSaml5AuthenticationProvider.ResponseValidator`:
232+
233+
[tabs]
234+
======
235+
Java::
236+
+
237+
[source,java,role="primary"]
238+
----
239+
@Bean
240+
OpenSaml5AuthenticationProvider saml2AuthenticationProvider() {
241+
OpenSaml5AuthenticationProvider saml2 = new OpenSaml5AuthenticationProvider();
242+
saml2.setResponseValidator(ResponseValidator.withDefaults(myCustomValidator));
243+
return saml2;
244+
}
245+
----
246+
247+
Kotlin::
248+
+
249+
[source,kotlin,role="secondary"]
250+
----
251+
@Bean
252+
fun saml2AuthenticationProvider(): OpenSaml5AuthenticationProvider {
253+
val saml2 = OpenSaml5AuthenticationProvider()
254+
saml2.setResponseValidator(ResponseValidator.withDefaults(myCustomValidator))
255+
return saml2
256+
}
257+
----
258+
======
259+
260+
=== Assertion Validation
261+
262+
Instead of doing:
263+
264+
[tabs]
265+
======
266+
Java::
267+
+
268+
[source,java,role="primary"]
269+
----
270+
@Bean
271+
OpenSaml5AuthenticationProvider saml2AuthenticationProvider() {
272+
OpenSaml5AuthenticationProvider saml2 = new OpenSaml5AuthenticationProvider();
273+
authenticationProvider.setAssertionValidator(OpenSaml5AuthenticationProvider
274+
.createDefaultAssertionValidatorWithParameters(assertionToken -> {
275+
Map<String, Object> params = new HashMap<>();
276+
params.put(CLOCK_SKEW, Duration.ofMinutes(10).toMillis());
277+
// ... other validation parameters
278+
return new ValidationContext(params);
279+
})
280+
);
281+
return saml2;
282+
}
283+
----
284+
285+
Kotlin::
286+
+
287+
[source,kotlin,role="secondary"]
288+
----
289+
@Bean
290+
fun saml2AuthenticationProvider(): OpenSaml5AuthenticationProvider {
291+
val saml2 = OpenSaml5AuthenticationProvider()
292+
authenticationProvider.setAssertionValidator(OpenSaml5AuthenticationProvider
293+
.createDefaultAssertionValidatorWithParameters { ->
294+
val params = HashMap<String, Object>()
295+
params.put(CLOCK_SKEW, Duration.ofMinutes(10).toMillis())
296+
// ... other validation parameters
297+
return ValidationContext(params)
298+
}
299+
)
300+
return saml2
301+
}
302+
----
303+
======
304+
305+
use `OpenSaml5AuthenticationProvider.AssertionValidator`:
306+
307+
[tabs]
308+
======
309+
Java::
310+
+
311+
[source,java,role="primary"]
312+
----
313+
@Bean
314+
OpenSaml5AuthenticationProvider saml2AuthenticationProvider() {
315+
OpenSaml5AuthenticationProvider saml2 = new OpenSaml5AuthenticationProvider();
316+
Duration tenMinutes = Duration.ofMinutes(10);
317+
authenticationProvider.setAssertionValidator(AssertionValidator.builder().clockSkew(tenMinutes).build());
318+
return saml2;
319+
}
320+
----
321+
322+
Kotlin::
323+
+
324+
[source,kotlin,role="secondary"]
325+
----
326+
@Bean
327+
fun saml2AuthenticationProvider(): OpenSaml5AuthenticationProvider {
328+
val saml2 = OpenSaml5AuthenticationProvider()
329+
val tenMinutes = Duration.ofMinutes(10)
330+
authenticationProvider.setAssertionValidator(AssertionValidator.builder().clockSkew(tenMinutes).build())
331+
return saml2
332+
}
333+
----
334+
======
335+
336+
== Response Authentication Converter
337+
338+
Instead of doing:
339+
340+
[tabs]
341+
======
342+
Java::
343+
+
344+
[source,java,role="primary"]
345+
----
346+
@Bean
347+
Converter<ResponseToken, Saml2Authentication> authenticationConverter() {
348+
return (responseToken) -> {
349+
Saml2Authentication authentication = OpenSaml5AutnenticationProvider.createDefaultResponseAuthenticationConverter()
350+
.convert(responseToken);
351+
// ... work with OpenSAML's Assertion object to extract the principal
352+
return new Saml2Authentication(myPrincipal, authentication.getSaml2Response(), authentication.getAuthorities());
353+
};
354+
}
355+
----
356+
357+
Kotlin::
358+
+
359+
[source,kotlin,role="secondary"]
360+
----
361+
@Bean
362+
fun authenticationConverter(): Converter<ResponseToken, Saml2Authentication> {
363+
return { responseToken ->
364+
val authentication =
365+
OpenSaml5AutnenticationProvider.createDefaultResponseAuthenticationConverter().convert(responseToken)
366+
// ... work with OpenSAML's Assertion object to extract the principal
367+
return Saml2Authentication(myPrincipal, authentication.getSaml2Response(), authentication.getAuthorities())
368+
}
369+
}
370+
----
371+
======
372+
373+
use `OpenSaml5AuthenticationProvider.ResponseAuthenticationConverter`:
374+
375+
[tabs]
376+
======
377+
Java::
378+
+
379+
[source,java,role="primary"]
380+
----
381+
@Bean
382+
ResponseAuthenticationConverter authenticationConverter() {
383+
ResponseAuthenticationConverter authenticationConverter = new ResponseAuthenticationConverter();
384+
authenticationConverter.setPrincipalNameConverter((assertion) -> {
385+
// ... work with OpenSAML's Assertion object to extract the principal
386+
});
387+
return authenticationConverter;
388+
}
389+
----
390+
391+
Kotlin::
392+
+
393+
[source,kotlin,role="secondary"]
394+
----
395+
@Bean
396+
fun authenticationConverter(): ResponseAuthenticationConverter {
397+
val authenticationConverter = ResponseAuthenticationConverter()
398+
authenticationConverter.setPrincipalNameConverter { assertion ->
399+
// ... work with OpenSAML's Assertion object to extract the principal
400+
}
401+
return authenticationConverter
402+
}
403+
----
404+
======

0 commit comments

Comments
 (0)