|
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 javax.servlet.http.Cookie;
|
| 22 | +import javax.servlet.http.HttpServletRequest; |
| 23 | +import javax.servlet.http.HttpServletResponse; |
22 | 24 | import javax.servlet.http.HttpSession;
|
23 | 25 |
|
24 | 26 | import org.junit.jupiter.api.Test;
|
|
38 | 40 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
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;
|
|
60 | 66 | import static org.mockito.BDDMockito.given;
|
61 | 67 | import static org.mockito.Mockito.atLeastOnce;
|
62 | 68 | import static org.mockito.Mockito.mock;
|
| 69 | +import static org.mockito.Mockito.reset; |
63 | 70 | import static org.mockito.Mockito.spy;
|
64 | 71 | import static org.mockito.Mockito.verify;
|
65 | 72 | import static org.springframework.security.config.Customizer.withDefaults;
|
@@ -303,6 +310,24 @@ public void getWhenRememberMeCookieAndNoKeyConfiguredThenKeyFromRememberMeServic
|
303 | 310 | this.mvc.perform(requestWithRememberme).andExpect(remembermeAuthentication);
|
304 | 311 | }
|
305 | 312 |
|
| 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 | + |
306 | 331 | @EnableWebSecurity
|
307 | 332 | static class NullUserDetailsConfig extends WebSecurityConfigurerAdapter {
|
308 | 333 |
|
@@ -582,4 +607,57 @@ protected void configure(HttpSecurity http) throws Exception {
|
582 | 607 |
|
583 | 608 | }
|
584 | 609 |
|
| 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 | + |
585 | 663 | }
|
0 commit comments