SEC-628: Added port-mappings element to allow use of a PortMapper.
This commit is contained in:
parent
60b7e2d4f2
commit
9e21c48fce
|
@ -43,4 +43,5 @@ public abstract class BeanIds {
|
|||
public static final String METHOD_DEFINITION_ATTRIBUTES = "_methodDefinitionAttributes";
|
||||
public static final String EMBEDDED_APACHE_DS = "_apacheDirectoryServerContainer";
|
||||
public static final String CONTEXT_SOURCE = "_securityContextSource";
|
||||
public static final String PORT_MAPPER = "_portMapper";
|
||||
}
|
||||
|
|
|
@ -27,4 +27,6 @@ abstract class Elements {
|
|||
public static final String ANNOTATION_DRIVEN = "annotation-driven";
|
||||
public static final String PASSWORD_ENCODER = "password-encoder";
|
||||
public static final String SALT_SOURCE = "salt-source";
|
||||
public static final String PORT_MAPPINGS = "port-mappings";
|
||||
public static final String PORT_MAPPING = "port-mapping";
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package org.springframework.security.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
|
@ -12,6 +11,7 @@ import org.springframework.beans.factory.config.RuntimeBeanReference;
|
|||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
|
@ -27,6 +27,8 @@ import org.springframework.security.securechannel.ChannelDecisionManagerImpl;
|
|||
import org.springframework.security.securechannel.ChannelProcessingFilter;
|
||||
import org.springframework.security.securechannel.InsecureChannelProcessor;
|
||||
import org.springframework.security.securechannel.SecureChannelProcessor;
|
||||
import org.springframework.security.securechannel.RetryWithHttpEntryPoint;
|
||||
import org.springframework.security.securechannel.RetryWithHttpsEntryPoint;
|
||||
import org.springframework.security.ui.ExceptionTranslationFilter;
|
||||
import org.springframework.security.util.FilterChainProxy;
|
||||
import org.springframework.security.util.RegexUrlPathMatcher;
|
||||
|
@ -76,9 +78,16 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||
static final String ATT_ACCESS_MGR = "access-decision-manager";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionRegistry registry = parserContext.getRegistry();
|
||||
RootBeanDefinition filterChainProxy = new RootBeanDefinition(FilterChainProxy.class);
|
||||
RootBeanDefinition httpScif = new RootBeanDefinition(HttpSessionContextIntegrationFilter.class);
|
||||
|
||||
BeanDefinition portMapper = new PortMappingsBeanDefinitionParser().parse(
|
||||
DomUtils.getChildElementByTagName(element, Elements.PORT_MAPPINGS), parserContext);
|
||||
registry.registerBeanDefinition(BeanIds.PORT_MAPPER, portMapper);
|
||||
|
||||
RuntimeBeanReference portMapperRef = new RuntimeBeanReference(BeanIds.PORT_MAPPER);
|
||||
|
||||
String createSession = element.getAttribute(ATT_CREATE_SESSION);
|
||||
if (OPT_CREATE_SESSION_ALWAYS.equals(createSession)) {
|
||||
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.TRUE);
|
||||
|
@ -157,8 +166,6 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||
parseInterceptUrls(DomUtils.getChildElementsByTagName(element, "intercept-url"),
|
||||
filterChainMap, interceptorFilterInvDefSource, channelFilterInvDefSource, parserContext);
|
||||
|
||||
BeanDefinitionRegistry registry = parserContext.getRegistry();
|
||||
|
||||
// Check if we need to register the channel processing beans
|
||||
if (((AbstractFilterInvocationDefinitionSource)channelFilterInvDefSource).getMapSize() > 0) {
|
||||
// At least one channel requirement has been specified
|
||||
|
@ -169,9 +176,17 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||
channelFilter.getPropertyValues().addPropertyValue("filterInvocationDefinitionSource",
|
||||
channelFilterInvDefSource);
|
||||
RootBeanDefinition channelDecisionManager = new RootBeanDefinition(ChannelDecisionManagerImpl.class);
|
||||
List channelProcessors = new ArrayList(2);
|
||||
channelProcessors.add(new SecureChannelProcessor());
|
||||
channelProcessors.add(new InsecureChannelProcessor());
|
||||
ManagedList channelProcessors = new ManagedList(2);
|
||||
RootBeanDefinition secureChannelProcessor = new RootBeanDefinition(SecureChannelProcessor.class);
|
||||
RootBeanDefinition retryWithHttp = new RootBeanDefinition(RetryWithHttpEntryPoint.class);
|
||||
RootBeanDefinition retryWithHttps = new RootBeanDefinition(RetryWithHttpsEntryPoint.class);
|
||||
retryWithHttp.getPropertyValues().addPropertyValue("portMapper", portMapperRef);
|
||||
retryWithHttps.getPropertyValues().addPropertyValue("portMapper", portMapperRef);
|
||||
secureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttps);
|
||||
RootBeanDefinition inSecureChannelProcessor = new RootBeanDefinition(InsecureChannelProcessor.class);
|
||||
inSecureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttp);
|
||||
channelProcessors.add(secureChannelProcessor);
|
||||
channelProcessors.add(inSecureChannelProcessor);
|
||||
channelDecisionManager.getPropertyValues().addPropertyValue("channelProcessors", channelProcessors);
|
||||
|
||||
registry.registerBeanDefinition(BeanIds.CHANNEL_PROCESSING_FILTER, channelFilter);
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.security.util.PortMapperImpl;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Parses a port-mappings element, producing a single {@link org.springframework.security.util.PortMapperImpl}
|
||||
* bean.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class PortMappingsBeanDefinitionParser implements BeanDefinitionParser {
|
||||
public static final String ATT_HTTP_PORT = "http";
|
||||
public static final String ATT_HTTPS_PORT = "https";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
BeanDefinition portMapper = new RootBeanDefinition(PortMapperImpl.class);
|
||||
|
||||
if (element != null) {
|
||||
List mappingElts = DomUtils.getChildElementsByTagName(element, Elements.PORT_MAPPING);
|
||||
Assert.notEmpty(mappingElts, "No port-mapping child elements!");
|
||||
Map mappings = new HashMap();
|
||||
|
||||
Iterator iterator = mappingElts.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Element elt = (Element) iterator.next();
|
||||
String httpPort = elt.getAttribute(ATT_HTTP_PORT);
|
||||
String httpsPort = elt.getAttribute(ATT_HTTPS_PORT);
|
||||
Assert.notNull(httpPort, "No http port supplied in mapping");
|
||||
Assert.notNull(httpsPort, "No https port supplied in mapping");
|
||||
|
||||
mappings.put(httpPort, httpsPort);
|
||||
}
|
||||
|
||||
portMapper.getPropertyValues().addPropertyValue("portMappings", mappings);
|
||||
}
|
||||
|
||||
return portMapper;
|
||||
}
|
||||
}
|
|
@ -23,9 +23,10 @@ import java.util.Map;
|
|||
|
||||
|
||||
/**
|
||||
* Concrete implementation of {@link PortMapper} that obtains HTTP:HTTPS pairs from the application context.<P>By
|
||||
* default the implementation will assume 80:443 and 8080:8443 are HTTP:HTTPS pairs respectively. If different pairs
|
||||
* are required, use {@link #setPortMappings(Map)}.</p>
|
||||
* Concrete implementation of {@link PortMapper} that obtains HTTP:HTTPS pairs from the application context.
|
||||
* <p>
|
||||
* By default the implementation will assume 80:443 and 8080:8443 are HTTP:HTTPS pairs respectively. If different pairs
|
||||
* are required, use {@link #setPortMappings(Map)}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author colin sampaleanu
|
||||
|
@ -75,10 +76,15 @@ public class PortMapperImpl implements PortMapper {
|
|||
}
|
||||
|
||||
/**
|
||||
* <p>Set to override the default HTTP port to HTTPS port mappings of 80:443, and 8080:8443.</p>
|
||||
* In a Spring XML ApplicationContext, a definition would look something like this:<pre>
|
||||
* <property name="portMappings"> <map> <entry key="80"><value>443</value></entry>
|
||||
* <entry key="8080"><value>8443</value></entry> </map> </property></pre>
|
||||
* Set to override the default HTTP port to HTTPS port mappings of 80:443, and 8080:8443.
|
||||
* In a Spring XML ApplicationContext, a definition would look something like this:
|
||||
* <pre>
|
||||
* <property name="portMappings">
|
||||
* <map>
|
||||
* <entry key="80"><value>443</value></entry>
|
||||
* <entry key="8080"><value>8443</value></entry>
|
||||
* </map>
|
||||
* </property></pre>
|
||||
*
|
||||
* @param newMappings A Map consisting of String keys and String values, where for each entry the key is the string
|
||||
* representation of an integer HTTP port number, and the value is the string representation of the
|
||||
|
|
|
@ -97,7 +97,7 @@ annotation-driven.attlist &=
|
|||
|
||||
http =
|
||||
## Container element for HTTP security configuration
|
||||
element http {http.attlist, (intercept-url+ & form-login? & http-basic? & logout? & concurrent-session-control? & remember-me? & anonymous?) }
|
||||
element http {http.attlist, (intercept-url+ & form-login? & http-basic? & logout? & concurrent-session-control? & remember-me? & anonymous? & port-mappings) }
|
||||
http.attlist &=
|
||||
## Automatically registers a login form, BASIC authentication, anonymous authentication, logout services, remember-me and servlet-api-integration. If set to "true", all of these capabilities are added (although you can still customize the configuration of each by providing the respective element). If unspecified, defaults to "false".
|
||||
attribute auto-config {"true" | "false" }?
|
||||
|
@ -239,6 +239,18 @@ user.attlist &=
|
|||
## One of more authorities granted to the user. Separate authorities with a comma (but no space). For example, "ROLE_USER,ROLE_ADMINISTRATOR"
|
||||
attribute authorities {xsd:string}
|
||||
|
||||
port-mappings =
|
||||
## Defines the list of mappings between http and https ports for use in redirects
|
||||
element port-mappings {port-mappings.attlist, port-mapping+}
|
||||
|
||||
port-mappings.attlist &= empty
|
||||
|
||||
port-mapping =
|
||||
element port-mapping {http-port, https-port}
|
||||
|
||||
http-port = attribute http {xsd:integer}
|
||||
|
||||
https-port = attribute https {xsd:integer}
|
||||
|
||||
jdbc-user-service =
|
||||
## Causes creation of a JDBC-based UserDetailsService.
|
||||
|
|
|
@ -258,6 +258,7 @@
|
|||
<xs:element ref="security:concurrent-session-control"/>
|
||||
<xs:element ref="security:remember-me"/>
|
||||
<xs:element ref="security:anonymous"/>
|
||||
<xs:element ref="security:port-mappings"/>
|
||||
</xs:choice>
|
||||
<xs:attributeGroup ref="security:http.attlist"/>
|
||||
</xs:complexType>
|
||||
|
@ -585,6 +586,28 @@
|
|||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="port-mappings">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Defines the list of mappings between http and https ports for use in redirects</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element maxOccurs="unbounded" ref="security:port-mapping"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="port-mapping">
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:http-port"/>
|
||||
<xs:attributeGroup ref="security:https-port"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:attributeGroup name="http-port">
|
||||
<xs:attribute name="http" use="required" type="xs:integer"/>
|
||||
</xs:attributeGroup>
|
||||
<xs:attributeGroup name="https-port">
|
||||
<xs:attribute name="https" use="required" type="xs:integer"/>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="jdbc-user-service">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Causes creation of a JDBC-based UserDetailsService.</xs:documentation>
|
||||
|
|
|
@ -4,6 +4,10 @@ import org.springframework.security.concurrent.ConcurrentSessionFilter;
|
|||
import org.springframework.security.context.HttpSessionContextIntegrationFilter;
|
||||
import org.springframework.security.intercept.web.FilterSecurityInterceptor;
|
||||
import org.springframework.security.securechannel.ChannelProcessingFilter;
|
||||
import org.springframework.security.securechannel.ChannelDecisionManager;
|
||||
import org.springframework.security.securechannel.ChannelDecisionManagerImpl;
|
||||
import org.springframework.security.securechannel.SecureChannelProcessor;
|
||||
import org.springframework.security.securechannel.RetryWithHttpsEntryPoint;
|
||||
import org.springframework.security.ui.ExceptionTranslationFilter;
|
||||
import org.springframework.security.ui.basicauth.BasicProcessingFilter;
|
||||
import org.springframework.security.ui.logout.LogoutFilter;
|
||||
|
@ -11,9 +15,11 @@ import org.springframework.security.ui.rememberme.RememberMeProcessingFilter;
|
|||
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;
|
||||
import org.springframework.security.ui.webapp.DefaultLoginPageGeneratingFilter;
|
||||
import org.springframework.security.util.FilterChainProxy;
|
||||
import org.springframework.security.util.PortMapperImpl;
|
||||
import org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
@ -79,5 +85,14 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||
assertTrue(filters.next() instanceof RememberMeProcessingFilter);
|
||||
assertTrue(filters.next() instanceof ExceptionTranslationFilter);
|
||||
assertTrue(filters.next() instanceof FilterSecurityInterceptor);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void portMappingsAreParsedCorrectly() throws Exception {
|
||||
PortMapperImpl pm = (PortMapperImpl) appContext.getBean(BeanIds.PORT_MAPPER);
|
||||
assertEquals(1, pm.getTranslatedPortMappings().size());
|
||||
assertEquals(Integer.valueOf(9080), pm.lookupHttpPort(9443));
|
||||
assertEquals(Integer.valueOf(9443), pm.lookupHttpsPort(9080));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,10 @@ http://www.springframework.org/schema/security http://www.springframework.org/sc
|
|||
<concurrent-session-control max-sessions="1"/>
|
||||
|
||||
<remember-me key="doesntmatter" token-repository="tokenRepo"/>
|
||||
|
||||
<port-mappings>
|
||||
<port-mapping http="9080" https="9443"/>
|
||||
</port-mappings>
|
||||
</http>
|
||||
|
||||
<authentication-provider>
|
||||
|
|
Loading…
Reference in New Issue