SEC-1893: Namespace now register PortMapper with custom mappings for all components that use a PortMapper
This commit is contained in:
parent
84141c4c76
commit
f78c11650f
config/src
main/java/org/springframework/security/config/http
AuthenticationConfigBuilder.javaFormLoginBeanDefinitionParser.javaHttpConfigurationBuilder.javaHttpSecurityBeanDefinitionParser.java
test/groovy/org/springframework/security/config/http
|
@ -47,6 +47,7 @@ import java.util.*;
|
||||||
* Handles creation of authentication mechanism filters and related beans for <http> parsing.
|
* Handles creation of authentication mechanism filters and related beans for <http> parsing.
|
||||||
*
|
*
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
|
* @author Rob Winch
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
final class AuthenticationConfigBuilder {
|
final class AuthenticationConfigBuilder {
|
||||||
|
@ -102,15 +103,19 @@ final class AuthenticationConfigBuilder {
|
||||||
private BeanDefinition loginPageGenerationFilter;
|
private BeanDefinition loginPageGenerationFilter;
|
||||||
private BeanDefinition etf;
|
private BeanDefinition etf;
|
||||||
private final BeanReference requestCache;
|
private final BeanReference requestCache;
|
||||||
|
private final BeanReference portMapper;
|
||||||
|
private final BeanReference portResolver;
|
||||||
|
|
||||||
public AuthenticationConfigBuilder(Element element, ParserContext pc, SessionCreationPolicy sessionPolicy,
|
public AuthenticationConfigBuilder(Element element, ParserContext pc, SessionCreationPolicy sessionPolicy,
|
||||||
BeanReference requestCache, BeanReference authenticationManager, BeanReference sessionStrategy) {
|
BeanReference requestCache, BeanReference authenticationManager, BeanReference sessionStrategy, BeanReference portMapper, BeanReference portResolver) {
|
||||||
this.httpElt = element;
|
this.httpElt = element;
|
||||||
this.pc = pc;
|
this.pc = pc;
|
||||||
this.requestCache = requestCache;
|
this.requestCache = requestCache;
|
||||||
autoConfig = "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
|
autoConfig = "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
|
||||||
this.allowSessionCreation = sessionPolicy != SessionCreationPolicy.never
|
this.allowSessionCreation = sessionPolicy != SessionCreationPolicy.never
|
||||||
&& sessionPolicy != SessionCreationPolicy.stateless;
|
&& sessionPolicy != SessionCreationPolicy.stateless;
|
||||||
|
this.portMapper = portMapper;
|
||||||
|
this.portResolver = portResolver;
|
||||||
|
|
||||||
createAnonymousFilter();
|
createAnonymousFilter();
|
||||||
createRememberMeFilter(authenticationManager);
|
createRememberMeFilter(authenticationManager);
|
||||||
|
@ -164,7 +169,7 @@ final class AuthenticationConfigBuilder {
|
||||||
|
|
||||||
if (formLoginElt != null || autoConfig) {
|
if (formLoginElt != null || autoConfig) {
|
||||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
|
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
|
||||||
AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation);
|
AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation, portMapper, portResolver);
|
||||||
|
|
||||||
parser.parse(formLoginElt, pc);
|
parser.parse(formLoginElt, pc);
|
||||||
formFilter = parser.getFilterBean();
|
formFilter = parser.getFilterBean();
|
||||||
|
@ -188,7 +193,7 @@ final class AuthenticationConfigBuilder {
|
||||||
|
|
||||||
if (openIDLoginElt != null) {
|
if (openIDLoginElt != null) {
|
||||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
|
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
|
||||||
OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation);
|
OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation, portMapper, portResolver);
|
||||||
|
|
||||||
parser.parse(openIDLoginElt, pc);
|
parser.parse(openIDLoginElt, pc);
|
||||||
openIDFilter = parser.getFilterBean();
|
openIDFilter = parser.getFilterBean();
|
||||||
|
|
|
@ -17,6 +17,7 @@ import org.w3c.dom.Element;
|
||||||
/**
|
/**
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
|
* @author Rob Winch
|
||||||
*/
|
*/
|
||||||
public class FormLoginBeanDefinitionParser {
|
public class FormLoginBeanDefinitionParser {
|
||||||
protected final Log logger = LogFactory.getLog(getClass());
|
protected final Log logger = LogFactory.getLog(getClass());
|
||||||
|
@ -44,18 +45,22 @@ public class FormLoginBeanDefinitionParser {
|
||||||
private final BeanReference requestCache;
|
private final BeanReference requestCache;
|
||||||
private final BeanReference sessionStrategy;
|
private final BeanReference sessionStrategy;
|
||||||
private final boolean allowSessionCreation;
|
private final boolean allowSessionCreation;
|
||||||
|
private final BeanReference portMapper;
|
||||||
|
private final BeanReference portResolver;
|
||||||
|
|
||||||
private RootBeanDefinition filterBean;
|
private RootBeanDefinition filterBean;
|
||||||
private RootBeanDefinition entryPointBean;
|
private RootBeanDefinition entryPointBean;
|
||||||
private String loginPage;
|
private String loginPage;
|
||||||
|
|
||||||
FormLoginBeanDefinitionParser(String defaultLoginProcessingUrl, String filterClassName,
|
FormLoginBeanDefinitionParser(String defaultLoginProcessingUrl, String filterClassName,
|
||||||
BeanReference requestCache, BeanReference sessionStrategy, boolean allowSessionCreation) {
|
BeanReference requestCache, BeanReference sessionStrategy, boolean allowSessionCreation, BeanReference portMapper, BeanReference portResolver) {
|
||||||
this.defaultLoginProcessingUrl = defaultLoginProcessingUrl;
|
this.defaultLoginProcessingUrl = defaultLoginProcessingUrl;
|
||||||
this.filterClassName = filterClassName;
|
this.filterClassName = filterClassName;
|
||||||
this.requestCache = requestCache;
|
this.requestCache = requestCache;
|
||||||
this.sessionStrategy = sessionStrategy;
|
this.sessionStrategy = sessionStrategy;
|
||||||
this.allowSessionCreation = allowSessionCreation;
|
this.allowSessionCreation = allowSessionCreation;
|
||||||
|
this.portMapper = portMapper;
|
||||||
|
this.portResolver = portResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BeanDefinition parse(Element elt, ParserContext pc) {
|
public BeanDefinition parse(Element elt, ParserContext pc) {
|
||||||
|
@ -111,6 +116,8 @@ public class FormLoginBeanDefinitionParser {
|
||||||
BeanDefinitionBuilder.rootBeanDefinition(LoginUrlAuthenticationEntryPoint.class);
|
BeanDefinitionBuilder.rootBeanDefinition(LoginUrlAuthenticationEntryPoint.class);
|
||||||
entryPointBuilder.getRawBeanDefinition().setSource(source);
|
entryPointBuilder.getRawBeanDefinition().setSource(source);
|
||||||
entryPointBuilder.addPropertyValue("loginFormUrl", loginPage != null ? loginPage : DEF_LOGIN_PAGE);
|
entryPointBuilder.addPropertyValue("loginFormUrl", loginPage != null ? loginPage : DEF_LOGIN_PAGE);
|
||||||
|
entryPointBuilder.addPropertyValue("portMapper", portMapper);
|
||||||
|
entryPointBuilder.addPropertyValue("portResolver", portResolver);
|
||||||
entryPointBean = (RootBeanDefinition) entryPointBuilder.getBeanDefinition();
|
entryPointBean = (RootBeanDefinition) entryPointBuilder.getBeanDefinition();
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -55,6 +55,7 @@ import org.w3c.dom.Element;
|
||||||
* Stateful class which helps HttpSecurityBDP to create the configuration for the <http> element.
|
* Stateful class which helps HttpSecurityBDP to create the configuration for the <http> element.
|
||||||
*
|
*
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
|
* @author Rob Winch
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
class HttpConfigurationBuilder {
|
class HttpConfigurationBuilder {
|
||||||
|
@ -92,16 +93,18 @@ class HttpConfigurationBuilder {
|
||||||
private RootBeanDefinition sfpf;
|
private RootBeanDefinition sfpf;
|
||||||
private BeanDefinition servApiFilter;
|
private BeanDefinition servApiFilter;
|
||||||
private BeanDefinition jaasApiFilter;
|
private BeanDefinition jaasApiFilter;
|
||||||
private final String portMapperName;
|
private final BeanReference portMapper;
|
||||||
|
private final BeanReference portResolver;
|
||||||
private BeanReference fsi;
|
private BeanReference fsi;
|
||||||
private BeanReference requestCache;
|
private BeanReference requestCache;
|
||||||
|
|
||||||
public HttpConfigurationBuilder(Element element, ParserContext pc,
|
public HttpConfigurationBuilder(Element element, ParserContext pc,
|
||||||
String portMapperName, BeanReference authenticationManager) {
|
BeanReference portMapper, BeanReference portResolver, BeanReference authenticationManager) {
|
||||||
|
|
||||||
this.httpElt = element;
|
this.httpElt = element;
|
||||||
this.pc = pc;
|
this.pc = pc;
|
||||||
this.portMapperName = portMapperName;
|
this.portMapper = portMapper;
|
||||||
|
this.portResolver = portResolver;
|
||||||
this.matcherType = MatcherType.fromElement(element);
|
this.matcherType = MatcherType.fromElement(element);
|
||||||
interceptUrls = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL);
|
interceptUrls = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL);
|
||||||
|
|
||||||
|
@ -374,9 +377,11 @@ class HttpConfigurationBuilder {
|
||||||
RootBeanDefinition secureChannelProcessor = new RootBeanDefinition(SecureChannelProcessor.class);
|
RootBeanDefinition secureChannelProcessor = new RootBeanDefinition(SecureChannelProcessor.class);
|
||||||
RootBeanDefinition retryWithHttp = new RootBeanDefinition(RetryWithHttpEntryPoint.class);
|
RootBeanDefinition retryWithHttp = new RootBeanDefinition(RetryWithHttpEntryPoint.class);
|
||||||
RootBeanDefinition retryWithHttps = new RootBeanDefinition(RetryWithHttpsEntryPoint.class);
|
RootBeanDefinition retryWithHttps = new RootBeanDefinition(RetryWithHttpsEntryPoint.class);
|
||||||
RuntimeBeanReference portMapper = new RuntimeBeanReference(portMapperName);
|
|
||||||
retryWithHttp.getPropertyValues().addPropertyValue("portMapper", portMapper);
|
retryWithHttp.getPropertyValues().addPropertyValue("portMapper", portMapper);
|
||||||
|
retryWithHttp.getPropertyValues().addPropertyValue("portResolver", portResolver);
|
||||||
retryWithHttps.getPropertyValues().addPropertyValue("portMapper", portMapper);
|
retryWithHttps.getPropertyValues().addPropertyValue("portMapper", portMapper);
|
||||||
|
retryWithHttps.getPropertyValues().addPropertyValue("portResolver", portResolver);
|
||||||
secureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttps);
|
secureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttps);
|
||||||
RootBeanDefinition inSecureChannelProcessor = new RootBeanDefinition(InsecureChannelProcessor.class);
|
RootBeanDefinition inSecureChannelProcessor = new RootBeanDefinition(InsecureChannelProcessor.class);
|
||||||
inSecureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttp);
|
inSecureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttp);
|
||||||
|
@ -433,10 +438,8 @@ class HttpConfigurationBuilder {
|
||||||
requestCacheBldr = BeanDefinitionBuilder.rootBeanDefinition(NullRequestCache.class);
|
requestCacheBldr = BeanDefinitionBuilder.rootBeanDefinition(NullRequestCache.class);
|
||||||
} else {
|
} else {
|
||||||
requestCacheBldr = BeanDefinitionBuilder.rootBeanDefinition(HttpSessionRequestCache.class);
|
requestCacheBldr = BeanDefinitionBuilder.rootBeanDefinition(HttpSessionRequestCache.class);
|
||||||
BeanDefinitionBuilder portResolver = BeanDefinitionBuilder.rootBeanDefinition(PortResolverImpl.class);
|
|
||||||
portResolver.addPropertyReference("portMapper", portMapperName);
|
|
||||||
requestCacheBldr.addPropertyValue("createSessionAllowed", sessionPolicy == SessionCreationPolicy.ifRequired);
|
requestCacheBldr.addPropertyValue("createSessionAllowed", sessionPolicy == SessionCreationPolicy.ifRequired);
|
||||||
requestCacheBldr.addPropertyValue("portResolver", portResolver.getBeanDefinition());
|
requestCacheBldr.addPropertyValue("portResolver", portResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
BeanDefinition bean = requestCacheBldr.getBeanDefinition();
|
BeanDefinition bean = requestCacheBldr.getBeanDefinition();
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.springframework.security.config.Elements;
|
||||||
import org.springframework.security.config.authentication.AuthenticationManagerFactoryBean;
|
import org.springframework.security.config.authentication.AuthenticationManagerFactoryBean;
|
||||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||||
import org.springframework.security.web.FilterChainProxy;
|
import org.springframework.security.web.FilterChainProxy;
|
||||||
|
import org.springframework.security.web.PortResolverImpl;
|
||||||
import org.springframework.security.web.util.AnyRequestMatcher;
|
import org.springframework.security.web.util.AnyRequestMatcher;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.util.xml.DomUtils;
|
import org.springframework.util.xml.DomUtils;
|
||||||
|
@ -35,6 +36,7 @@ import java.util.*;
|
||||||
*
|
*
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
|
* @author Rob Winch
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
|
@ -108,17 +110,18 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
return createSecurityFilterChainBean(element, pc, Collections.emptyList());
|
return createSecurityFilterChainBean(element, pc, Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
final String portMapperName = createPortMapper(element, pc);
|
final BeanReference portMapper = createPortMapper(element, pc);
|
||||||
|
final BeanReference portResolver = createPortResolver(portMapper, pc);
|
||||||
|
|
||||||
ManagedList<BeanReference> authenticationProviders = new ManagedList<BeanReference>();
|
ManagedList<BeanReference> authenticationProviders = new ManagedList<BeanReference>();
|
||||||
BeanReference authenticationManager = createAuthenticationManager(element, pc, authenticationProviders);
|
BeanReference authenticationManager = createAuthenticationManager(element, pc, authenticationProviders);
|
||||||
|
|
||||||
HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, pc,
|
HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, pc,
|
||||||
portMapperName, authenticationManager);
|
portMapper, portResolver, authenticationManager);
|
||||||
|
|
||||||
AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, pc,
|
AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, pc,
|
||||||
httpBldr.getSessionCreationPolicy(), httpBldr.getRequestCache(), authenticationManager,
|
httpBldr.getSessionCreationPolicy(), httpBldr.getRequestCache(), authenticationManager,
|
||||||
httpBldr.getSessionStrategy());
|
httpBldr.getSessionStrategy(), portMapper, portResolver);
|
||||||
|
|
||||||
authenticationProviders.addAll(authBldr.getProviders());
|
authenticationProviders.addAll(authBldr.getProviders());
|
||||||
|
|
||||||
|
@ -179,14 +182,22 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
return new RuntimeBeanReference(id);
|
return new RuntimeBeanReference(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createPortMapper(Element elt, ParserContext pc) {
|
private BeanReference createPortMapper(Element elt, ParserContext pc) {
|
||||||
// Register the portMapper. A default will always be created, even if no element exists.
|
// Register the portMapper. A default will always be created, even if no element exists.
|
||||||
BeanDefinition portMapper = new PortMappingsBeanDefinitionParser().parse(
|
BeanDefinition portMapper = new PortMappingsBeanDefinitionParser().parse(
|
||||||
DomUtils.getChildElementByTagName(elt, Elements.PORT_MAPPINGS), pc);
|
DomUtils.getChildElementByTagName(elt, Elements.PORT_MAPPINGS), pc);
|
||||||
String portMapperName = pc.getReaderContext().generateBeanName(portMapper);
|
String portMapperName = pc.getReaderContext().generateBeanName(portMapper);
|
||||||
pc.registerBeanComponent(new BeanComponentDefinition(portMapper, portMapperName));
|
pc.registerBeanComponent(new BeanComponentDefinition(portMapper, portMapperName));
|
||||||
|
|
||||||
return portMapperName;
|
return new RuntimeBeanReference(portMapperName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RuntimeBeanReference createPortResolver(BeanReference portMapper, ParserContext pc) {
|
||||||
|
RootBeanDefinition portResolver = new RootBeanDefinition(PortResolverImpl.class);
|
||||||
|
portResolver.getPropertyValues().addPropertyValue("portMapper", portMapper);
|
||||||
|
String portResolverName = pc.getReaderContext().generateBeanName(portResolver);
|
||||||
|
pc.registerBeanComponent(new BeanComponentDefinition(portResolver, portResolverName));
|
||||||
|
return new RuntimeBeanReference(portResolverName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -688,6 +688,33 @@ class MiscHttpConfigTests extends AbstractHttpConfigTests {
|
||||||
expect:
|
expect:
|
||||||
getFilter(UsernamePasswordAuthenticationFilter.class).authenticationManager.parent instanceof MockAuthenticationManager
|
getFilter(UsernamePasswordAuthenticationFilter.class).authenticationManager.parent instanceof MockAuthenticationManager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SEC-1893
|
||||||
|
def customPortMappings() {
|
||||||
|
when: 'A custom port-mappings is registered'
|
||||||
|
def expectedHttpsPortMappings = [8443:8080]
|
||||||
|
xml.http('auto-config': 'true') {
|
||||||
|
'intercept-url'('pattern':'/**','requires-channel':'https')
|
||||||
|
'port-mappings' {
|
||||||
|
'port-mapping'(http:'8443',https:'8080')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createAppContext()
|
||||||
|
|
||||||
|
then: 'All the components created by the namespace use that port mapping'
|
||||||
|
getFilter(RequestCacheAwareFilter.class).requestCache.portResolver.portMapper.httpsPortMappings == expectedHttpsPortMappings
|
||||||
|
|
||||||
|
def channelProcessors = getFilter(ChannelProcessingFilter.class).channelDecisionManager.channelProcessors
|
||||||
|
channelProcessors.size() == 2
|
||||||
|
channelProcessors.each { cp->
|
||||||
|
cp.entryPoint.portMapper.httpsPortMappings == expectedHttpsPortMappings
|
||||||
|
cp.entryPoint.portResolver.portMapper.httpsPortMappings == expectedHttpsPortMappings
|
||||||
|
}
|
||||||
|
|
||||||
|
def authEntryPoint = getFilter(ExceptionTranslationFilter.class).authenticationEntryPoint
|
||||||
|
authEntryPoint.portMapper.httpsPortMappings == expectedHttpsPortMappings
|
||||||
|
authEntryPoint.portResolver.portMapper.httpsPortMappings == expectedHttpsPortMappings
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockAuthenticationManager implements AuthenticationManager {
|
class MockAuthenticationManager implements AuthenticationManager {
|
||||||
|
|
Loading…
Reference in New Issue