Add SecurityContextHolderStrategy to Pre-authenticated scenarios
Issue gh-11060 Issue gh-11061
This commit is contained in:
parent
97cb2a7d91
commit
83b3bb3209
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2002-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -198,7 +198,8 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends Abstr
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(H http) {
|
public void configure(H http) {
|
||||||
J2eePreAuthenticatedProcessingFilter filter = getFilter(http.getSharedObject(AuthenticationManager.class));
|
J2eePreAuthenticatedProcessingFilter filter = getFilter(http.getSharedObject(AuthenticationManager.class),
|
||||||
|
http);
|
||||||
http.addFilter(filter);
|
http.addFilter(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,12 +209,14 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends Abstr
|
||||||
* @param authenticationManager the {@link AuthenticationManager} to use.
|
* @param authenticationManager the {@link AuthenticationManager} to use.
|
||||||
* @return the {@link J2eePreAuthenticatedProcessingFilter} to use.
|
* @return the {@link J2eePreAuthenticatedProcessingFilter} to use.
|
||||||
*/
|
*/
|
||||||
private J2eePreAuthenticatedProcessingFilter getFilter(AuthenticationManager authenticationManager) {
|
private J2eePreAuthenticatedProcessingFilter getFilter(AuthenticationManager authenticationManager, H http) {
|
||||||
if (this.j2eePreAuthenticatedProcessingFilter == null) {
|
if (this.j2eePreAuthenticatedProcessingFilter == null) {
|
||||||
this.j2eePreAuthenticatedProcessingFilter = new J2eePreAuthenticatedProcessingFilter();
|
this.j2eePreAuthenticatedProcessingFilter = new J2eePreAuthenticatedProcessingFilter();
|
||||||
this.j2eePreAuthenticatedProcessingFilter.setAuthenticationManager(authenticationManager);
|
this.j2eePreAuthenticatedProcessingFilter.setAuthenticationManager(authenticationManager);
|
||||||
this.j2eePreAuthenticatedProcessingFilter
|
this.j2eePreAuthenticatedProcessingFilter
|
||||||
.setAuthenticationDetailsSource(createWebAuthenticationDetailsSource());
|
.setAuthenticationDetailsSource(createWebAuthenticationDetailsSource());
|
||||||
|
this.j2eePreAuthenticatedProcessingFilter
|
||||||
|
.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
||||||
this.j2eePreAuthenticatedProcessingFilter = postProcess(this.j2eePreAuthenticatedProcessingFilter);
|
this.j2eePreAuthenticatedProcessingFilter = postProcess(this.j2eePreAuthenticatedProcessingFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -183,11 +183,11 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(H http) {
|
public void configure(H http) {
|
||||||
X509AuthenticationFilter filter = getFilter(http.getSharedObject(AuthenticationManager.class));
|
X509AuthenticationFilter filter = getFilter(http.getSharedObject(AuthenticationManager.class), http);
|
||||||
http.addFilter(filter);
|
http.addFilter(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private X509AuthenticationFilter getFilter(AuthenticationManager authenticationManager) {
|
private X509AuthenticationFilter getFilter(AuthenticationManager authenticationManager, H http) {
|
||||||
if (this.x509AuthenticationFilter == null) {
|
if (this.x509AuthenticationFilter == null) {
|
||||||
this.x509AuthenticationFilter = new X509AuthenticationFilter();
|
this.x509AuthenticationFilter = new X509AuthenticationFilter();
|
||||||
this.x509AuthenticationFilter.setAuthenticationManager(authenticationManager);
|
this.x509AuthenticationFilter.setAuthenticationManager(authenticationManager);
|
||||||
|
@ -197,6 +197,7 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>>
|
||||||
if (this.authenticationDetailsSource != null) {
|
if (this.authenticationDetailsSource != null) {
|
||||||
this.x509AuthenticationFilter.setAuthenticationDetailsSource(this.authenticationDetailsSource);
|
this.x509AuthenticationFilter.setAuthenticationDetailsSource(this.authenticationDetailsSource);
|
||||||
}
|
}
|
||||||
|
this.x509AuthenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
||||||
this.x509AuthenticationFilter = postProcess(this.x509AuthenticationFilter);
|
this.x509AuthenticationFilter = postProcess(this.x509AuthenticationFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -236,8 +236,8 @@ final class AuthenticationConfigBuilder {
|
||||||
createOAuth2ClientFilters(sessionStrategy, requestCache, authenticationManager,
|
createOAuth2ClientFilters(sessionStrategy, requestCache, authenticationManager,
|
||||||
authenticationFilterSecurityContextRepositoryRef);
|
authenticationFilterSecurityContextRepositoryRef);
|
||||||
createSaml2LoginFilter(authenticationManager, authenticationFilterSecurityContextRepositoryRef);
|
createSaml2LoginFilter(authenticationManager, authenticationFilterSecurityContextRepositoryRef);
|
||||||
createX509Filter(authenticationManager);
|
createX509Filter(authenticationManager, authenticationFilterSecurityContextHolderStrategyRef);
|
||||||
createJeeFilter(authenticationManager);
|
createJeeFilter(authenticationManager, authenticationFilterSecurityContextHolderStrategyRef);
|
||||||
createLogoutFilter(authenticationFilterSecurityContextHolderStrategyRef);
|
createLogoutFilter(authenticationFilterSecurityContextHolderStrategyRef);
|
||||||
createSaml2LogoutFilter();
|
createSaml2LogoutFilter();
|
||||||
createLoginPageFilterIfNeeded();
|
createLoginPageFilterIfNeeded();
|
||||||
|
@ -488,7 +488,8 @@ final class AuthenticationConfigBuilder {
|
||||||
this.bearerTokenAuthenticationFilter = resourceServerBuilder.parse(resourceServerElt, this.pc);
|
this.bearerTokenAuthenticationFilter = resourceServerBuilder.parse(resourceServerElt, this.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void createX509Filter(BeanReference authManager) {
|
void createX509Filter(BeanReference authManager,
|
||||||
|
BeanMetadataElement authenticationFilterSecurityContextHolderStrategyRef) {
|
||||||
Element x509Elt = DomUtils.getChildElementByTagName(this.httpElt, Elements.X509);
|
Element x509Elt = DomUtils.getChildElementByTagName(this.httpElt, Elements.X509);
|
||||||
RootBeanDefinition filter = null;
|
RootBeanDefinition filter = null;
|
||||||
if (x509Elt != null) {
|
if (x509Elt != null) {
|
||||||
|
@ -496,6 +497,8 @@ final class AuthenticationConfigBuilder {
|
||||||
.rootBeanDefinition(X509AuthenticationFilter.class);
|
.rootBeanDefinition(X509AuthenticationFilter.class);
|
||||||
filterBuilder.getRawBeanDefinition().setSource(this.pc.extractSource(x509Elt));
|
filterBuilder.getRawBeanDefinition().setSource(this.pc.extractSource(x509Elt));
|
||||||
filterBuilder.addPropertyValue("authenticationManager", authManager);
|
filterBuilder.addPropertyValue("authenticationManager", authManager);
|
||||||
|
filterBuilder.addPropertyValue("securityContextHolderStrategy",
|
||||||
|
authenticationFilterSecurityContextHolderStrategyRef);
|
||||||
String regex = x509Elt.getAttribute("subject-principal-regex");
|
String regex = x509Elt.getAttribute("subject-principal-regex");
|
||||||
if (StringUtils.hasText(regex)) {
|
if (StringUtils.hasText(regex)) {
|
||||||
BeanDefinitionBuilder extractor = BeanDefinitionBuilder
|
BeanDefinitionBuilder extractor = BeanDefinitionBuilder
|
||||||
|
@ -536,7 +539,8 @@ final class AuthenticationConfigBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void createJeeFilter(BeanReference authManager) {
|
void createJeeFilter(BeanReference authManager,
|
||||||
|
BeanMetadataElement authenticationFilterSecurityContextHolderStrategyRef) {
|
||||||
Element jeeElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.JEE);
|
Element jeeElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.JEE);
|
||||||
RootBeanDefinition filter = null;
|
RootBeanDefinition filter = null;
|
||||||
if (jeeElt != null) {
|
if (jeeElt != null) {
|
||||||
|
@ -544,6 +548,8 @@ final class AuthenticationConfigBuilder {
|
||||||
.rootBeanDefinition(J2eePreAuthenticatedProcessingFilter.class);
|
.rootBeanDefinition(J2eePreAuthenticatedProcessingFilter.class);
|
||||||
filterBuilder.getRawBeanDefinition().setSource(this.pc.extractSource(jeeElt));
|
filterBuilder.getRawBeanDefinition().setSource(this.pc.extractSource(jeeElt));
|
||||||
filterBuilder.addPropertyValue("authenticationManager", authManager);
|
filterBuilder.addPropertyValue("authenticationManager", authManager);
|
||||||
|
filterBuilder.addPropertyValue("securityContextHolderStrategy",
|
||||||
|
authenticationFilterSecurityContextHolderStrategyRef);
|
||||||
BeanDefinitionBuilder adsBldr = BeanDefinitionBuilder
|
BeanDefinitionBuilder adsBldr = BeanDefinitionBuilder
|
||||||
.rootBeanDefinition(J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource.class);
|
.rootBeanDefinition(J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource.class);
|
||||||
adsBldr.addPropertyValue("userRoles2GrantedAuthoritiesMapper",
|
adsBldr.addPropertyValue("userRoles2GrantedAuthoritiesMapper",
|
||||||
|
|
|
@ -28,24 +28,30 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
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.authentication.builders.AuthenticationManagerBuilder;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
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.EnableWebSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
import org.springframework.security.config.test.SpringTestContext;
|
import org.springframework.security.config.test.SpringTestContext;
|
||||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||||
|
import org.springframework.security.core.context.SecurityContextChangedListener;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
import org.springframework.security.core.userdetails.User;
|
import org.springframework.security.core.userdetails.User;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
|
||||||
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
|
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.springframework.security.config.Customizer.withDefaults;
|
import static org.springframework.security.config.Customizer.withDefaults;
|
||||||
|
import static org.springframework.security.config.annotation.SecurityContextChangedListenerArgumentMatchers.setAuthentication;
|
||||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.x509;
|
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.x509;
|
||||||
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
|
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
@ -90,6 +96,21 @@ public class X509ConfigurerTests {
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void x509WhenCustomSecurityContextHolderStrategyThenUses() throws Exception {
|
||||||
|
this.spring.register(DefaultsInLambdaConfig.class, SecurityContextChangedListenerConfig.class).autowire();
|
||||||
|
X509Certificate certificate = loadCert("rod.cer");
|
||||||
|
// @formatter:off
|
||||||
|
this.mvc.perform(get("/").with(x509(certificate)))
|
||||||
|
.andExpect(authenticated().withUsername("rod"));
|
||||||
|
// @formatter:on
|
||||||
|
SecurityContextHolderStrategy strategy = this.spring.getContext().getBean(SecurityContextHolderStrategy.class);
|
||||||
|
verify(strategy, atLeastOnce()).getContext();
|
||||||
|
SecurityContextChangedListener listener = this.spring.getContext()
|
||||||
|
.getBean(SecurityContextChangedListener.class);
|
||||||
|
verify(listener).securityContextChanged(setAuthentication(PreAuthenticatedAuthenticationToken.class));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void x509WhenSubjectPrincipalRegexInLambdaThenUsesRegexToExtractPrincipal() throws Exception {
|
public void x509WhenSubjectPrincipalRegexInLambdaThenUsesRegexToExtractPrincipal() throws Exception {
|
||||||
this.spring.register(SubjectPrincipalRegexInLambdaConfig.class).autowire();
|
this.spring.register(SubjectPrincipalRegexInLambdaConfig.class).autowire();
|
||||||
|
|
|
@ -76,6 +76,7 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
import org.springframework.security.core.context.SecurityContext;
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
import org.springframework.security.core.context.SecurityContextImpl;
|
import org.springframework.security.core.context.SecurityContextImpl;
|
||||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
import org.springframework.security.web.FilterChainProxy;
|
import org.springframework.security.web.FilterChainProxy;
|
||||||
|
@ -380,6 +381,19 @@ public class MiscHttpConfigTests {
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getWhenUsingX509CustomSecurityContextHolderStrategyThenUses() throws Exception {
|
||||||
|
System.setProperty("subject_principal_regex", "OU=(.*?)(?:,|$)");
|
||||||
|
this.spring.configLocations(xml("X509WithSecurityContextHolderStrategy")).autowire();
|
||||||
|
RequestPostProcessor x509 = x509(
|
||||||
|
"classpath:org/springframework/security/config/http/MiscHttpConfigTests-certificate.pem");
|
||||||
|
// @formatter:off
|
||||||
|
this.mvc.perform(get("/protected").with(x509))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
// @formatter:on
|
||||||
|
verify(this.spring.getContext().getBean(SecurityContextHolderStrategy.class), atLeastOnce()).getContext();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void configureWhenUsingInvalidLogoutSuccessUrlThenThrowsException() {
|
public void configureWhenUsingInvalidLogoutSuccessUrlThenThrowsException() {
|
||||||
assertThatExceptionOfType(BeanCreationException.class)
|
assertThatExceptionOfType(BeanCreationException.class)
|
||||||
|
@ -652,6 +666,26 @@ public class MiscHttpConfigTests {
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loginWhenJeeFilterCustomSecurityContextHolderStrategyThenUses() throws Exception {
|
||||||
|
this.spring.configLocations(xml("JeeFilterWithSecurityContextHolderStrategy")).autowire();
|
||||||
|
Principal user = mock(Principal.class);
|
||||||
|
given(user.getName()).willReturn("joe");
|
||||||
|
// @formatter:off
|
||||||
|
MockHttpServletRequestBuilder rolesRequest = get("/roles")
|
||||||
|
.principal(user)
|
||||||
|
.with((request) -> {
|
||||||
|
request.addUserRole("admin");
|
||||||
|
request.addUserRole("user");
|
||||||
|
request.addUserRole("unmapped");
|
||||||
|
return request;
|
||||||
|
});
|
||||||
|
this.mvc.perform(rolesRequest)
|
||||||
|
.andExpect(content().string("ROLE_admin,ROLE_user"));
|
||||||
|
// @formatter:on
|
||||||
|
verify(this.spring.getContext().getBean(SecurityContextHolderStrategy.class), atLeastOnce()).getContext();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void loginWhenUsingCustomAuthenticationDetailsSourceRefThenAuthenticationSourcesDetailsAccordingly()
|
public void loginWhenUsingCustomAuthenticationDetailsSourceRefThenAuthenticationSourcesDetailsAccordingly()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?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 security-context-holder-strategy-ref="ref">
|
||||||
|
<jee mappable-roles="admin,user"/>
|
||||||
|
</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:import resource="MiscHttpConfigTests-controllers.xml"/>
|
||||||
|
<b:import resource="userservice.xml"/>
|
||||||
|
</b:beans>
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?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 security-context-holder-strategy-ref="ref">
|
||||||
|
<x509 subject-principal-regex="${subject_principal_regex:(.*)}"/>
|
||||||
|
<intercept-url pattern="/**" access="authenticated"/>
|
||||||
|
</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="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/>
|
||||||
|
|
||||||
|
<b:import resource="MiscHttpConfigTests-controllers.xml"/>
|
||||||
|
<b:import resource="userservice.xml"/>
|
||||||
|
</b:beans>
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2021 the original author or authors.
|
* Copyright 2002-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -36,6 +36,7 @@ import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.core.context.SecurityContext;
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
import org.springframework.security.web.WebAttributes;
|
import org.springframework.security.web.WebAttributes;
|
||||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||||
|
@ -88,6 +89,9 @@ import org.springframework.web.filter.GenericFilterBean;
|
||||||
public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFilterBean
|
public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFilterBean
|
||||||
implements ApplicationEventPublisherAware {
|
implements ApplicationEventPublisherAware {
|
||||||
|
|
||||||
|
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
|
||||||
|
.getContextHolderStrategy();
|
||||||
|
|
||||||
private ApplicationEventPublisher eventPublisher = null;
|
private ApplicationEventPublisher eventPublisher = null;
|
||||||
|
|
||||||
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
|
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
|
||||||
|
@ -132,8 +136,8 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
|
||||||
throws IOException, ServletException {
|
throws IOException, ServletException {
|
||||||
if (this.requiresAuthenticationRequestMatcher.matches((HttpServletRequest) request)) {
|
if (this.requiresAuthenticationRequestMatcher.matches((HttpServletRequest) request)) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug(LogMessage
|
logger.debug(LogMessage.of(
|
||||||
.of(() -> "Authenticating " + SecurityContextHolder.getContext().getAuthentication()));
|
() -> "Authenticating " + this.securityContextHolderStrategy.getContext().getAuthentication()));
|
||||||
}
|
}
|
||||||
doAuthenticate((HttpServletRequest) request, (HttpServletResponse) response);
|
doAuthenticate((HttpServletRequest) request, (HttpServletResponse) response);
|
||||||
}
|
}
|
||||||
|
@ -211,9 +215,9 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
|
||||||
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||||
Authentication authResult) throws IOException, ServletException {
|
Authentication authResult) throws IOException, ServletException {
|
||||||
this.logger.debug(LogMessage.format("Authentication success: %s", authResult));
|
this.logger.debug(LogMessage.format("Authentication success: %s", authResult));
|
||||||
SecurityContext context = SecurityContextHolder.createEmptyContext();
|
SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
|
||||||
context.setAuthentication(authResult);
|
context.setAuthentication(authResult);
|
||||||
SecurityContextHolder.setContext(context);
|
this.securityContextHolderStrategy.setContext(context);
|
||||||
this.securityContextRepository.saveContext(context, request, response);
|
this.securityContextRepository.saveContext(context, request, response);
|
||||||
if (this.eventPublisher != null) {
|
if (this.eventPublisher != null) {
|
||||||
this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
|
this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
|
||||||
|
@ -231,7 +235,7 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
|
||||||
*/
|
*/
|
||||||
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||||
AuthenticationException failed) throws IOException, ServletException {
|
AuthenticationException failed) throws IOException, ServletException {
|
||||||
SecurityContextHolder.clearContext();
|
this.securityContextHolderStrategy.clearContext();
|
||||||
this.logger.debug("Cleared security context due to exception", failed);
|
this.logger.debug("Cleared security context due to exception", failed);
|
||||||
request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, failed);
|
request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, failed);
|
||||||
if (this.authenticationFailureHandler != null) {
|
if (this.authenticationFailureHandler != null) {
|
||||||
|
@ -335,6 +339,17 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
|
||||||
this.requiresAuthenticationRequestMatcher = requiresAuthenticationRequestMatcher;
|
this.requiresAuthenticationRequestMatcher = requiresAuthenticationRequestMatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use
|
||||||
|
* the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}.
|
||||||
|
*
|
||||||
|
* @since 5.8
|
||||||
|
*/
|
||||||
|
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
|
||||||
|
Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null");
|
||||||
|
this.securityContextHolderStrategy = securityContextHolderStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override to extract the principal information from the current request
|
* Override to extract the principal information from the current request
|
||||||
*/
|
*/
|
||||||
|
@ -354,7 +369,8 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(HttpServletRequest request) {
|
public boolean matches(HttpServletRequest request) {
|
||||||
Authentication currentUser = SecurityContextHolder.getContext().getAuthentication();
|
Authentication currentUser = AbstractPreAuthenticatedProcessingFilter.this.securityContextHolderStrategy
|
||||||
|
.getContext().getAuthentication();
|
||||||
if (currentUser == null) {
|
if (currentUser == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -367,7 +383,7 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
|
||||||
AbstractPreAuthenticatedProcessingFilter.this.logger
|
AbstractPreAuthenticatedProcessingFilter.this.logger
|
||||||
.debug("Pre-authenticated principal has changed and will be reauthenticated");
|
.debug("Pre-authenticated principal has changed and will be reauthenticated");
|
||||||
if (AbstractPreAuthenticatedProcessingFilter.this.invalidateSessionOnPrincipalChange) {
|
if (AbstractPreAuthenticatedProcessingFilter.this.invalidateSessionOnPrincipalChange) {
|
||||||
SecurityContextHolder.clearContext();
|
AbstractPreAuthenticatedProcessingFilter.this.securityContextHolderStrategy.clearContext();
|
||||||
HttpSession session = request.getSession(false);
|
HttpSession session = request.getSession(false);
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
AbstractPreAuthenticatedProcessingFilter.this.logger.debug("Invalidating existing session");
|
AbstractPreAuthenticatedProcessingFilter.this.logger.debug("Invalidating existing session");
|
||||||
|
|
Loading…
Reference in New Issue