Skip to content

Commit e9a02bc

Browse files
committed
RememberMeConfigurer Picks Up SecurityContextRepository
Closes gh-13104
1 parent 6d37ca1 commit e9a02bc

File tree

2 files changed

+87
-2
lines changed

2 files changed

+87
-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: 79 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 javax.servlet.http.Cookie;
22+
import javax.servlet.http.HttpServletRequest;
23+
import javax.servlet.http.HttpServletResponse;
2224
import javax.servlet.http.HttpSession;
2325

2426
import org.junit.jupiter.api.Test;
@@ -38,6 +40,7 @@
3840
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
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;
@@ -60,6 +66,7 @@
6066
import static org.mockito.BDDMockito.given;
6167
import static org.mockito.Mockito.atLeastOnce;
6268
import static org.mockito.Mockito.mock;
69+
import static org.mockito.Mockito.reset;
6370
import static org.mockito.Mockito.spy;
6471
import static org.mockito.Mockito.verify;
6572
import static org.springframework.security.config.Customizer.withDefaults;
@@ -303,6 +310,24 @@ public void getWhenRememberMeCookieAndNoKeyConfiguredThenKeyFromRememberMeServic
303310
this.mvc.perform(requestWithRememberme).andExpect(remembermeAuthentication);
304311
}
305312

313+
// gh-13104
314+
@Test
315+
public void getWhenCustomSecurityContextRepositoryThenUses() throws Exception {
316+
this.spring.register(SecurityContextRepositoryConfig.class).autowire();
317+
SecurityContextRepository repository = this.spring.getContext().getBean(SecurityContextRepository.class);
318+
MvcResult mvcResult = this.mvc.perform(post("/login").with(csrf()).param("username", "user")
319+
.param("password", "password").param("remember-me", "true")).andReturn();
320+
Cookie rememberMeCookie = mvcResult.getResponse().getCookie("remember-me");
321+
reset(repository);
322+
// @formatter:off
323+
MockHttpServletRequestBuilder request = get("/abc").cookie(rememberMeCookie);
324+
SecurityMockMvcResultMatchers.AuthenticatedMatcher remembermeAuthentication = authenticated()
325+
.withAuthentication((auth) -> assertThat(auth).isInstanceOf(RememberMeAuthenticationToken.class));
326+
// @formatter:on
327+
this.mvc.perform(request).andExpect(remembermeAuthentication);
328+
verify(repository).saveContext(any(), any(), any());
329+
}
330+
306331
@EnableWebSecurity
307332
static class NullUserDetailsConfig extends WebSecurityConfigurerAdapter {
308333

@@ -582,4 +607,57 @@ protected void configure(HttpSecurity http) throws Exception {
582607

583608
}
584609

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

0 commit comments

Comments
 (0)