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

This commit is contained in:
Rob Winch 2012-03-11 20:52:17 -05:00
parent 84141c4c76
commit f78c11650f
5 changed files with 69 additions and 16 deletions
config/src

View File

@ -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();

View File

@ -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;

View File

@ -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();

View File

@ -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);
} }
/** /**

View File

@ -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 {