Skip to content

Commit 4b29450

Browse files
committed
Add Saml2LogoutConfigurer
Closes gh-9497
1 parent d5d5911 commit 4b29450

File tree

7 files changed

+1313
-155
lines changed

7 files changed

+1313
-155
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
7373
import org.springframework.security.config.annotation.web.configurers.openid.OpenIDLoginConfigurer;
7474
import org.springframework.security.config.annotation.web.configurers.saml2.Saml2LoginConfigurer;
75+
import org.springframework.security.config.annotation.web.configurers.saml2.Saml2LogoutConfigurer;
7576
import org.springframework.security.core.Authentication;
7677
import org.springframework.security.core.context.SecurityContext;
7778
import org.springframework.security.core.context.SecurityContextHolder;
@@ -2209,6 +2210,143 @@ public HttpSecurity saml2Login(Customizer<Saml2LoginConfigurer<HttpSecurity>> sa
22092210
return HttpSecurity.this;
22102211
}
22112212

2213+
/**
2214+
* Configures logout support for an SAML 2.0 Relying Party. <br>
2215+
* <br>
2216+
*
2217+
* Implements the <b>Single Logout Profile, using POST and REDIRECT bindings</b>, as
2218+
* documented in the
2219+
* <a target="_blank" href="https://docs.oasis-open.org/security/saml/">SAML V2.0
2220+
* Core, Profiles and Bindings</a> specifications. <br>
2221+
* <br>
2222+
*
2223+
* As a prerequisite to using this feature, is that you have a SAML v2.0 Asserting
2224+
* Party to sent a logout request to. The representation of the relying party and the
2225+
* asserting party is contained within {@link RelyingPartyRegistration}. <br>
2226+
* <br>
2227+
*
2228+
* {@link RelyingPartyRegistration}(s) are composed within a
2229+
* {@link RelyingPartyRegistrationRepository}, which is <b>required</b> and must be
2230+
* registered with the {@link ApplicationContext} or configured via
2231+
* {@link #saml2Login(Customizer)}.<br>
2232+
* <br>
2233+
*
2234+
* The default configuration provides an auto-generated logout endpoint at
2235+
* <code>&quot;/logout&quot;</code> and redirects to <code>/login?logout</code> when
2236+
* logout completes. <br>
2237+
* <br>
2238+
*
2239+
* <p>
2240+
* <h2>Example Configuration</h2>
2241+
*
2242+
* The following example shows the minimal configuration required, using a
2243+
* hypothetical asserting party.
2244+
*
2245+
* <pre>
2246+
* &#064;EnableWebSecurity
2247+
* &#064;Configuration
2248+
* public class Saml2LogoutSecurityConfig {
2249+
* &#064;Bean
2250+
* public SecurityFilterChain web(HttpSecurity http) throws Exception {
2251+
* http
2252+
* .authorizeRequests((authorize) -> authorize
2253+
* .anyRequest().authenticated()
2254+
* )
2255+
* .saml2Login(withDefaults())
2256+
* .saml2Logout(withDefaults());
2257+
* return http.build();
2258+
* }
2259+
*
2260+
* &#064;Bean
2261+
* public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() {
2262+
* RelyingPartyRegistration registration = RelyingPartyRegistrations
2263+
* .withMetadataLocation("https://ap.example.org/metadata")
2264+
* .registrationId("simple")
2265+
* .build();
2266+
* return new InMemoryRelyingPartyRegistrationRepository(registration);
2267+
* }
2268+
* }
2269+
* </pre>
2270+
*
2271+
* <p>
2272+
* @return the {@link HttpSecurity} for further customizations
2273+
* @throws Exception
2274+
* @since 5.6
2275+
*/
2276+
public HttpSecurity saml2Logout(Customizer<Saml2LogoutConfigurer<HttpSecurity>> saml2LogoutCustomizer)
2277+
throws Exception {
2278+
saml2LogoutCustomizer.customize(getOrApply(new Saml2LogoutConfigurer<>(getContext())));
2279+
return HttpSecurity.this;
2280+
}
2281+
2282+
/**
2283+
* Configures logout support for an SAML 2.0 Relying Party. <br>
2284+
* <br>
2285+
*
2286+
* Implements the <b>Single Logout Profile, using POST and REDIRECT bindings</b>, as
2287+
* documented in the
2288+
* <a target="_blank" href="https://docs.oasis-open.org/security/saml/">SAML V2.0
2289+
* Core, Profiles and Bindings</a> specifications. <br>
2290+
* <br>
2291+
*
2292+
* As a prerequisite to using this feature, is that you have a SAML v2.0 Asserting
2293+
* Party to sent a logout request to. The representation of the relying party and the
2294+
* asserting party is contained within {@link RelyingPartyRegistration}. <br>
2295+
* <br>
2296+
*
2297+
* {@link RelyingPartyRegistration}(s) are composed within a
2298+
* {@link RelyingPartyRegistrationRepository}, which is <b>required</b> and must be
2299+
* registered with the {@link ApplicationContext} or configured via
2300+
* {@link #saml2Login()}.<br>
2301+
* <br>
2302+
*
2303+
* The default configuration provides an auto-generated logout endpoint at
2304+
* <code>&quot;/logout&quot;</code> and redirects to <code>/login?logout</code> when
2305+
* logout completes. <br>
2306+
* <br>
2307+
*
2308+
* <p>
2309+
* <h2>Example Configuration</h2>
2310+
*
2311+
* The following example shows the minimal configuration required, using a
2312+
* hypothetical asserting party.
2313+
*
2314+
* <pre>
2315+
* &#064;EnableWebSecurity
2316+
* &#064;Configuration
2317+
* public class Saml2LogoutSecurityConfig {
2318+
* &#064;Bean
2319+
* public SecurityFilterChain web(HttpSecurity http) throws Exception {
2320+
* http
2321+
* .authorizeRequests()
2322+
* .anyRequest().authenticated()
2323+
* .and()
2324+
* .saml2Login()
2325+
* .and()
2326+
* .saml2Logout();
2327+
* return http.build();
2328+
* }
2329+
*
2330+
* &#064;Bean
2331+
* public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() {
2332+
* RelyingPartyRegistration registration = RelyingPartyRegistrations
2333+
* .withMetadataLocation("https://ap.example.org/metadata")
2334+
* .registrationId("simple")
2335+
* .build();
2336+
* return new InMemoryRelyingPartyRegistrationRepository(registration);
2337+
* }
2338+
* }
2339+
* </pre>
2340+
*
2341+
* <p>
2342+
* @return the {@link Saml2LoginConfigurer} for further customizations
2343+
* @throws Exception
2344+
* @since 5.6
2345+
*/
2346+
public Saml2LogoutConfigurer<HttpSecurity> saml2Logout() throws Exception {
2347+
return getOrApply(new Saml2LogoutConfigurer<>(getContext()));
2348+
}
2349+
22122350
/**
22132351
* Configures authentication support using an OAuth 2.0 and/or OpenID Connect 1.0
22142352
* Provider. <br>

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,10 +250,11 @@ public LogoutConfigurer<H> permitAll(boolean permitAll) {
250250
* {@link SimpleUrlLogoutSuccessHandler} using the {@link #logoutSuccessUrl(String)}.
251251
* @return the {@link LogoutSuccessHandler} to use
252252
*/
253-
private LogoutSuccessHandler getLogoutSuccessHandler() {
253+
public LogoutSuccessHandler getLogoutSuccessHandler() {
254254
LogoutSuccessHandler handler = this.logoutSuccessHandler;
255255
if (handler == null) {
256256
handler = createDefaultSuccessHandler();
257+
this.logoutSuccessHandler = handler;
257258
}
258259
return handler;
259260
}
@@ -312,7 +313,7 @@ private String getLogoutSuccessUrl() {
312313
* Gets the {@link LogoutHandler} instances that will be used.
313314
* @return the {@link LogoutHandler} instances. Cannot be null.
314315
*/
315-
List<LogoutHandler> getLogoutHandlers() {
316+
public List<LogoutHandler> getLogoutHandlers() {
316317
return this.logoutHandlers;
317318
}
318319

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,7 @@ protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingU
205205
@Override
206206
public void init(B http) throws Exception {
207207
registerDefaultCsrfOverride(http);
208-
if (this.relyingPartyRegistrationRepository == null) {
209-
this.relyingPartyRegistrationRepository = getSharedOrBean(http, RelyingPartyRegistrationRepository.class);
210-
}
208+
relyingPartyRegistrationRepository(http);
211209
this.saml2WebSsoAuthenticationFilter = new Saml2WebSsoAuthenticationFilter(getAuthenticationConverter(http),
212210
this.loginProcessingUrl);
213211
setAuthenticationRequestRepository(http, this.saml2WebSsoAuthenticationFilter);
@@ -257,6 +255,13 @@ public void configure(B http) throws Exception {
257255
}
258256
}
259257

258+
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository(B http) {
259+
if (this.relyingPartyRegistrationRepository == null) {
260+
this.relyingPartyRegistrationRepository = getSharedOrBean(http, RelyingPartyRegistrationRepository.class);
261+
}
262+
return this.relyingPartyRegistrationRepository;
263+
}
264+
260265
private void setAuthenticationRequestRepository(B http,
261266
Saml2WebSsoAuthenticationFilter saml2WebSsoAuthenticationFilter) {
262267
saml2WebSsoAuthenticationFilter.setAuthenticationRequestRepository(getAuthenticationRequestRepository(http));

0 commit comments

Comments
 (0)