Skip to content

Commit 33708e6

Browse files
gouravjzheaux
authored andcommitted
Add postProcess support to Saml2LogoutConfigurer
Closes gh-10311
1 parent fbb7691 commit 33708e6

File tree

2 files changed

+115
-3
lines changed

2 files changed

+115
-3
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ private Saml2LogoutRequestFilter createLogoutRequestProcessingFilter(
253253
Saml2LogoutRequestFilter filter = new Saml2LogoutRequestFilter(registrations,
254254
this.logoutRequestConfigurer.logoutRequestValidator(), logoutResponseResolver, logoutHandlers);
255255
filter.setLogoutRequestMatcher(createLogoutRequestMatcher());
256-
return filter;
256+
return postProcess(filter);
257257
}
258258

259259
private Saml2LogoutResponseFilter createLogoutResponseProcessingFilter(
@@ -262,7 +262,7 @@ private Saml2LogoutResponseFilter createLogoutResponseProcessingFilter(
262262
this.logoutResponseConfigurer.logoutResponseValidator(), this.logoutSuccessHandler);
263263
logoutResponseFilter.setLogoutRequestMatcher(createLogoutResponseMatcher());
264264
logoutResponseFilter.setLogoutRequestRepository(this.logoutRequestConfigurer.logoutRequestRepository);
265-
return logoutResponseFilter;
265+
return postProcess(logoutResponseFilter);
266266
}
267267

268268
private LogoutFilter createRelyingPartyLogoutFilter(RelyingPartyRegistrationResolver registrations) {
@@ -271,7 +271,7 @@ private LogoutFilter createRelyingPartyLogoutFilter(RelyingPartyRegistrationReso
271271
registrations);
272272
LogoutFilter logoutFilter = new LogoutFilter(logoutRequestSuccessHandler, logoutHandlers);
273273
logoutFilter.setLogoutRequestMatcher(createLogoutMatcher());
274-
return logoutFilter;
274+
return postProcess(logoutFilter);
275275
}
276276

277277
private RequestMatcher createLogoutMatcher() {

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

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.springframework.mock.web.MockHttpServletResponse;
3838
import org.springframework.mock.web.MockHttpSession;
3939
import org.springframework.security.authentication.TestingAuthenticationToken;
40+
import org.springframework.security.config.annotation.ObjectPostProcessor;
4041
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
4142
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
4243
import org.springframework.security.config.test.SpringTestContext;
@@ -59,12 +60,16 @@
5960
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
6061
import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations;
6162
import org.springframework.security.saml2.provider.service.web.authentication.logout.HttpSessionLogoutRequestRepository;
63+
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestFilter;
6264
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestRepository;
6365
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestResolver;
66+
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutResponseFilter;
6467
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutResponseResolver;
6568
import org.springframework.security.web.SecurityFilterChain;
69+
import org.springframework.security.web.authentication.logout.LogoutFilter;
6670
import org.springframework.security.web.authentication.logout.LogoutHandler;
6771
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
72+
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
6873
import org.springframework.test.web.servlet.MockMvc;
6974
import org.springframework.test.web.servlet.MvcResult;
7075

@@ -75,6 +80,8 @@
7580
import static org.mockito.BDDMockito.mock;
7681
import static org.mockito.BDDMockito.verify;
7782
import static org.mockito.BDDMockito.verifyNoInteractions;
83+
import static org.mockito.Mockito.atLeastOnce;
84+
import static org.mockito.Mockito.spy;
7885
import static org.springframework.security.config.Customizer.withDefaults;
7986
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
8087
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
@@ -346,6 +353,47 @@ public void saml2LogoutResponseWhenCustomLogoutResponseHandlerThenUses() throws
346353
verify(getBean(Saml2LogoutResponseValidator.class)).validate(any());
347354
}
348355

356+
@Test
357+
public void saml2LogoutWhenLogoutGetThenLogsOutAndSendsLogoutRequest() throws Exception {
358+
this.spring.register(Saml2LogoutWithHttpGet.class).autowire();
359+
MvcResult result = this.mvc.perform(get("/logout").with(authentication(this.user)))
360+
.andExpect(status().isFound()).andReturn();
361+
String location = result.getResponse().getHeader("Location");
362+
LogoutHandler logoutHandler = this.spring.getContext().getBean(LogoutHandler.class);
363+
assertThat(location).startsWith("https://ap.example.org/logout/saml2/request");
364+
verify(logoutHandler).logout(any(), any(), any());
365+
}
366+
367+
@Test
368+
public void saml2LogoutWhenSaml2LogoutRequestFilterPostProcessedThenUses() {
369+
370+
Saml2DefaultsWithObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
371+
this.spring.register(Saml2DefaultsWithObjectPostProcessorConfig.class).autowire();
372+
verify(Saml2DefaultsWithObjectPostProcessorConfig.objectPostProcessor)
373+
.postProcess(any(Saml2LogoutRequestFilter.class));
374+
375+
}
376+
377+
@Test
378+
public void saml2LogoutWhenSaml2LogoutResponseFilterPostProcessedThenUses() {
379+
380+
Saml2DefaultsWithObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
381+
this.spring.register(Saml2DefaultsWithObjectPostProcessorConfig.class).autowire();
382+
verify(Saml2DefaultsWithObjectPostProcessorConfig.objectPostProcessor)
383+
.postProcess(any(Saml2LogoutResponseFilter.class));
384+
385+
}
386+
387+
@Test
388+
public void saml2LogoutWhenLogoutFilterPostProcessedThenUses() {
389+
390+
Saml2DefaultsWithObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
391+
this.spring.register(Saml2DefaultsWithObjectPostProcessorConfig.class).autowire();
392+
verify(Saml2DefaultsWithObjectPostProcessorConfig.objectPostProcessor, atLeastOnce())
393+
.postProcess(any(LogoutFilter.class));
394+
395+
}
396+
349397
private <T> T getBean(Class<T> clazz) {
350398
return this.spring.getContext().getBean(clazz);
351399
}
@@ -401,6 +449,61 @@ LogoutSuccessHandler logoutSuccessHandler() {
401449

402450
}
403451

452+
@EnableWebSecurity
453+
@Import(Saml2LoginConfigBeans.class)
454+
static class Saml2LogoutWithHttpGet {
455+
456+
LogoutHandler mockLogoutHandler = mock(LogoutHandler.class);
457+
458+
@Bean
459+
SecurityFilterChain web(HttpSecurity http) throws Exception {
460+
// @formatter:off
461+
http
462+
.authorizeRequests((authorize) -> authorize.anyRequest().authenticated())
463+
.logout((logout) -> logout.addLogoutHandler(this.mockLogoutHandler))
464+
.saml2Login(withDefaults())
465+
.saml2Logout((saml2) -> saml2.addObjectPostProcessor(new ObjectPostProcessor<LogoutFilter>() {
466+
@Override
467+
public <O extends LogoutFilter> O postProcess(O filter) {
468+
filter.setLogoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET"));
469+
return filter;
470+
}
471+
}));
472+
return http.build();
473+
// @formatter:on
474+
}
475+
476+
@Bean
477+
LogoutHandler logoutHandler() {
478+
return this.mockLogoutHandler;
479+
}
480+
481+
}
482+
483+
@EnableWebSecurity
484+
@Import(Saml2LoginConfigBeans.class)
485+
static class Saml2DefaultsWithObjectPostProcessorConfig {
486+
487+
static ObjectPostProcessor<Object> objectPostProcessor;
488+
489+
@Bean
490+
SecurityFilterChain web(HttpSecurity http) throws Exception {
491+
// @formatter:off
492+
http
493+
.authorizeRequests((authorize) -> authorize.anyRequest().authenticated())
494+
.saml2Login(withDefaults())
495+
.saml2Logout(withDefaults());
496+
return http.build();
497+
// @formatter:on
498+
}
499+
500+
@Bean
501+
static ObjectPostProcessor<Object> objectPostProcessor() {
502+
return objectPostProcessor;
503+
}
504+
505+
}
506+
404507
@EnableWebSecurity
405508
@Import(Saml2LoginConfigBeans.class)
406509
static class Saml2LogoutComponentsConfig {
@@ -490,4 +593,13 @@ private Consumer<Collection<Saml2X509Credential>> credential(Saml2X509Credential
490593

491594
}
492595

596+
static class ReflectingObjectPostProcessor implements ObjectPostProcessor<Object> {
597+
598+
@Override
599+
public <O> O postProcess(O object) {
600+
return object;
601+
}
602+
603+
}
604+
493605
}

0 commit comments

Comments
 (0)