Browse Source

SEC-1893: Namespace now register PortMapper with custom mappings for all components that use a PortMapper

Rob Winch 13 years ago
parent
commit
f78c11650f

+ 8 - 3
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();

+ 8 - 1
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;

+ 10 - 7
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();

+ 16 - 5
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<BeanReference> authenticationProviders = new ManagedList<BeanReference>();
         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);
     }
 
     /**

+ 27 - 0
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 {