Skip to content

Commit 5814f61

Browse files
committed
Merge branch '6.0.x'
Closes gh-13128
2 parents 5af8f8d + 46ad9c1 commit 5814f61

File tree

2 files changed

+85
-2
lines changed

2 files changed

+85
-2
lines changed

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

Lines changed: 8 additions & 1 deletion
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-2023 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.
@@ -35,6 +35,7 @@
3535
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter;
3636
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
3737
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
38+
import org.springframework.security.web.context.SecurityContextRepository;
3839
import org.springframework.util.Assert;
3940

4041
/**
@@ -288,6 +289,12 @@ public void configure(H http) {
288289
if (this.authenticationSuccessHandler != null) {
289290
rememberMeFilter.setAuthenticationSuccessHandler(this.authenticationSuccessHandler);
290291
}
292+
SecurityContextConfigurer<?> securityContextConfigurer = http.getConfigurer(SecurityContextConfigurer.class);
293+
if (securityContextConfigurer != null && securityContextConfigurer.isRequireExplicitSave()) {
294+
SecurityContextRepository securityContextRepository = securityContextConfigurer
295+
.getSecurityContextRepository();
296+
rememberMeFilter.setSecurityContextRepository(securityContextRepository);
297+
}
291298
rememberMeFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
292299
rememberMeFilter = postProcess(rememberMeFilter);
293300
http.addFilter(rememberMeFilter);

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

Lines changed: 77 additions & 1 deletion
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-2023 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.
@@ -19,6 +19,8 @@
1919
import java.util.Collections;
2020

2121
import jakarta.servlet.http.Cookie;
22+
import jakarta.servlet.http.HttpServletRequest;
23+
import jakarta.servlet.http.HttpServletResponse;
2224
import jakarta.servlet.http.HttpSession;
2325
import org.junit.jupiter.api.Test;
2426
import org.junit.jupiter.api.extension.ExtendWith;
@@ -38,6 +40,7 @@
3840
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
3941
import org.springframework.security.config.test.SpringTestContext;
4042
import org.springframework.security.config.test.SpringTestContextExtension;
43+
import org.springframework.security.core.context.SecurityContext;
4144
import org.springframework.security.core.context.SecurityContextHolderStrategy;
4245
import org.springframework.security.core.userdetails.PasswordEncodedUser;
4346
import org.springframework.security.core.userdetails.User;
@@ -48,6 +51,9 @@
4851
import org.springframework.security.web.authentication.RememberMeServices;
4952
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter;
5053
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
54+
import org.springframework.security.web.context.HttpRequestResponseHolder;
55+
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
56+
import org.springframework.security.web.context.SecurityContextRepository;
5157
import org.springframework.test.web.servlet.MockMvc;
5258
import org.springframework.test.web.servlet.MvcResult;
5359
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
@@ -59,6 +65,7 @@
5965
import static org.mockito.BDDMockito.given;
6066
import static org.mockito.Mockito.atLeastOnce;
6167
import static org.mockito.Mockito.mock;
68+
import static org.mockito.Mockito.reset;
6269
import static org.mockito.Mockito.spy;
6370
import static org.mockito.Mockito.verify;
6471
import static org.springframework.security.config.Customizer.withDefaults;
@@ -294,6 +301,24 @@ public void getWhenRememberMeCookieAndNoKeyConfiguredThenKeyFromRememberMeServic
294301
this.mvc.perform(requestWithRememberme).andExpect(remembermeAuthentication);
295302
}
296303

304+
// gh-13104
305+
@Test
306+
public void getWhenCustomSecurityContextRepositoryThenUses() throws Exception {
307+
this.spring.register(SecurityContextRepositoryConfig.class).autowire();
308+
SecurityContextRepository repository = this.spring.getContext().getBean(SecurityContextRepository.class);
309+
MvcResult mvcResult = this.mvc.perform(post("/login").with(csrf()).param("username", "user")
310+
.param("password", "password").param("remember-me", "true")).andReturn();
311+
Cookie rememberMeCookie = mvcResult.getResponse().getCookie("remember-me");
312+
reset(repository);
313+
// @formatter:off
314+
MockHttpServletRequestBuilder request = get("/abc").cookie(rememberMeCookie);
315+
SecurityMockMvcResultMatchers.AuthenticatedMatcher remembermeAuthentication = authenticated()
316+
.withAuthentication((auth) -> assertThat(auth).isInstanceOf(RememberMeAuthenticationToken.class));
317+
// @formatter:on
318+
this.mvc.perform(request).andExpect(remembermeAuthentication);
319+
verify(repository).saveContext(any(), any(), any());
320+
}
321+
297322
@Configuration
298323
@EnableWebSecurity
299324
static class NullUserDetailsConfig {
@@ -577,4 +602,55 @@ SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
577602

578603
}
579604

605+
@Configuration
606+
@EnableWebSecurity
607+
static class SecurityContextRepositoryConfig {
608+
609+
private SecurityContextRepository repository = spy(new SpySecurityContextRepository());
610+
611+
@Bean
612+
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
613+
// @formatter:off
614+
http
615+
.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
616+
.securityContext((context) -> context.securityContextRepository(this.repository))
617+
.formLogin(withDefaults())
618+
.rememberMe(withDefaults());
619+
return http.build();
620+
// @formatter:on
621+
}
622+
623+
@Bean
624+
SecurityContextRepository securityContextRepository() {
625+
return this.repository;
626+
}
627+
628+
@Bean
629+
UserDetailsService userDetailsService() {
630+
return new InMemoryUserDetailsManager(PasswordEncodedUser.user());
631+
}
632+
633+
private static class SpySecurityContextRepository implements SecurityContextRepository {
634+
635+
SecurityContextRepository delegate = new HttpSessionSecurityContextRepository();
636+
637+
@Override
638+
public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
639+
return this.delegate.loadContext(requestResponseHolder);
640+
}
641+
642+
@Override
643+
public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) {
644+
this.delegate.saveContext(context, request, response);
645+
}
646+
647+
@Override
648+
public boolean containsContext(HttpServletRequest request) {
649+
return this.delegate.containsContext(request);
650+
}
651+
652+
}
653+
654+
}
655+
580656
}

0 commit comments

Comments
 (0)