Use SecurityContextHolderStrategy for Remember-me
Issue gh-11060 Isuse gh-11061
This commit is contained in:
+1
@@ -293,6 +293,7 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
if (this.authenticationSuccessHandler != null) {
|
||||
rememberMeFilter.setAuthenticationSuccessHandler(this.authenticationSuccessHandler);
|
||||
}
|
||||
rememberMeFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
||||
rememberMeFilter = postProcess(rememberMeFilter);
|
||||
http.addFilter(rememberMeFilter);
|
||||
}
|
||||
|
||||
+4
-3
@@ -228,7 +228,7 @@ final class AuthenticationConfigBuilder {
|
||||
this.portResolver = portResolver;
|
||||
this.csrfLogoutHandler = csrfLogoutHandler;
|
||||
createAnonymousFilter(authenticationFilterSecurityContextHolderStrategyRef);
|
||||
createRememberMeFilter(authenticationManager);
|
||||
createRememberMeFilter(authenticationManager, authenticationFilterSecurityContextHolderStrategyRef);
|
||||
createBasicFilter(authenticationManager, authenticationFilterSecurityContextHolderStrategyRef);
|
||||
createBearerTokenAuthenticationFilter(authenticationManager);
|
||||
createFormLoginFilter(sessionStrategy, authenticationManager,
|
||||
@@ -245,7 +245,8 @@ final class AuthenticationConfigBuilder {
|
||||
createExceptionTranslationFilter(authenticationFilterSecurityContextHolderStrategyRef);
|
||||
}
|
||||
|
||||
void createRememberMeFilter(BeanReference authenticationManager) {
|
||||
void createRememberMeFilter(BeanReference authenticationManager,
|
||||
BeanMetadataElement authenticationFilterSecurityContextHolderStrategyRef) {
|
||||
// Parse remember me before logout as RememberMeServices is also a LogoutHandler
|
||||
// implementation.
|
||||
Element rememberMeElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.REMEMBER_ME);
|
||||
@@ -255,7 +256,7 @@ final class AuthenticationConfigBuilder {
|
||||
key = createKey();
|
||||
}
|
||||
RememberMeBeanDefinitionParser rememberMeParser = new RememberMeBeanDefinitionParser(key,
|
||||
authenticationManager);
|
||||
authenticationManager, authenticationFilterSecurityContextHolderStrategyRef);
|
||||
this.rememberMeFilter = rememberMeParser.parse(rememberMeElt, this.pc);
|
||||
this.rememberMeServicesId = rememberMeParser.getRememberMeServicesId();
|
||||
createRememberMeProvider(key);
|
||||
|
||||
+8
-1
@@ -20,6 +20,7 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanReference;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
@@ -70,11 +71,15 @@ class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
private final BeanReference authenticationManager;
|
||||
|
||||
private final BeanMetadataElement authenticationFilterSecurityContextHolderStrategyRef;
|
||||
|
||||
private String rememberMeServicesId;
|
||||
|
||||
RememberMeBeanDefinitionParser(String key, BeanReference authenticationManager) {
|
||||
RememberMeBeanDefinitionParser(String key, BeanReference authenticationManager,
|
||||
BeanMetadataElement authenticationFilterSecurityContextHolderStrategyRef) {
|
||||
this.key = key;
|
||||
this.authenticationManager = authenticationManager;
|
||||
this.authenticationFilterSecurityContextHolderStrategyRef = authenticationFilterSecurityContextHolderStrategyRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -175,6 +180,8 @@ class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
filter.addConstructorArgValue(this.authenticationManager);
|
||||
filter.addConstructorArgReference(servicesName);
|
||||
filter.addPropertyValue("securityContextHolderStrategy",
|
||||
this.authenticationFilterSecurityContextHolderStrategyRef);
|
||||
pc.popAndRegisterContainingComponent();
|
||||
return filter.getBeanDefinition();
|
||||
}
|
||||
|
||||
+24
-5
@@ -30,12 +30,14 @@ import org.springframework.mock.web.MockHttpSession;
|
||||
import org.springframework.security.authentication.RememberMeAuthenticationToken;
|
||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.core.userdetails.PasswordEncodedUser;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
@@ -55,6 +57,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -100,7 +103,8 @@ public class RememberMeConfigurerTests {
|
||||
@Test
|
||||
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnRememberMeAuthenticationFilter() {
|
||||
this.spring.register(ObjectPostProcessorConfig.class).autowire();
|
||||
verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(RememberMeAuthenticationFilter.class));
|
||||
verify(this.spring.getContext().getBean(ObjectPostProcessor.class))
|
||||
.postProcess(any(RememberMeAuthenticationFilter.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -131,6 +135,21 @@ public class RememberMeConfigurerTests {
|
||||
this.mvc.perform(request).andExpect(remembermeAuthentication);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rememberMeWhenCustomSecurityContextHolderStrategyThenUses() throws Exception {
|
||||
this.spring.register(UserDetailsServiceBeanConfig.class, SecurityContextChangedListenerConfig.class).autowire();
|
||||
MvcResult mvcResult = this.mvc.perform(post("/login").with(csrf()).param("username", "user")
|
||||
.param("password", "password").param("remember-me", "true")).andReturn();
|
||||
Cookie rememberMeCookie = mvcResult.getResponse().getCookie("remember-me");
|
||||
// @formatter:off
|
||||
MockHttpServletRequestBuilder request = get("/abc").cookie(rememberMeCookie);
|
||||
SecurityMockMvcResultMatchers.AuthenticatedMatcher remembermeAuthentication = authenticated()
|
||||
.withAuthentication((auth) -> assertThat(auth).isInstanceOf(RememberMeAuthenticationToken.class));
|
||||
// @formatter:on
|
||||
this.mvc.perform(request).andExpect(remembermeAuthentication);
|
||||
verify(this.spring.getContext().getBean(SecurityContextHolderStrategy.class), atLeastOnce()).getContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loginWhenRememberMeTrueThenRespondsWithRememberMeCookie() throws Exception {
|
||||
this.spring.register(RememberMeConfig.class).autowire();
|
||||
@@ -315,14 +334,14 @@ public class RememberMeConfigurerTests {
|
||||
@EnableWebSecurity
|
||||
static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
static ObjectPostProcessor<Object> objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
|
||||
ObjectPostProcessor<Object> objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.rememberMe()
|
||||
.userDetailsService(new AuthenticationManagerBuilder(objectPostProcessor).getDefaultUserDetailsService());
|
||||
.userDetailsService(new AuthenticationManagerBuilder(this.objectPostProcessor).getDefaultUserDetailsService());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@@ -335,8 +354,8 @@ public class RememberMeConfigurerTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
static ObjectPostProcessor<Object> objectPostProcessor() {
|
||||
return objectPostProcessor;
|
||||
ObjectPostProcessor<Object> objectPostProcessor() {
|
||||
return this.objectPostProcessor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+13
@@ -29,6 +29,7 @@ import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.security.TestDataSource;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
|
||||
@@ -219,6 +220,18 @@ public class RememberMeConfigTests {
|
||||
() -> this.spring.configLocations(xml("NegativeTokenValidityWithPersistentRepository")).autowire());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rememberMeWhenCustomSecurityContextHolderStrategyThenUses() throws Exception {
|
||||
this.spring.configLocations(xml("WithSecurityContextHolderStrategy")).autowire();
|
||||
MvcResult result = rememberAuthentication("user", "password").andReturn();
|
||||
Cookie cookie = rememberMeCookie(result);
|
||||
// @formatter:off
|
||||
this.mvc.perform(get("/authenticated").cookie(cookie))
|
||||
.andExpect(status().isOk());
|
||||
// @formatter:on
|
||||
verify(this.spring.getContext().getBean(SecurityContextHolderStrategy.class), atLeastOnce()).getContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWithRememberMeWhenUsingCustomUserDetailsServiceThenInvokesThisUserDetailsService()
|
||||
throws Exception {
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2002-2018 the original author or authors.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ https://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://www.springframework.org/schema/security"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/security
|
||||
https://www.springframework.org/schema/security/spring-security.xsd
|
||||
http://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<http auto-config="true" security-context-holder-strategy-ref="ref">
|
||||
<intercept-url pattern="/authenticated" access="authenticated"/>
|
||||
<remember-me/>
|
||||
</http>
|
||||
|
||||
<b:bean id="ref" class="org.mockito.Mockito" factory-method="spy">
|
||||
<b:constructor-arg>
|
||||
<b:bean class="org.springframework.security.config.MockSecurityContextHolderStrategy"/>
|
||||
</b:constructor-arg>
|
||||
</b:bean>
|
||||
|
||||
<b:bean
|
||||
name="basicController"
|
||||
class="org.springframework.security.config.http.RememberMeConfigTests.BasicController"/>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
</b:beans>
|
||||
Reference in New Issue
Block a user