Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,14 @@ private SecurityContextRepository getSecurityContextRepository(H http) {
return securityContextRepository;
}

private RequestMatcher getLogoutRequestMatcher(H http) {
/**
* Gets the {@link RequestMatcher} that will be used to determine if logout should
* occur.
* @param http the builder to use
* @return the {@link RequestMatcher} that will be used to determine if logout
* should occur
*/
public RequestMatcher getLogoutRequestMatcher(H http) {
if (this.logoutRequestMatcher != null) {
return this.logoutRequestMatcher;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>

private LogoutSuccessHandler logoutSuccessHandler;

private RequestMatcher logoutRequestMatcher;

private LogoutRequestConfigurer logoutRequestConfigurer;

private LogoutResponseConfigurer logoutResponseConfigurer;
Expand Down Expand Up @@ -204,6 +206,7 @@ public void configure(H http) {
if (logout != null) {
this.logoutHandlers = logout.getLogoutHandlers();
this.logoutSuccessHandler = logout.getLogoutSuccessHandler();
this.logoutRequestMatcher = logout.getLogoutRequestMatcher(http);
}
RelyingPartyRegistrationRepository registrations = getRelyingPartyRegistrationRepository(http);
http.addFilterBefore(createLogoutRequestProcessingFilter(registrations), CsrfFilter.class);
Expand Down Expand Up @@ -271,7 +274,8 @@ private Saml2RelyingPartyInitiatedLogoutFilter createRelyingPartyLogoutFilter(
}

private RequestMatcher createLogoutMatcher() {
RequestMatcher logout = getRequestMatcherBuilder().matcher(HttpMethod.POST, this.logoutUrl);
RequestMatcher logout = (this.logoutRequestMatcher != null) ? this.logoutRequestMatcher
: getRequestMatcherBuilder().matcher(HttpMethod.POST, this.logoutUrl);
RequestMatcher saml2 = new Saml2RequestMatcher(getSecurityContextHolderStrategy());
return new AndRequestMatcher(logout, saml2);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,19 @@ public void saml2LogoutWhenDefaultsThenLogsOutAndSendsLogoutRequest() throws Exc
verify(logoutHandler).logout(any(), any(), any());
}

// gh-10821
@Test
public void saml2LogoutWhenLogoutRequestMatcherConfiguredThenUses() throws Exception {
this.spring.register(Saml2LogoutRequestMatcherConfig.class).autowire();
MvcResult result = this.mvc.perform(post("/signout").with(authentication(this.user)).with(csrf()))
.andExpect(status().isFound())
.andReturn();
String location = result.getResponse().getHeader("Location");
LogoutHandler logoutHandler = this.spring.getContext().getBean(LogoutHandler.class);
assertThat(location).startsWith("https://ap.example.org/logout/saml2/request");
verify(logoutHandler).logout(any(), any(), any());
}

// gh-19128
@Test
public void saml2LogoutWhenBuilderBeanWithBasePathThenLogoutUrlIgnoresBasePath() throws Exception {
Expand Down Expand Up @@ -644,6 +657,35 @@ LogoutSuccessHandler logoutSuccessHandler() {

}

@Configuration
@EnableWebSecurity
@Import(Saml2LoginConfigBeans.class)
static class Saml2LogoutRequestMatcherConfig {

LogoutHandler mockLogoutHandler = mock(LogoutHandler.class);

@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
.logout((logout) -> logout
.logoutRequestMatcher(pathPattern(HttpMethod.POST, "/signout"))
.addLogoutHandler(this.mockLogoutHandler)
)
.saml2Login(withDefaults())
.saml2Logout(withDefaults());
return http.build();
// @formatter:on
}

@Bean
LogoutHandler logoutHandler() {
return this.mockLogoutHandler;
}

}

@Configuration
@EnableWebSecurity
@Import(Saml2LoginConfigBeans.class)
Expand Down