Skip to content

Commit 05cb2a0

Browse files
committed
Add Support for Changing Session Cookie Name
Issue gh-14904
1 parent b129a74 commit 05cb2a0

File tree

2 files changed

+102
-0
lines changed

2 files changed

+102
-0
lines changed

config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5672,6 +5672,8 @@ public final class SessionLogoutConfigurer {
56725672

56735673
private String logoutUri = "{baseScheme}://localhost{basePort}/logout/connect/back-channel/{registrationId}";
56745674

5675+
private String cookieName = "SESSION";
5676+
56755677
private SessionLogoutConfigurer() {
56765678

56775679
}
@@ -5703,10 +5705,30 @@ public SessionLogoutConfigurer uri(String uri) {
57035705
return this;
57045706
}
57055707

5708+
/**
5709+
* Use this cookie name to propagate the internal session identifier in
5710+
* the internal logout invocation.
5711+
*
5712+
* <p>
5713+
* This defaults to {@code JSESSIONID}.
5714+
*
5715+
* <p>
5716+
* When using Spring Session, you may need to set this to {@code SESSION}
5717+
* @param cookieName the cookie name to use
5718+
* @return the
5719+
* {@link OidcLogoutConfigurer.BackChannelLogoutConfigurer.SessionLogoutConfigurer}
5720+
* for further customizations
5721+
*/
5722+
public SessionLogoutConfigurer cookieName(String cookieName) {
5723+
this.cookieName = cookieName;
5724+
return this;
5725+
}
5726+
57065727
private ServerLogoutHandler configure() {
57075728
OidcBackChannelServerLogoutHandler logoutHandler = new OidcBackChannelServerLogoutHandler();
57085729
logoutHandler.setSessionRegistry(OidcLogoutSpec.this.getSessionRegistry());
57095730
logoutHandler.setLogoutUri(this.logoutUri);
5731+
logoutHandler.setSessionCookieName(this.cookieName);
57105732
return logoutHandler;
57115733
}
57125734

config/src/test/java/org/springframework/security/config/web/server/OidcLogoutSpecTests.java

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.ArrayList;
2626
import java.util.List;
2727
import java.util.Map;
28+
import java.util.function.Consumer;
2829

2930
import com.nimbusds.jose.jwk.JWKSet;
3031
import com.nimbusds.jose.jwk.RSAKey;
@@ -96,6 +97,7 @@
9697
import org.springframework.web.server.WebSession;
9798
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
9899

100+
import static org.assertj.core.api.Assertions.assertThat;
99101
import static org.hamcrest.Matchers.containsString;
100102
import static org.mockito.ArgumentMatchers.any;
101103
import static org.mockito.BDDMockito.given;
@@ -291,6 +293,29 @@ void logoutWhenSelfRemoteLogoutUriThenUses() {
291293
this.test.get().uri("/token/logout").cookie("SESSION", sessionId).exchange().expectStatus().isUnauthorized();
292294
}
293295

296+
@Test
297+
void logoutWhenDifferentCookieNameThenUses() {
298+
this.spring.register(OidcProviderConfig.class, CookieConfig.class).autowire();
299+
String registrationId = this.clientRegistration.getRegistrationId();
300+
String sessionId = login();
301+
String logoutToken = this.test.get()
302+
.uri("/token/logout")
303+
.cookie("SESSION", sessionId)
304+
.exchange()
305+
.expectStatus()
306+
.isOk()
307+
.returnResult(String.class)
308+
.getResponseBody()
309+
.blockFirst();
310+
this.test.post()
311+
.uri(this.web.url("/logout/connect/back-channel/" + registrationId).toString())
312+
.body(BodyInserters.fromFormData("logout_token", logoutToken))
313+
.exchange()
314+
.expectStatus()
315+
.isOk();
316+
this.test.get().uri("/token/logout").cookie("SESSION", sessionId).exchange().expectStatus().isUnauthorized();
317+
}
318+
294319
@Test
295320
void logoutWhenRemoteLogoutFailsThenReportsPartialLogout() {
296321
this.spring.register(WebServerConfig.class, OidcProviderConfig.class, WithBrokenLogoutConfig.class).autowire();
@@ -491,6 +516,51 @@ SecurityWebFilterChain filters(ServerHttpSecurity http) throws Exception {
491516

492517
}
493518

519+
@Configuration
520+
@EnableWebFluxSecurity
521+
@Import(RegistrationConfig.class)
522+
static class CookieConfig {
523+
524+
private final MockWebServer server = new MockWebServer();
525+
526+
@Bean
527+
@Order(1)
528+
SecurityWebFilterChain filters(ServerHttpSecurity http) throws Exception {
529+
// @formatter:off
530+
http
531+
.authorizeExchange((authorize) -> authorize.anyExchange().authenticated())
532+
.oauth2Login(Customizer.withDefaults())
533+
.oidcLogout((oidc) -> oidc
534+
.backChannel((backchannel) -> backchannel
535+
.sessionLogout((logout) -> logout.cookieName("JSESSIONID"))
536+
)
537+
);
538+
// @formatter:on
539+
540+
return http.build();
541+
}
542+
543+
@Bean
544+
MockWebServer web(ObjectProvider<WebTestClient> web) {
545+
WebTestClientDispatcher dispatcher = new WebTestClientDispatcher(web);
546+
dispatcher.setAssertion((rr) -> {
547+
String cookie = rr.getHeaders().get("Cookie");
548+
if (cookie == null) {
549+
return;
550+
}
551+
assertThat(cookie).contains("JSESSIONID");
552+
});
553+
this.server.setDispatcher(dispatcher);
554+
return this.server;
555+
}
556+
557+
@PreDestroy
558+
void shutdown() throws IOException {
559+
this.server.shutdown();
560+
}
561+
562+
}
563+
494564
@Configuration
495565
@EnableWebFluxSecurity
496566
@Import(RegistrationConfig.class)
@@ -699,12 +769,15 @@ private static class WebTestClientDispatcher extends Dispatcher {
699769

700770
private WebTestClient web;
701771

772+
private Consumer<RecordedRequest> assertion = (rr) -> { };
773+
702774
WebTestClientDispatcher(ObjectProvider<WebTestClient> web) {
703775
this.webProvider = web;
704776
}
705777

706778
@Override
707779
public MockResponse dispatch(RecordedRequest request) throws InterruptedException {
780+
this.assertion.accept(request);
708781
this.web = this.webProvider.getObject();
709782
String method = request.getMethod();
710783
String path = request.getPath();
@@ -747,6 +820,10 @@ public MockResponse dispatch(RecordedRequest request) throws InterruptedExceptio
747820
}
748821
}
749822

823+
void setAssertion(Consumer<RecordedRequest> assertion) {
824+
this.assertion = assertion;
825+
}
826+
750827
private String session(RecordedRequest request) {
751828
String cookieHeaderValue = request.getHeader("Cookie");
752829
if (cookieHeaderValue == null) {
@@ -758,6 +835,9 @@ private String session(RecordedRequest request) {
758835
if (SESSION_COOKIE_NAME.equals(parts[0])) {
759836
return parts[1];
760837
}
838+
if ("JSESSIONID".equals(parts[0])) {
839+
return parts[1];
840+
}
761841
}
762842
return null;
763843
}

0 commit comments

Comments
 (0)