Add SecurityContextHolderStrategy XML Configuration for Defaults
Issue gh-11061
This commit is contained in:
parent
2c09a300b6
commit
2a70707c35
|
@ -236,6 +236,7 @@ final class AuthenticationConfigBuilder {
|
|||
|
||||
AuthenticationConfigBuilder(Element element, boolean forceAutoConfig, ParserContext pc,
|
||||
SessionCreationPolicy sessionPolicy, BeanReference requestCache, BeanReference authenticationManager,
|
||||
BeanReference authenticationFilterSecurityContextHolderStrategyRef,
|
||||
BeanReference authenticationFilterSecurityContextRepositoryRef, BeanReference sessionStrategy,
|
||||
BeanReference portMapper, BeanReference portResolver, BeanMetadataElement csrfLogoutHandler) {
|
||||
this.httpElt = element;
|
||||
|
@ -247,11 +248,12 @@ final class AuthenticationConfigBuilder {
|
|||
this.portMapper = portMapper;
|
||||
this.portResolver = portResolver;
|
||||
this.csrfLogoutHandler = csrfLogoutHandler;
|
||||
createAnonymousFilter();
|
||||
createAnonymousFilter(authenticationFilterSecurityContextHolderStrategyRef);
|
||||
createRememberMeFilter(authenticationManager);
|
||||
createBasicFilter(authenticationManager);
|
||||
createBasicFilter(authenticationManager, authenticationFilterSecurityContextHolderStrategyRef);
|
||||
createBearerTokenAuthenticationFilter(authenticationManager);
|
||||
createFormLoginFilter(sessionStrategy, authenticationManager, authenticationFilterSecurityContextRepositoryRef);
|
||||
createFormLoginFilter(sessionStrategy, authenticationManager,
|
||||
authenticationFilterSecurityContextHolderStrategyRef, authenticationFilterSecurityContextRepositoryRef);
|
||||
createOAuth2ClientFilters(sessionStrategy, requestCache, authenticationManager,
|
||||
authenticationFilterSecurityContextRepositoryRef);
|
||||
createOpenIDLoginFilter(sessionStrategy, authenticationManager,
|
||||
|
@ -259,11 +261,11 @@ final class AuthenticationConfigBuilder {
|
|||
createSaml2LoginFilter(authenticationManager, authenticationFilterSecurityContextRepositoryRef);
|
||||
createX509Filter(authenticationManager);
|
||||
createJeeFilter(authenticationManager);
|
||||
createLogoutFilter();
|
||||
createLogoutFilter(authenticationFilterSecurityContextHolderStrategyRef);
|
||||
createSaml2LogoutFilter();
|
||||
createLoginPageFilterIfNeeded();
|
||||
createUserDetailsServiceFactory();
|
||||
createExceptionTranslationFilter();
|
||||
createExceptionTranslationFilter(authenticationFilterSecurityContextHolderStrategyRef);
|
||||
}
|
||||
|
||||
void createRememberMeFilter(BeanReference authenticationManager) {
|
||||
|
@ -293,6 +295,7 @@ final class AuthenticationConfigBuilder {
|
|||
}
|
||||
|
||||
void createFormLoginFilter(BeanReference sessionStrategy, BeanReference authManager,
|
||||
BeanReference authenticationFilterSecurityContextHolderStrategyRef,
|
||||
BeanReference authenticationFilterSecurityContextRepositoryRef) {
|
||||
Element formLoginElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.FORM_LOGIN);
|
||||
RootBeanDefinition formFilter = null;
|
||||
|
@ -313,6 +316,8 @@ final class AuthenticationConfigBuilder {
|
|||
formFilter.getPropertyValues().addPropertyValue("securityContextRepository",
|
||||
authenticationFilterSecurityContextRepositoryRef);
|
||||
}
|
||||
formFilter.getPropertyValues().addPropertyValue("securityContextHolderStrategy",
|
||||
authenticationFilterSecurityContextHolderStrategyRef);
|
||||
// Id is required by login page filter
|
||||
this.formFilterId = this.pc.getReaderContext().generateBeanName(formFilter);
|
||||
this.pc.registerBeanComponent(new BeanComponentDefinition(formFilter, this.formFilterId));
|
||||
|
@ -564,7 +569,8 @@ final class AuthenticationConfigBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
void createBasicFilter(BeanReference authManager) {
|
||||
void createBasicFilter(BeanReference authManager,
|
||||
BeanReference authenticationFilterSecurityContextHolderStrategyRef) {
|
||||
Element basicAuthElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.BASIC_AUTH);
|
||||
if (basicAuthElt == null && !this.autoConfig) {
|
||||
// No basic auth, do nothing
|
||||
|
@ -592,6 +598,8 @@ final class AuthenticationConfigBuilder {
|
|||
}
|
||||
filterBuilder.addConstructorArgValue(authManager);
|
||||
filterBuilder.addConstructorArgValue(this.basicEntryPoint);
|
||||
filterBuilder.addPropertyValue("securityContextHolderStrategy",
|
||||
authenticationFilterSecurityContextHolderStrategyRef);
|
||||
this.basicFilter = filterBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
|
@ -739,7 +747,7 @@ final class AuthenticationConfigBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
void createLogoutFilter() {
|
||||
void createLogoutFilter(BeanReference authenticationFilterSecurityContextHolderStrategyRef) {
|
||||
Element logoutElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.LOGOUT);
|
||||
if (logoutElt != null || this.autoConfig) {
|
||||
String formLoginPage = this.formLoginPage;
|
||||
|
@ -747,7 +755,8 @@ final class AuthenticationConfigBuilder {
|
|||
formLoginPage = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL;
|
||||
}
|
||||
LogoutBeanDefinitionParser logoutParser = new LogoutBeanDefinitionParser(formLoginPage,
|
||||
this.rememberMeServicesId, this.csrfLogoutHandler);
|
||||
this.rememberMeServicesId, this.csrfLogoutHandler,
|
||||
authenticationFilterSecurityContextHolderStrategyRef);
|
||||
this.logoutFilter = logoutParser.parse(logoutElt, this.pc);
|
||||
this.logoutHandlers = logoutParser.getLogoutHandlers();
|
||||
this.logoutSuccessHandler = logoutParser.getLogoutSuccessHandler();
|
||||
|
@ -803,7 +812,7 @@ final class AuthenticationConfigBuilder {
|
|||
return this.csrfIgnoreRequestMatchers;
|
||||
}
|
||||
|
||||
void createAnonymousFilter() {
|
||||
void createAnonymousFilter(BeanReference authenticationFilterSecurityContextHolderStrategyRef) {
|
||||
Element anonymousElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.ANONYMOUS);
|
||||
if (anonymousElt != null && "false".equals(anonymousElt.getAttribute("enabled"))) {
|
||||
return;
|
||||
|
@ -833,6 +842,8 @@ final class AuthenticationConfigBuilder {
|
|||
this.anonymousFilter.getConstructorArgumentValues().addIndexedArgumentValue(1, username);
|
||||
this.anonymousFilter.getConstructorArgumentValues().addIndexedArgumentValue(2,
|
||||
AuthorityUtils.commaSeparatedStringToAuthorityList(grantedAuthority));
|
||||
this.anonymousFilter.getPropertyValues().addPropertyValue("securityContextHolderStrategy",
|
||||
authenticationFilterSecurityContextHolderStrategyRef);
|
||||
this.anonymousFilter.setSource(source);
|
||||
RootBeanDefinition anonymousProviderBean = new RootBeanDefinition(AnonymousAuthenticationProvider.class);
|
||||
anonymousProviderBean.getConstructorArgumentValues().addIndexedArgumentValue(0, key);
|
||||
|
@ -847,7 +858,7 @@ final class AuthenticationConfigBuilder {
|
|||
return Long.toString(random.nextLong());
|
||||
}
|
||||
|
||||
void createExceptionTranslationFilter() {
|
||||
void createExceptionTranslationFilter(BeanReference authenticationFilterSecurityContextHolderStrategyRef) {
|
||||
BeanDefinitionBuilder etfBuilder = BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
|
||||
this.accessDeniedHandler = createAccessDeniedHandler(this.httpElt, this.pc);
|
||||
etfBuilder.addPropertyValue("accessDeniedHandler", this.accessDeniedHandler);
|
||||
|
@ -855,6 +866,8 @@ final class AuthenticationConfigBuilder {
|
|||
this.mainEntryPoint = selectEntryPoint();
|
||||
etfBuilder.addConstructorArgValue(this.mainEntryPoint);
|
||||
etfBuilder.addConstructorArgValue(this.requestCache);
|
||||
etfBuilder.addPropertyValue("securityContextHolderStrategy",
|
||||
authenticationFilterSecurityContextHolderStrategyRef);
|
||||
this.etf = etfBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import javax.servlet.ServletRequest;
|
|||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanReference;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
|
@ -40,6 +41,8 @@ import org.springframework.security.access.vote.AuthenticatedVoter;
|
|||
import org.springframework.security.access.vote.RoleVoter;
|
||||
import org.springframework.security.config.Elements;
|
||||
import org.springframework.security.config.http.GrantedAuthorityDefaultsParserUtils.AbstractGrantedAuthorityDefaultsBeanFactory;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||
import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
|
||||
|
@ -106,6 +109,8 @@ class HttpConfigurationBuilder {
|
|||
|
||||
private static final String ATT_SESSION_AUTH_ERROR_URL = "session-authentication-error-url";
|
||||
|
||||
private static final String ATT_SECURITY_CONTEXT_HOLDER_STRATEGY = "security-context-holder-strategy-ref";
|
||||
|
||||
private static final String ATT_SECURITY_CONTEXT_REPOSITORY = "security-context-repository-ref";
|
||||
|
||||
private static final String ATT_SECURITY_CONTEXT_EXPLICIT_SAVE = "security-context-explicit-save";
|
||||
|
@ -156,6 +161,8 @@ class HttpConfigurationBuilder {
|
|||
|
||||
private BeanDefinition forceEagerSessionCreationFilter;
|
||||
|
||||
private BeanReference holderStrategyRef;
|
||||
|
||||
private BeanReference contextRepoRef;
|
||||
|
||||
private BeanReference sessionRegistryRef;
|
||||
|
@ -215,6 +222,7 @@ class HttpConfigurationBuilder {
|
|||
String createSession = element.getAttribute(ATT_CREATE_SESSION);
|
||||
this.sessionPolicy = !StringUtils.hasText(createSession) ? SessionCreationPolicy.IF_REQUIRED
|
||||
: createPolicy(createSession);
|
||||
createSecurityContextHolderStrategy();
|
||||
createForceEagerSessionCreationFilter();
|
||||
createDisableEncodeUrlFilter();
|
||||
createCsrfFilter();
|
||||
|
@ -294,6 +302,10 @@ class HttpConfigurationBuilder {
|
|||
return lowerCase ? path.toLowerCase() : path;
|
||||
}
|
||||
|
||||
BeanReference getSecurityContextHolderStrategyForAuthenticationFilters() {
|
||||
return this.holderStrategyRef;
|
||||
}
|
||||
|
||||
BeanReference getSecurityContextRepositoryForAuthenticationFilters() {
|
||||
return (isExplicitSave()) ? this.contextRepoRef : null;
|
||||
}
|
||||
|
@ -331,11 +343,23 @@ class HttpConfigurationBuilder {
|
|||
default:
|
||||
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
|
||||
}
|
||||
scpf.addPropertyValue("securityContextHolderStrategy", this.holderStrategyRef);
|
||||
scpf.addConstructorArgValue(this.contextRepoRef);
|
||||
|
||||
this.securityContextPersistenceFilter = scpf.getBeanDefinition();
|
||||
}
|
||||
|
||||
private void createSecurityContextHolderStrategy() {
|
||||
String holderStrategyRef = this.httpElt.getAttribute(ATT_SECURITY_CONTEXT_HOLDER_STRATEGY);
|
||||
if (!StringUtils.hasText(holderStrategyRef)) {
|
||||
BeanDefinition holderStrategyBean = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(SecurityContextHolderStrategyFactory.class).getBeanDefinition();
|
||||
holderStrategyRef = this.pc.getReaderContext().generateBeanName(holderStrategyBean);
|
||||
this.pc.registerBeanComponent(new BeanComponentDefinition(holderStrategyBean, holderStrategyRef));
|
||||
}
|
||||
this.holderStrategyRef = new RuntimeBeanReference(holderStrategyRef);
|
||||
}
|
||||
|
||||
private void createSecurityContextRepository() {
|
||||
String repoRef = this.httpElt.getAttribute(ATT_SECURITY_CONTEXT_REPOSITORY);
|
||||
if (!StringUtils.hasText(repoRef)) {
|
||||
|
@ -359,6 +383,7 @@ class HttpConfigurationBuilder {
|
|||
contextRepo.addPropertyValue("disableUrlRewriting", Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
contextRepo.addPropertyValue("securityContextHolderStrategy", this.holderStrategyRef);
|
||||
BeanDefinition repoBean = contextRepo.getBeanDefinition();
|
||||
repoRef = this.pc.getReaderContext().generateBeanName(repoBean);
|
||||
this.pc.registerBeanComponent(new BeanComponentDefinition(repoBean, repoRef));
|
||||
|
@ -374,6 +399,7 @@ class HttpConfigurationBuilder {
|
|||
|
||||
private void createSecurityContextHolderFilter() {
|
||||
BeanDefinitionBuilder filter = BeanDefinitionBuilder.rootBeanDefinition(SecurityContextHolderFilter.class);
|
||||
filter.addPropertyValue("securityContextHolderStrategy", this.holderStrategyRef);
|
||||
filter.addConstructorArgValue(this.contextRepoRef);
|
||||
this.securityContextPersistenceFilter = filter.getBeanDefinition();
|
||||
}
|
||||
|
@ -485,6 +511,7 @@ class HttpConfigurationBuilder {
|
|||
if (StringUtils.hasText(errorUrl)) {
|
||||
failureHandler.getPropertyValues().addPropertyValue("defaultFailureUrl", errorUrl);
|
||||
}
|
||||
sessionMgmtFilter.addPropertyValue("securityContextHolderStrategy", this.holderStrategyRef);
|
||||
sessionMgmtFilter.addPropertyValue("authenticationFailureHandler", failureHandler);
|
||||
sessionMgmtFilter.addConstructorArgValue(this.contextRepoRef);
|
||||
if (!StringUtils.hasText(sessionAuthStratRef) && sessionFixationStrategy != null && !useChangeSessionId) {
|
||||
|
@ -744,6 +771,7 @@ class HttpConfigurationBuilder {
|
|||
builder.addPropertyValue("observeOncePerRequest", Boolean.FALSE);
|
||||
}
|
||||
builder.addPropertyValue("securityMetadataSource", securityMds);
|
||||
builder.addPropertyValue("securityContextHolderStrategy", this.holderStrategyRef);
|
||||
BeanDefinition fsiBean = builder.getBeanDefinition();
|
||||
String fsiId = this.pc.getReaderContext().generateBeanName(fsiBean);
|
||||
this.pc.registerBeanComponent(new BeanComponentDefinition(fsiBean, fsiId));
|
||||
|
@ -883,4 +911,18 @@ class HttpConfigurationBuilder {
|
|||
|
||||
}
|
||||
|
||||
static class SecurityContextHolderStrategyFactory implements FactoryBean<SecurityContextHolderStrategy> {
|
||||
|
||||
@Override
|
||||
public SecurityContextHolderStrategy getObject() throws Exception {
|
||||
return SecurityContextHolder.getContextHolderStrategy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return SecurityContextHolderStrategy.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -147,6 +147,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||
httpBldr.getSecurityContextRepositoryForAuthenticationFilters();
|
||||
AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, forceAutoConfig, pc,
|
||||
httpBldr.getSessionCreationPolicy(), httpBldr.getRequestCache(), authenticationManager,
|
||||
httpBldr.getSecurityContextHolderStrategyForAuthenticationFilters(),
|
||||
httpBldr.getSecurityContextRepositoryForAuthenticationFilters(), httpBldr.getSessionStrategy(),
|
||||
portMapper, portResolver, httpBldr.getCsrfLogoutHandler());
|
||||
httpBldr.setLogoutHandlers(authBldr.getLogoutHandlers());
|
||||
|
|
|
@ -20,6 +20,7 @@ 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;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
|
@ -61,13 +62,17 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
|||
|
||||
private BeanMetadataElement logoutSuccessHandler;
|
||||
|
||||
LogoutBeanDefinitionParser(String loginPageUrl, String rememberMeServices, BeanMetadataElement csrfLogoutHandler) {
|
||||
private BeanReference authenticationFilterSecurityContextHolderStrategyRef;
|
||||
|
||||
LogoutBeanDefinitionParser(String loginPageUrl, String rememberMeServices, BeanMetadataElement csrfLogoutHandler,
|
||||
BeanReference authenticationFilterSecurityContextHolderStrategyRef) {
|
||||
this.defaultLogoutUrl = loginPageUrl + "?logout";
|
||||
this.rememberMeServices = rememberMeServices;
|
||||
this.csrfEnabled = csrfLogoutHandler != null;
|
||||
if (this.csrfEnabled) {
|
||||
this.logoutHandlers.add(csrfLogoutHandler);
|
||||
}
|
||||
this.authenticationFilterSecurityContextHolderStrategyRef = authenticationFilterSecurityContextHolderStrategyRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -123,6 +128,8 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
|||
}
|
||||
this.logoutHandlers.add(new RootBeanDefinition(LogoutSuccessEventPublishingLogoutHandler.class));
|
||||
builder.addConstructorArgValue(this.logoutHandlers);
|
||||
builder.addPropertyValue("securityContextHolderStrategy",
|
||||
this.authenticationFilterSecurityContextHolderStrategyRef);
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
|
|
|
@ -333,6 +333,9 @@ http.attlist &=
|
|||
attribute auto-config {xsd:boolean}?
|
||||
http.attlist &=
|
||||
use-expressions?
|
||||
http.attlist &=
|
||||
## A reference to a SecurityContextHolderStrategy bean. This can be used to customize how the SecurityContextHolder is stored during a request
|
||||
attribute security-context-holder-strategy-ref {xsd:token}?
|
||||
http.attlist &=
|
||||
## Controls the eagerness with which an HTTP session is created by Spring Security classes. If not set, defaults to "ifRequired". If "stateless" is used, this implies that the application guarantees that it will not create a session. This differs from the use of "never" which means that Spring Security will not create a session, but will make use of one if the application does.
|
||||
attribute create-session {"ifRequired" | "always" | "never" | "stateless"}?
|
||||
|
|
|
@ -1224,6 +1224,13 @@
|
|||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="security-context-holder-strategy-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A reference to a SecurityContextHolderStrategy bean. This can be used to customize how the
|
||||
SecurityContextHolder is stored during a request
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="create-session">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Controls the eagerness with which an HTTP session is created by Spring Security classes.
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.springframework.security.config.test.SpringTestContext;
|
|||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
|
@ -45,6 +46,8 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
|
@ -147,6 +150,14 @@ public class FormLoginConfigTests {
|
|||
.andExpect(redirectedUrl("/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenCustomSecurityContextHolderStrategyThenUses() throws Exception {
|
||||
this.spring.configLocations(this.xml("WithCustomSecurityContextHolderStrategy")).autowire();
|
||||
SecurityContextHolderStrategy strategy = this.spring.getContext().getBean(SecurityContextHolderStrategy.class);
|
||||
this.mvc.perform(post("/login").with(csrf())).andExpect(redirectedUrl("/login?error"));
|
||||
verify(strategy, atLeastOnce()).getContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* SEC-2919 - DefaultLoginGeneratingFilter incorrectly used if login-url="/login"
|
||||
*/
|
||||
|
|
|
@ -32,8 +32,11 @@ import org.springframework.mock.web.MockFilterChain;
|
|||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
|
@ -94,6 +97,30 @@ public class NamespaceHttpBasicTests {
|
|||
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpBasicCustomSecurityContextHolderStrategy() throws Exception {
|
||||
// @formatter:off
|
||||
loadContext("<http auto-config=\"true\" use-expressions=\"false\" security-context-holder-strategy-ref=\"ref\"/>\n"
|
||||
+ "<authentication-manager id=\"authenticationManager\">\n"
|
||||
+ " <authentication-provider>\n"
|
||||
+ " <user-service>\n"
|
||||
+ " <user name=\"user\" password=\"{noop}test\" authorities=\"ROLE_USER\"/>\n"
|
||||
+ " </user-service>\n"
|
||||
+ " </authentication-provider>\n"
|
||||
+ "</authentication-manager>\n"
|
||||
+ "<b:bean id=\"ref\" class=\"org.mockito.Mockito\" factory-method=\"spy\">\n" +
|
||||
" <b:constructor-arg>\n" +
|
||||
" <b:bean class=\"org.springframework.security.config.MockSecurityContextHolderStrategy\"/>\n" +
|
||||
" </b:constructor-arg>\n" +
|
||||
"</b:bean>");
|
||||
// @formatter:on
|
||||
this.request.addHeader("Authorization",
|
||||
"Basic " + Base64.getEncoder().encodeToString("user:test".getBytes("UTF-8")));
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
verify(this.context.getBean(SecurityContextHolderStrategy.class), atLeastOnce()).getContext();
|
||||
}
|
||||
|
||||
// gh-4220
|
||||
@Test
|
||||
public void httpBasicUnauthorizedOnDefault() throws Exception {
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<?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" use-expressions="false" security-context-holder-strategy-ref="ref">
|
||||
</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="userservice.xml"/>
|
||||
</b:beans>
|
|
@ -131,6 +131,9 @@ This is a more powerful alternative to <<nsa-http-pattern,pattern>>.
|
|||
A request pattern can be mapped to an empty filter chain, by setting this attribute to `none`.
|
||||
No security will be applied and none of Spring Security's features will be available.
|
||||
|
||||
[[nsa-http-security-context-holder-strategy-ref]]
|
||||
* **security-context-repository-ref**
|
||||
Allows injection of a custom `SecurityContextHolderStrategy` into `SecurityContextPersistenceFilter`, `SecurityContextHolderFilter`, `BasicAuthenticationFilter`, `UsernamePasswordAuthenticationFilter`, `ExceptionTranslationFilter`, `LogoutFilter`, and others.
|
||||
|
||||
[[nsa-http-security-context-explicit-save]]
|
||||
* **security-context-explicit-save**
|
||||
|
|
Loading…
Reference in New Issue