Skip to content

Commit f78c116

Browse files
committed
SEC-1893: Namespace now register PortMapper with custom mappings for all components that use a PortMapper
1 parent 84141c4 commit f78c116

File tree

5 files changed

+69
-16
lines changed

5 files changed

+69
-16
lines changed

config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
* Handles creation of authentication mechanism filters and related beans for <http> parsing.
4848
*
4949
* @author Luke Taylor
50+
* @author Rob Winch
5051
* @since 3.0
5152
*/
5253
final class AuthenticationConfigBuilder {
@@ -102,15 +103,19 @@ final class AuthenticationConfigBuilder {
102103
private BeanDefinition loginPageGenerationFilter;
103104
private BeanDefinition etf;
104105
private final BeanReference requestCache;
106+
private final BeanReference portMapper;
107+
private final BeanReference portResolver;
105108

106109
public AuthenticationConfigBuilder(Element element, ParserContext pc, SessionCreationPolicy sessionPolicy,
107-
BeanReference requestCache, BeanReference authenticationManager, BeanReference sessionStrategy) {
110+
BeanReference requestCache, BeanReference authenticationManager, BeanReference sessionStrategy, BeanReference portMapper, BeanReference portResolver) {
108111
this.httpElt = element;
109112
this.pc = pc;
110113
this.requestCache = requestCache;
111114
autoConfig = "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
112115
this.allowSessionCreation = sessionPolicy != SessionCreationPolicy.never
113116
&& sessionPolicy != SessionCreationPolicy.stateless;
117+
this.portMapper = portMapper;
118+
this.portResolver = portResolver;
114119

115120
createAnonymousFilter();
116121
createRememberMeFilter(authenticationManager);
@@ -164,7 +169,7 @@ void createFormLoginFilter(BeanReference sessionStrategy, BeanReference authMana
164169

165170
if (formLoginElt != null || autoConfig) {
166171
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
167-
AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation);
172+
AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation, portMapper, portResolver);
168173

169174
parser.parse(formLoginElt, pc);
170175
formFilter = parser.getFilterBean();
@@ -188,7 +193,7 @@ void createOpenIDLoginFilter(BeanReference sessionStrategy, BeanReference authMa
188193

189194
if (openIDLoginElt != null) {
190195
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
191-
OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation);
196+
OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation, portMapper, portResolver);
192197

193198
parser.parse(openIDLoginElt, pc);
194199
openIDFilter = parser.getFilterBean();

config/src/main/java/org/springframework/security/config/http/FormLoginBeanDefinitionParser.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
/**
1818
* @author Luke Taylor
1919
* @author Ben Alex
20+
* @author Rob Winch
2021
*/
2122
public class FormLoginBeanDefinitionParser {
2223
protected final Log logger = LogFactory.getLog(getClass());
@@ -44,18 +45,22 @@ public class FormLoginBeanDefinitionParser {
4445
private final BeanReference requestCache;
4546
private final BeanReference sessionStrategy;
4647
private final boolean allowSessionCreation;
48+
private final BeanReference portMapper;
49+
private final BeanReference portResolver;
4750

4851
private RootBeanDefinition filterBean;
4952
private RootBeanDefinition entryPointBean;
5053
private String loginPage;
5154

5255
FormLoginBeanDefinitionParser(String defaultLoginProcessingUrl, String filterClassName,
53-
BeanReference requestCache, BeanReference sessionStrategy, boolean allowSessionCreation) {
56+
BeanReference requestCache, BeanReference sessionStrategy, boolean allowSessionCreation, BeanReference portMapper, BeanReference portResolver) {
5457
this.defaultLoginProcessingUrl = defaultLoginProcessingUrl;
5558
this.filterClassName = filterClassName;
5659
this.requestCache = requestCache;
5760
this.sessionStrategy = sessionStrategy;
5861
this.allowSessionCreation = allowSessionCreation;
62+
this.portMapper = portMapper;
63+
this.portResolver = portResolver;
5964
}
6065

6166
public BeanDefinition parse(Element elt, ParserContext pc) {
@@ -111,6 +116,8 @@ public BeanDefinition parse(Element elt, ParserContext pc) {
111116
BeanDefinitionBuilder.rootBeanDefinition(LoginUrlAuthenticationEntryPoint.class);
112117
entryPointBuilder.getRawBeanDefinition().setSource(source);
113118
entryPointBuilder.addPropertyValue("loginFormUrl", loginPage != null ? loginPage : DEF_LOGIN_PAGE);
119+
entryPointBuilder.addPropertyValue("portMapper", portMapper);
120+
entryPointBuilder.addPropertyValue("portResolver", portResolver);
114121
entryPointBean = (RootBeanDefinition) entryPointBuilder.getBeanDefinition();
115122

116123
return null;

config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
* Stateful class which helps HttpSecurityBDP to create the configuration for the <http> element.
5656
*
5757
* @author Luke Taylor
58+
* @author Rob Winch
5859
* @since 3.0
5960
*/
6061
class HttpConfigurationBuilder {
@@ -92,16 +93,18 @@ class HttpConfigurationBuilder {
9293
private RootBeanDefinition sfpf;
9394
private BeanDefinition servApiFilter;
9495
private BeanDefinition jaasApiFilter;
95-
private final String portMapperName;
96+
private final BeanReference portMapper;
97+
private final BeanReference portResolver;
9698
private BeanReference fsi;
9799
private BeanReference requestCache;
98100

99101
public HttpConfigurationBuilder(Element element, ParserContext pc,
100-
String portMapperName, BeanReference authenticationManager) {
102+
BeanReference portMapper, BeanReference portResolver, BeanReference authenticationManager) {
101103

102104
this.httpElt = element;
103105
this.pc = pc;
104-
this.portMapperName = portMapperName;
106+
this.portMapper = portMapper;
107+
this.portResolver = portResolver;
105108
this.matcherType = MatcherType.fromElement(element);
106109
interceptUrls = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL);
107110

@@ -374,9 +377,11 @@ private void createChannelProcessingFilter() {
374377
RootBeanDefinition secureChannelProcessor = new RootBeanDefinition(SecureChannelProcessor.class);
375378
RootBeanDefinition retryWithHttp = new RootBeanDefinition(RetryWithHttpEntryPoint.class);
376379
RootBeanDefinition retryWithHttps = new RootBeanDefinition(RetryWithHttpsEntryPoint.class);
377-
RuntimeBeanReference portMapper = new RuntimeBeanReference(portMapperName);
380+
378381
retryWithHttp.getPropertyValues().addPropertyValue("portMapper", portMapper);
382+
retryWithHttp.getPropertyValues().addPropertyValue("portResolver", portResolver);
379383
retryWithHttps.getPropertyValues().addPropertyValue("portMapper", portMapper);
384+
retryWithHttps.getPropertyValues().addPropertyValue("portResolver", portResolver);
380385
secureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttps);
381386
RootBeanDefinition inSecureChannelProcessor = new RootBeanDefinition(InsecureChannelProcessor.class);
382387
inSecureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttp);
@@ -433,10 +438,8 @@ private void createRequestCacheFilter() {
433438
requestCacheBldr = BeanDefinitionBuilder.rootBeanDefinition(NullRequestCache.class);
434439
} else {
435440
requestCacheBldr = BeanDefinitionBuilder.rootBeanDefinition(HttpSessionRequestCache.class);
436-
BeanDefinitionBuilder portResolver = BeanDefinitionBuilder.rootBeanDefinition(PortResolverImpl.class);
437-
portResolver.addPropertyReference("portMapper", portMapperName);
438441
requestCacheBldr.addPropertyValue("createSessionAllowed", sessionPolicy == SessionCreationPolicy.ifRequired);
439-
requestCacheBldr.addPropertyValue("portResolver", portResolver.getBeanDefinition());
442+
requestCacheBldr.addPropertyValue("portResolver", portResolver);
440443
}
441444

442445
BeanDefinition bean = requestCacheBldr.getBeanDefinition();

config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.springframework.security.config.authentication.AuthenticationManagerFactoryBean;
2424
import org.springframework.security.web.DefaultSecurityFilterChain;
2525
import org.springframework.security.web.FilterChainProxy;
26+
import org.springframework.security.web.PortResolverImpl;
2627
import org.springframework.security.web.util.AnyRequestMatcher;
2728
import org.springframework.util.StringUtils;
2829
import org.springframework.util.xml.DomUtils;
@@ -35,6 +36,7 @@
3536
*
3637
* @author Luke Taylor
3738
* @author Ben Alex
39+
* @author Rob Winch
3840
* @since 2.0
3941
*/
4042
public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
@@ -108,17 +110,18 @@ private BeanReference createFilterChain(Element element, ParserContext pc) {
108110
return createSecurityFilterChainBean(element, pc, Collections.emptyList());
109111
}
110112

111-
final String portMapperName = createPortMapper(element, pc);
113+
final BeanReference portMapper = createPortMapper(element, pc);
114+
final BeanReference portResolver = createPortResolver(portMapper, pc);
112115

113116
ManagedList<BeanReference> authenticationProviders = new ManagedList<BeanReference>();
114117
BeanReference authenticationManager = createAuthenticationManager(element, pc, authenticationProviders);
115118

116119
HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, pc,
117-
portMapperName, authenticationManager);
120+
portMapper, portResolver, authenticationManager);
118121

119122
AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, pc,
120123
httpBldr.getSessionCreationPolicy(), httpBldr.getRequestCache(), authenticationManager,
121-
httpBldr.getSessionStrategy());
124+
httpBldr.getSessionStrategy(), portMapper, portResolver);
122125

123126
authenticationProviders.addAll(authBldr.getProviders());
124127

@@ -179,14 +182,22 @@ private BeanReference createSecurityFilterChainBean(Element element, ParserConte
179182
return new RuntimeBeanReference(id);
180183
}
181184

182-
private String createPortMapper(Element elt, ParserContext pc) {
185+
private BeanReference createPortMapper(Element elt, ParserContext pc) {
183186
// Register the portMapper. A default will always be created, even if no element exists.
184187
BeanDefinition portMapper = new PortMappingsBeanDefinitionParser().parse(
185188
DomUtils.getChildElementByTagName(elt, Elements.PORT_MAPPINGS), pc);
186189
String portMapperName = pc.getReaderContext().generateBeanName(portMapper);
187190
pc.registerBeanComponent(new BeanComponentDefinition(portMapper, portMapperName));
188191

189-
return portMapperName;
192+
return new RuntimeBeanReference(portMapperName);
193+
}
194+
195+
private RuntimeBeanReference createPortResolver(BeanReference portMapper, ParserContext pc) {
196+
RootBeanDefinition portResolver = new RootBeanDefinition(PortResolverImpl.class);
197+
portResolver.getPropertyValues().addPropertyValue("portMapper", portMapper);
198+
String portResolverName = pc.getReaderContext().generateBeanName(portResolver);
199+
pc.registerBeanComponent(new BeanComponentDefinition(portResolver, portResolverName));
200+
return new RuntimeBeanReference(portResolverName);
190201
}
191202

192203
/**

config/src/test/groovy/org/springframework/security/config/http/MiscHttpConfigTests.groovy

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,33 @@ class MiscHttpConfigTests extends AbstractHttpConfigTests {
688688
expect:
689689
getFilter(UsernamePasswordAuthenticationFilter.class).authenticationManager.parent instanceof MockAuthenticationManager
690690
}
691+
692+
// SEC-1893
693+
def customPortMappings() {
694+
when: 'A custom port-mappings is registered'
695+
def expectedHttpsPortMappings = [8443:8080]
696+
xml.http('auto-config': 'true') {
697+
'intercept-url'('pattern':'/**','requires-channel':'https')
698+
'port-mappings' {
699+
'port-mapping'(http:'8443',https:'8080')
700+
}
701+
}
702+
createAppContext()
703+
704+
then: 'All the components created by the namespace use that port mapping'
705+
getFilter(RequestCacheAwareFilter.class).requestCache.portResolver.portMapper.httpsPortMappings == expectedHttpsPortMappings
706+
707+
def channelProcessors = getFilter(ChannelProcessingFilter.class).channelDecisionManager.channelProcessors
708+
channelProcessors.size() == 2
709+
channelProcessors.each { cp->
710+
cp.entryPoint.portMapper.httpsPortMappings == expectedHttpsPortMappings
711+
cp.entryPoint.portResolver.portMapper.httpsPortMappings == expectedHttpsPortMappings
712+
}
713+
714+
def authEntryPoint = getFilter(ExceptionTranslationFilter.class).authenticationEntryPoint
715+
authEntryPoint.portMapper.httpsPortMappings == expectedHttpsPortMappings
716+
authEntryPoint.portResolver.portMapper.httpsPortMappings == expectedHttpsPortMappings
717+
}
691718
}
692719

693720
class MockAuthenticationManager implements AuthenticationManager {

0 commit comments

Comments
 (0)