Skip to content

Commit 2affae5

Browse files
committed
Consider customization of Saml2LogoutRequestValidatorParametersResolver
Closes spring-projectsgh-16840 Signed-off-by: Evgeniy Cheban <[email protected]>
1 parent ef4479a commit 2affae5

File tree

3 files changed

+106
-4
lines changed

3 files changed

+106
-4
lines changed

Diff for: config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java

+32-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -109,6 +109,7 @@
109109
*
110110
* @author Josh Cummings
111111
* @author Ngoc Nhan
112+
* @author Evgeniy Cheban
112113
* @since 5.6
113114
* @see Saml2LogoutConfigurer
114115
*/
@@ -262,12 +263,25 @@ private Saml2LogoutRequestFilter createLogoutRequestProcessingFilter(
262263
LogoutHandler[] logoutHandlers = this.logoutHandlers.toArray(new LogoutHandler[0]);
263264
Saml2LogoutResponseResolver logoutResponseResolver = createSaml2LogoutResponseResolver(registrations);
264265
Saml2LogoutRequestFilter filter = new Saml2LogoutRequestFilter(
265-
createSaml2LogoutResponseParametersResolver(registrations),
266+
getLogoutRequestParametersResolver(registrations),
266267
this.logoutRequestConfigurer.logoutRequestValidator(), logoutResponseResolver, logoutHandlers);
267268
filter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
268269
return postProcess(filter);
269270
}
270271

272+
private Saml2LogoutRequestValidatorParametersResolver getLogoutRequestParametersResolver(
273+
RelyingPartyRegistrationRepository registrations) {
274+
if (this.logoutRequestConfigurer.logoutRequestParametersResolver != null) {
275+
return this.logoutRequestConfigurer.logoutRequestParametersResolver;
276+
}
277+
Saml2LogoutRequestValidatorParametersResolver logoutRequestResolver = getBeanOrNull(
278+
Saml2LogoutRequestValidatorParametersResolver.class);
279+
if (logoutRequestResolver != null) {
280+
return logoutRequestResolver;
281+
}
282+
return createSaml2LogoutResponseParametersResolver(registrations);
283+
}
284+
271285
private Saml2LogoutRequestValidatorParametersResolver createSaml2LogoutResponseParametersResolver(
272286
RelyingPartyRegistrationRepository registrations) {
273287
RequestMatcher requestMatcher = createLogoutRequestMatcher();
@@ -352,6 +366,8 @@ public final class LogoutRequestConfigurer {
352366

353367
private Saml2LogoutRequestResolver logoutRequestResolver;
354368

369+
private Saml2LogoutRequestValidatorParametersResolver logoutRequestParametersResolver;
370+
355371
private Saml2LogoutRequestRepository logoutRequestRepository = new HttpSessionLogoutRequestRepository();
356372

357373
LogoutRequestConfigurer() {
@@ -394,6 +410,20 @@ public LogoutRequestConfigurer logoutRequestResolver(Saml2LogoutRequestResolver
394410
return this;
395411
}
396412

413+
/**
414+
* Use this {@link Saml2LogoutRequestValidatorParametersResolver} for resolving
415+
* logout request and associated validation parameters.
416+
* @param logoutRequestParametersResolver the
417+
* {@link Saml2LogoutRequestValidatorParametersResolver} to use
418+
* @return the {@link LogoutRequestConfigurer} for further customizations
419+
* @since 6.5
420+
*/
421+
public LogoutRequestConfigurer logoutRequestParametersResolver(
422+
Saml2LogoutRequestValidatorParametersResolver logoutRequestParametersResolver) {
423+
this.logoutRequestParametersResolver = logoutRequestParametersResolver;
424+
return this;
425+
}
426+
397427
/**
398428
* Use this {@link Saml2LogoutRequestRepository} for storing logout requests
399429
* @param logoutRequestRepository the {@link Saml2LogoutRequestRepository} to use

Diff for: config/src/main/kotlin/org/springframework/security/config/annotation/web/saml2/LogoutRequestDsl.kt

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,16 +22,20 @@ import org.springframework.security.saml2.provider.service.authentication.logout
2222
import org.springframework.security.saml2.provider.service.web.authentication.logout.HttpSessionLogoutRequestRepository
2323
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestRepository
2424
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestResolver
25+
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestValidatorParametersResolver
2526

2627
/**
2728
* A Kotlin DSL to configure SAML 2.0 Logout Request components using idiomatic Kotlin code.
2829
*
2930
* @author Josh Cummings
31+
* @author Evgeniy Cheban
3032
* @since 6.3
3133
* @property logoutUrl The URL by which the asserting party can send a SAML 2.0 Logout Request.
3234
* The Asserting Party should use whatever HTTP method specified in {@link RelyingPartyRegistration#getSingleLogoutServiceBindings()}.
3335
* @property logoutRequestValidator the [Saml2LogoutRequestValidator] to use for validating incoming {@code LogoutRequest}s.
3436
* @property logoutRequestResolver the [Saml2LogoutRequestResolver] to use for generating outgoing {@code LogoutRequest}s.
37+
* @property logoutRequestParametersResolver the [Saml2LogoutRequestValidatorParametersResolver] to use for resolving logout
38+
* request and associated validation parameters.
3539
* @property logoutRequestRepository the [Saml2LogoutRequestRepository] to use for storing outgoing {@code LogoutRequest}s for
3640
* linking to the corresponding {@code LogoutResponse} from the asserting party
3741
*/
@@ -40,13 +44,15 @@ class LogoutRequestDsl {
4044
var logoutUrl = "/logout/saml2/slo"
4145
var logoutRequestValidator: Saml2LogoutRequestValidator? = null
4246
var logoutRequestResolver: Saml2LogoutRequestResolver? = null
47+
var logoutRequestParametersResolver: Saml2LogoutRequestValidatorParametersResolver? = null
4348
var logoutRequestRepository: Saml2LogoutRequestRepository = HttpSessionLogoutRequestRepository()
4449

4550
internal fun get(): (Saml2LogoutConfigurer<HttpSecurity>.LogoutRequestConfigurer) -> Unit {
4651
return { logoutRequest ->
4752
logoutUrl.also { logoutRequest.logoutUrl(logoutUrl) }
4853
logoutRequestValidator?.also { logoutRequest.logoutRequestValidator(logoutRequestValidator) }
4954
logoutRequestResolver?.also { logoutRequest.logoutRequestResolver(logoutRequestResolver) }
55+
logoutRequestParametersResolver?.also { logoutRequest.logoutRequestParametersResolver(logoutRequestParametersResolver) }
5056
logoutRequestRepository.also { logoutRequest.logoutRequestRepository(logoutRequestRepository) }
5157
}
5258
}

Diff for: config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurerTests.java

+67-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -70,6 +70,7 @@
7070
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestFilter;
7171
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestRepository;
7272
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestResolver;
73+
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestValidatorParametersResolver;
7374
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutResponseFilter;
7475
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutResponseResolver;
7576
import org.springframework.security.web.SecurityFilterChain;
@@ -542,6 +543,22 @@ public void saml2LogoutWhenLogoutFilterPostProcessedThenUses() {
542543

543544
}
544545

546+
@Test
547+
public void saml2LogoutWhenCustomLogoutRequestParametersResolverBeanThenUses() throws Exception {
548+
this.spring.register(Saml2DefaultsWithLogoutRequestParametersResolverBeanConfig.class).autowire();
549+
this.mvc.perform(post("/logout").with(authentication(this.user)).with(csrf()));
550+
verify(Saml2DefaultsWithLogoutRequestParametersResolverBeanConfig.logoutRequestParametersResolver)
551+
.resolve(any(), eq(this.user));
552+
}
553+
554+
@Test
555+
public void saml2LogoutWhenCustomLogoutRequestParametersResolverSetThenUses() throws Exception {
556+
this.spring.register(Saml2DefaultsWithLogoutRequestParametersResolverSetConfig.class).autowire();
557+
this.mvc.perform(post("/logout").with(authentication(this.user)).with(csrf()));
558+
verify(Saml2DefaultsWithLogoutRequestParametersResolverSetConfig.logoutRequestParametersResolver).resolve(any(),
559+
eq(this.user));
560+
}
561+
545562
private <T> T getBean(Class<T> clazz) {
546563
return this.spring.getContext().getBean(clazz);
547564
}
@@ -723,6 +740,55 @@ Saml2LogoutResponseResolver logoutResponseResolver() {
723740

724741
}
725742

743+
@Configuration
744+
@EnableWebSecurity
745+
@Import(Saml2LoginConfigBeans.class)
746+
static class Saml2DefaultsWithLogoutRequestParametersResolverBeanConfig {
747+
748+
static Saml2LogoutRequestValidatorParametersResolver logoutRequestParametersResolver = mock(
749+
Saml2LogoutRequestValidatorParametersResolver.class);
750+
751+
@Bean
752+
SecurityFilterChain web(HttpSecurity http) throws Exception {
753+
// @formatter:off
754+
http
755+
.authorizeRequests((authorize) -> authorize.anyRequest().authenticated())
756+
.saml2Login(withDefaults())
757+
.saml2Logout(withDefaults());
758+
return http.build();
759+
// @formatter:on
760+
}
761+
762+
@Bean
763+
Saml2LogoutRequestValidatorParametersResolver logoutRequestParametersResolver() {
764+
return logoutRequestParametersResolver;
765+
}
766+
767+
}
768+
769+
@Configuration
770+
@EnableWebSecurity
771+
@Import(Saml2LoginConfigBeans.class)
772+
static class Saml2DefaultsWithLogoutRequestParametersResolverSetConfig {
773+
774+
static Saml2LogoutRequestValidatorParametersResolver logoutRequestParametersResolver = mock(
775+
Saml2LogoutRequestValidatorParametersResolver.class);
776+
777+
@Bean
778+
SecurityFilterChain web(HttpSecurity http) throws Exception {
779+
// @formatter:off
780+
http
781+
.authorizeRequests((authorize) -> authorize.anyRequest().authenticated())
782+
.saml2Login(withDefaults())
783+
.saml2Logout((logout) -> logout
784+
.logoutRequest((logoutRequest) -> logoutRequest
785+
.logoutRequestParametersResolver(logoutRequestParametersResolver)));
786+
return http.build();
787+
// @formatter:on
788+
}
789+
790+
}
791+
726792
static class Saml2LoginConfigBeans {
727793

728794
@Bean

0 commit comments

Comments
 (0)