|
1 | 1 | /*
|
2 |
| - * Copyright 2002-2022 the original author or authors. |
| 2 | + * Copyright 2002-2023 the original author or authors. |
3 | 3 | *
|
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | 5 | * you may not use this file except in compliance with the License.
|
|
19 | 19 | import java.util.Collections;
|
20 | 20 |
|
21 | 21 | import jakarta.servlet.http.Cookie;
|
| 22 | +import jakarta.servlet.http.HttpServletRequest; |
| 23 | +import jakarta.servlet.http.HttpServletResponse; |
22 | 24 | import jakarta.servlet.http.HttpSession;
|
23 | 25 | import org.junit.jupiter.api.Test;
|
24 | 26 | import org.junit.jupiter.api.extension.ExtendWith;
|
|
38 | 40 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
39 | 41 | import org.springframework.security.config.test.SpringTestContext;
|
40 | 42 | import org.springframework.security.config.test.SpringTestContextExtension;
|
| 43 | +import org.springframework.security.core.context.SecurityContext; |
41 | 44 | import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
42 | 45 | import org.springframework.security.core.userdetails.PasswordEncodedUser;
|
43 | 46 | import org.springframework.security.core.userdetails.User;
|
|
48 | 51 | import org.springframework.security.web.authentication.RememberMeServices;
|
49 | 52 | import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter;
|
50 | 53 | 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; |
51 | 57 | import org.springframework.test.web.servlet.MockMvc;
|
52 | 58 | import org.springframework.test.web.servlet.MvcResult;
|
53 | 59 | import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
|
59 | 65 | import static org.mockito.BDDMockito.given;
|
60 | 66 | import static org.mockito.Mockito.atLeastOnce;
|
61 | 67 | import static org.mockito.Mockito.mock;
|
| 68 | +import static org.mockito.Mockito.reset; |
62 | 69 | import static org.mockito.Mockito.spy;
|
63 | 70 | import static org.mockito.Mockito.verify;
|
64 | 71 | import static org.springframework.security.config.Customizer.withDefaults;
|
@@ -294,6 +301,24 @@ public void getWhenRememberMeCookieAndNoKeyConfiguredThenKeyFromRememberMeServic
|
294 | 301 | this.mvc.perform(requestWithRememberme).andExpect(remembermeAuthentication);
|
295 | 302 | }
|
296 | 303 |
|
| 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 | + |
297 | 322 | @Configuration
|
298 | 323 | @EnableWebSecurity
|
299 | 324 | static class NullUserDetailsConfig {
|
@@ -577,4 +602,55 @@ SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
577 | 602 |
|
578 | 603 | }
|
579 | 604 |
|
| 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 | + |
580 | 656 | }
|
0 commit comments