diff --git a/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java b/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java index 5d0f6f3104..5e250b5897 100644 --- a/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java +++ b/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java @@ -47,6 +47,7 @@ import java.util.*; * Handles creation of authentication mechanism filters and related beans for <http> parsing. * * @author Luke Taylor + * @author Rob Winch * @since 3.0 */ final class AuthenticationConfigBuilder { @@ -102,15 +103,19 @@ final class AuthenticationConfigBuilder { private BeanDefinition loginPageGenerationFilter; private BeanDefinition etf; private final BeanReference requestCache; + private final BeanReference portMapper; + private final BeanReference portResolver; 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.pc = pc; this.requestCache = requestCache; autoConfig = "true".equals(element.getAttribute(ATT_AUTO_CONFIG)); this.allowSessionCreation = sessionPolicy != SessionCreationPolicy.never && sessionPolicy != SessionCreationPolicy.stateless; + this.portMapper = portMapper; + this.portResolver = portResolver; createAnonymousFilter(); createRememberMeFilter(authenticationManager); @@ -164,7 +169,7 @@ final class AuthenticationConfigBuilder { if (formLoginElt != null || autoConfig) { 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); formFilter = parser.getFilterBean(); @@ -188,7 +193,7 @@ final class AuthenticationConfigBuilder { if (openIDLoginElt != null) { 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); openIDFilter = parser.getFilterBean(); diff --git a/config/src/main/java/org/springframework/security/config/http/FormLoginBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/http/FormLoginBeanDefinitionParser.java index ee95ef91af..bd1695abb5 100644 --- a/config/src/main/java/org/springframework/security/config/http/FormLoginBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/http/FormLoginBeanDefinitionParser.java @@ -17,6 +17,7 @@ import org.w3c.dom.Element; /** * @author Luke Taylor * @author Ben Alex + * @author Rob Winch */ public class FormLoginBeanDefinitionParser { protected final Log logger = LogFactory.getLog(getClass()); @@ -44,18 +45,22 @@ public class FormLoginBeanDefinitionParser { private final BeanReference requestCache; private final BeanReference sessionStrategy; private final boolean allowSessionCreation; + private final BeanReference portMapper; + private final BeanReference portResolver; private RootBeanDefinition filterBean; private RootBeanDefinition entryPointBean; private String loginPage; 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.filterClassName = filterClassName; this.requestCache = requestCache; this.sessionStrategy = sessionStrategy; this.allowSessionCreation = allowSessionCreation; + this.portMapper = portMapper; + this.portResolver = portResolver; } public BeanDefinition parse(Element elt, ParserContext pc) { @@ -111,6 +116,8 @@ public class FormLoginBeanDefinitionParser { BeanDefinitionBuilder.rootBeanDefinition(LoginUrlAuthenticationEntryPoint.class); entryPointBuilder.getRawBeanDefinition().setSource(source); entryPointBuilder.addPropertyValue("loginFormUrl", loginPage != null ? loginPage : DEF_LOGIN_PAGE); + entryPointBuilder.addPropertyValue("portMapper", portMapper); + entryPointBuilder.addPropertyValue("portResolver", portResolver); entryPointBean = (RootBeanDefinition) entryPointBuilder.getBeanDefinition(); return null; diff --git a/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java b/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java index 690c3c1040..02bad774c9 100644 --- a/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java +++ b/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java @@ -55,6 +55,7 @@ import org.w3c.dom.Element; * Stateful class which helps HttpSecurityBDP to create the configuration for the <http> element. * * @author Luke Taylor + * @author Rob Winch * @since 3.0 */ class HttpConfigurationBuilder { @@ -92,16 +93,18 @@ class HttpConfigurationBuilder { private RootBeanDefinition sfpf; private BeanDefinition servApiFilter; private BeanDefinition jaasApiFilter; - private final String portMapperName; + private final BeanReference portMapper; + private final BeanReference portResolver; private BeanReference fsi; private BeanReference requestCache; public HttpConfigurationBuilder(Element element, ParserContext pc, - String portMapperName, BeanReference authenticationManager) { + BeanReference portMapper, BeanReference portResolver, BeanReference authenticationManager) { this.httpElt = element; this.pc = pc; - this.portMapperName = portMapperName; + this.portMapper = portMapper; + this.portResolver = portResolver; this.matcherType = MatcherType.fromElement(element); interceptUrls = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL); @@ -374,9 +377,11 @@ class HttpConfigurationBuilder { RootBeanDefinition secureChannelProcessor = new RootBeanDefinition(SecureChannelProcessor.class); RootBeanDefinition retryWithHttp = new RootBeanDefinition(RetryWithHttpEntryPoint.class); RootBeanDefinition retryWithHttps = new RootBeanDefinition(RetryWithHttpsEntryPoint.class); - RuntimeBeanReference portMapper = new RuntimeBeanReference(portMapperName); + retryWithHttp.getPropertyValues().addPropertyValue("portMapper", portMapper); + retryWithHttp.getPropertyValues().addPropertyValue("portResolver", portResolver); retryWithHttps.getPropertyValues().addPropertyValue("portMapper", portMapper); + retryWithHttps.getPropertyValues().addPropertyValue("portResolver", portResolver); secureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttps); RootBeanDefinition inSecureChannelProcessor = new RootBeanDefinition(InsecureChannelProcessor.class); inSecureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttp); @@ -433,10 +438,8 @@ class HttpConfigurationBuilder { requestCacheBldr = BeanDefinitionBuilder.rootBeanDefinition(NullRequestCache.class); } else { requestCacheBldr = BeanDefinitionBuilder.rootBeanDefinition(HttpSessionRequestCache.class); - BeanDefinitionBuilder portResolver = BeanDefinitionBuilder.rootBeanDefinition(PortResolverImpl.class); - portResolver.addPropertyReference("portMapper", portMapperName); requestCacheBldr.addPropertyValue("createSessionAllowed", sessionPolicy == SessionCreationPolicy.ifRequired); - requestCacheBldr.addPropertyValue("portResolver", portResolver.getBeanDefinition()); + requestCacheBldr.addPropertyValue("portResolver", portResolver); } BeanDefinition bean = requestCacheBldr.getBeanDefinition(); diff --git a/config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java index ce4a364b4a..93e060cfca 100644 --- a/config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java @@ -23,6 +23,7 @@ import org.springframework.security.config.Elements; import org.springframework.security.config.authentication.AuthenticationManagerFactoryBean; import org.springframework.security.web.DefaultSecurityFilterChain; import org.springframework.security.web.FilterChainProxy; +import org.springframework.security.web.PortResolverImpl; import org.springframework.security.web.util.AnyRequestMatcher; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; @@ -35,6 +36,7 @@ import java.util.*; * * @author Luke Taylor * @author Ben Alex + * @author Rob Winch * @since 2.0 */ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { @@ -108,17 +110,18 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { 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 authenticationProviders = new ManagedList(); BeanReference authenticationManager = createAuthenticationManager(element, pc, authenticationProviders); HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, pc, - portMapperName, authenticationManager); + portMapper, portResolver, authenticationManager); AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, pc, httpBldr.getSessionCreationPolicy(), httpBldr.getRequestCache(), authenticationManager, - httpBldr.getSessionStrategy()); + httpBldr.getSessionStrategy(), portMapper, portResolver); authenticationProviders.addAll(authBldr.getProviders()); @@ -179,14 +182,22 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { 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. BeanDefinition portMapper = new PortMappingsBeanDefinitionParser().parse( DomUtils.getChildElementByTagName(elt, Elements.PORT_MAPPINGS), pc); String portMapperName = pc.getReaderContext().generateBeanName(portMapper); 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); } /** diff --git a/config/src/test/groovy/org/springframework/security/config/http/MiscHttpConfigTests.groovy b/config/src/test/groovy/org/springframework/security/config/http/MiscHttpConfigTests.groovy index 353c878487..194b6f762d 100644 --- a/config/src/test/groovy/org/springframework/security/config/http/MiscHttpConfigTests.groovy +++ b/config/src/test/groovy/org/springframework/security/config/http/MiscHttpConfigTests.groovy @@ -688,6 +688,33 @@ class MiscHttpConfigTests extends AbstractHttpConfigTests { expect: 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 {