mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-25 21:42:17 +00:00
SEC-1309: Namespace configurations should support Spring EL. Removed premature conversion of URL paths to lower case, which messes up if they are case-sensitive expressions or placeholders. Some other minor changes to suppport EL configuration.
This commit is contained in:
parent
8a0f69b955
commit
eddde8ea28
@ -65,11 +65,10 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
|||||||
|
|
||||||
static BeanDefinition createSecurityMetadataSource(List<Element> interceptUrls, Element elt, ParserContext pc) {
|
static BeanDefinition createSecurityMetadataSource(List<Element> interceptUrls, Element elt, ParserContext pc) {
|
||||||
UrlMatcher matcher = HttpSecurityBeanDefinitionParser.createUrlMatcher(elt);
|
UrlMatcher matcher = HttpSecurityBeanDefinitionParser.createUrlMatcher(elt);
|
||||||
boolean convertPathsToLowerCase = (matcher instanceof AntUrlPathMatcher) && matcher.requiresLowerCaseUrl();
|
|
||||||
boolean useExpressions = isUseExpressions(elt);
|
boolean useExpressions = isUseExpressions(elt);
|
||||||
|
|
||||||
ManagedMap<BeanDefinition, BeanDefinition> requestToAttributesMap = parseInterceptUrlsForFilterInvocationRequestMap(
|
ManagedMap<BeanDefinition, BeanDefinition> requestToAttributesMap = parseInterceptUrlsForFilterInvocationRequestMap(
|
||||||
interceptUrls, convertPathsToLowerCase, useExpressions, pc);
|
interceptUrls, useExpressions, pc);
|
||||||
BeanDefinitionBuilder fidsBuilder;
|
BeanDefinitionBuilder fidsBuilder;
|
||||||
|
|
||||||
if (useExpressions) {
|
if (useExpressions) {
|
||||||
@ -105,7 +104,7 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static ManagedMap<BeanDefinition, BeanDefinition> parseInterceptUrlsForFilterInvocationRequestMap(List<Element> urlElts,
|
private static ManagedMap<BeanDefinition, BeanDefinition> parseInterceptUrlsForFilterInvocationRequestMap(List<Element> urlElts,
|
||||||
boolean useLowerCasePaths, boolean useExpressions, ParserContext parserContext) {
|
boolean useExpressions, ParserContext parserContext) {
|
||||||
|
|
||||||
ManagedMap<BeanDefinition, BeanDefinition> filterInvocationDefinitionMap = new ManagedMap<BeanDefinition, BeanDefinition>();
|
ManagedMap<BeanDefinition, BeanDefinition> filterInvocationDefinitionMap = new ManagedMap<BeanDefinition, BeanDefinition>();
|
||||||
|
|
||||||
@ -121,17 +120,11 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
|||||||
parserContext.getReaderContext().error("path attribute cannot be empty or null", urlElt);
|
parserContext.getReaderContext().error("path attribute cannot be empty or null", urlElt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useLowerCasePaths) {
|
|
||||||
path = path.toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
String method = urlElt.getAttribute(ATT_HTTP_METHOD);
|
String method = urlElt.getAttribute(ATT_HTTP_METHOD);
|
||||||
if (!StringUtils.hasText(method)) {
|
if (!StringUtils.hasText(method)) {
|
||||||
method = null;
|
method = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use beans to
|
|
||||||
|
|
||||||
BeanDefinitionBuilder keyBldr = BeanDefinitionBuilder.rootBeanDefinition(RequestKey.class);
|
BeanDefinitionBuilder keyBldr = BeanDefinitionBuilder.rootBeanDefinition(RequestKey.class);
|
||||||
keyBldr.addConstructorArgValue(path);
|
keyBldr.addConstructorArgValue(path);
|
||||||
keyBldr.addConstructorArgValue(method);
|
keyBldr.addConstructorArgValue(method);
|
||||||
@ -141,7 +134,7 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
|||||||
|
|
||||||
if (useExpressions) {
|
if (useExpressions) {
|
||||||
logger.info("Creating access control expression attribute '" + access + "' for " + path);
|
logger.info("Creating access control expression attribute '" + access + "' for " + path);
|
||||||
// The expression will be parsed later by the ExpressionFilterInvocationSecurityMetadataSource
|
// The single expression will be parsed later by the ExpressionFilterInvocationSecurityMetadataSource
|
||||||
attributeBuilder.setFactoryMethod("createList");
|
attributeBuilder.setFactoryMethod("createList");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -160,5 +153,4 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
|||||||
return filterInvocationDefinitionMap;
|
return filterInvocationDefinitionMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,18 @@
|
|||||||
package org.springframework.security.config.http;
|
package org.springframework.security.config.http;
|
||||||
|
|
||||||
import org.springframework.security.config.Elements;
|
|
||||||
import org.springframework.security.web.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.StringUtils;
|
|
||||||
import org.springframework.util.xml.DomUtils;
|
|
||||||
|
|
||||||
import org.w3c.dom.Element;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.HashMap;
|
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.beans.factory.support.ManagedMap;
|
||||||
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
|
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||||
|
import org.springframework.beans.factory.xml.ParserContext;
|
||||||
|
import org.springframework.security.config.Elements;
|
||||||
|
import org.springframework.security.web.PortMapperImpl;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.util.xml.DomUtils;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a port-mappings element, producing a single {@link org.springframework.security.web.PortMapperImpl}
|
* Parses a port-mappings element, producing a single {@link org.springframework.security.web.PortMapperImpl}
|
||||||
@ -37,7 +36,7 @@ class PortMappingsBeanDefinitionParser implements BeanDefinitionParser {
|
|||||||
parserContext.getReaderContext().error("No port-mapping child elements specified", element);
|
parserContext.getReaderContext().error("No port-mapping child elements specified", element);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map mappings = new HashMap();
|
Map mappings = new ManagedMap();
|
||||||
|
|
||||||
for (Element elt : mappingElts) {
|
for (Element elt : mappingElts) {
|
||||||
String httpPort = elt.getAttribute(ATT_HTTP_PORT);
|
String httpPort = elt.getAttribute(ATT_HTTP_PORT);
|
||||||
|
@ -329,7 +329,7 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||||||
// SEC-1201
|
// SEC-1201
|
||||||
@Test
|
@Test
|
||||||
public void interceptUrlsAndFormLoginSupportPropertyPlaceholders() throws Exception {
|
public void interceptUrlsAndFormLoginSupportPropertyPlaceholders() throws Exception {
|
||||||
System.setProperty("secure.url", "/secure");
|
System.setProperty("secure.Url", "/Secure");
|
||||||
System.setProperty("secure.role", "ROLE_A");
|
System.setProperty("secure.role", "ROLE_A");
|
||||||
System.setProperty("login.page", "/loginPage");
|
System.setProperty("login.page", "/loginPage");
|
||||||
System.setProperty("default.target", "/defaultTarget");
|
System.setProperty("default.target", "/defaultTarget");
|
||||||
@ -337,11 +337,32 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||||||
setContext(
|
setContext(
|
||||||
"<b:bean class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
"<b:bean class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
||||||
"<http>" +
|
"<http>" +
|
||||||
" <intercept-url pattern='${secure.url}' access='${secure.role}' />" +
|
" <intercept-url pattern='${secure.Url}' access='${secure.role}' />" +
|
||||||
" <form-login login-page='${login.page}' default-target-url='${default.target}' " +
|
" <form-login login-page='${login.page}' default-target-url='${default.target}' " +
|
||||||
" authentication-failure-url='${auth.failure}' />" +
|
" authentication-failure-url='${auth.failure}' />" +
|
||||||
"</http>" + AUTH_PROVIDER_XML);
|
"</http>" + AUTH_PROVIDER_XML);
|
||||||
|
checkPropertyValues() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SEC-1309
|
||||||
|
@Test
|
||||||
|
public void interceptUrlsAndFormLoginSupportEL() throws Exception {
|
||||||
|
System.setProperty("secure.url", "/Secure");
|
||||||
|
System.setProperty("secure.role", "ROLE_A");
|
||||||
|
System.setProperty("login.page", "/loginPage");
|
||||||
|
System.setProperty("default.target", "/defaultTarget");
|
||||||
|
System.setProperty("auth.failure", "/authFailure");
|
||||||
|
setContext(
|
||||||
|
"<b:bean class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
||||||
|
"<http>" +
|
||||||
|
" <intercept-url pattern=\"#{systemProperties['secure.url']}\" access=\"#{systemProperties['secure.role']}\" />" +
|
||||||
|
" <form-login login-page=\"#{systemProperties['login.page']}\" default-target-url=\"#{systemProperties['default.target']}\" " +
|
||||||
|
" authentication-failure-url=\"#{systemProperties['auth.failure']}\" />" +
|
||||||
|
"</http>" + AUTH_PROVIDER_XML);
|
||||||
|
checkPropertyValues() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkPropertyValues() throws Exception {
|
||||||
// Check the security attribute
|
// Check the security attribute
|
||||||
FilterSecurityInterceptor fis = (FilterSecurityInterceptor) getFilter(FilterSecurityInterceptor.class);
|
FilterSecurityInterceptor fis = (FilterSecurityInterceptor) getFilter(FilterSecurityInterceptor.class);
|
||||||
FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource();
|
FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource();
|
||||||
@ -452,14 +473,14 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void portMappingsWorkWithPlaceholders() throws Exception {
|
public void portMappingsWorkWithPlaceholdersAndEL() throws Exception {
|
||||||
System.setProperty("http", "9080");
|
System.setProperty("http", "9080");
|
||||||
System.setProperty("https", "9443");
|
System.setProperty("https", "9443");
|
||||||
setContext(
|
setContext(
|
||||||
" <b:bean id='configurer' class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
" <b:bean id='configurer' class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
||||||
" <http auto-config='true'>" +
|
" <http auto-config='true'>" +
|
||||||
" <port-mappings>" +
|
" <port-mappings>" +
|
||||||
" <port-mapping http='${http}' https='${https}'/>" +
|
" <port-mapping http='#{systemProperties.http}' https='${https}'/>" +
|
||||||
" </port-mappings>" +
|
" </port-mappings>" +
|
||||||
" </http>" + AUTH_PROVIDER_XML);
|
" </http>" + AUTH_PROVIDER_XML);
|
||||||
|
|
||||||
@ -475,7 +496,7 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void accessDeniedPageWorkWithPlaceholders() throws Exception {
|
public void accessDeniedPageWorksWithPlaceholders() throws Exception {
|
||||||
System.setProperty("accessDenied", "/go-away");
|
System.setProperty("accessDenied", "/go-away");
|
||||||
setContext(
|
setContext(
|
||||||
" <b:bean id='configurer' class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
" <b:bean id='configurer' class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
||||||
@ -485,10 +506,10 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void accessDeniedHandlerPageIsSetCorectly() throws Exception {
|
public void accessDeniedHandlerPageWorksWithEL() throws Exception {
|
||||||
setContext(
|
setContext(
|
||||||
" <http auto-config='true'>" +
|
" <http auto-config='true'>" +
|
||||||
" <access-denied-handler error-page='/go-away'/>" +
|
" <access-denied-handler error-page=\"#{'/go' + '-away'} \" />" +
|
||||||
" </http>" + AUTH_PROVIDER_XML);
|
" </http>" + AUTH_PROVIDER_XML);
|
||||||
ExceptionTranslationFilter filter = (ExceptionTranslationFilter) getFilter(ExceptionTranslationFilter.class);
|
ExceptionTranslationFilter filter = (ExceptionTranslationFilter) getFilter(ExceptionTranslationFilter.class);
|
||||||
assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage"));
|
assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage"));
|
||||||
@ -507,7 +528,7 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected=BeanDefinitionParsingException.class)
|
@Test(expected=BeanDefinitionParsingException.class)
|
||||||
public void accessDeniedHandlerAndAccessDeniedHandlerAreMutuallyExclusive() throws Exception {
|
public void accessDeniedPageAndAccessDeniedHandlerAreMutuallyExclusive() throws Exception {
|
||||||
setContext(
|
setContext(
|
||||||
" <http auto-config='true' access-denied-page='/go-away'>" +
|
" <http auto-config='true' access-denied-page='/go-away'>" +
|
||||||
" <access-denied-handler error-page='/go-away'/>" +
|
" <access-denied-handler error-page='/go-away'/>" +
|
||||||
@ -595,11 +616,11 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||||||
public void rememberMeServiceWorksWithExternalServicesImpl() throws Exception {
|
public void rememberMeServiceWorksWithExternalServicesImpl() throws Exception {
|
||||||
setContext(
|
setContext(
|
||||||
"<http auto-config='true'>" +
|
"<http auto-config='true'>" +
|
||||||
" <remember-me key='ourkey' services-ref='rms'/>" +
|
" <remember-me key=\"#{'our' + 'key'}\" services-ref='rms'/>" +
|
||||||
"</http>" +
|
"</http>" +
|
||||||
"<b:bean id='rms' class='"+ TokenBasedRememberMeServices.class.getName() +"'> " +
|
"<b:bean id='rms' class='"+ TokenBasedRememberMeServices.class.getName() +"'> " +
|
||||||
" <b:property name='userDetailsService' ref='us'/>" +
|
" <b:property name='userDetailsService' ref='us'/>" +
|
||||||
" <b:property name='key' value='ourkey'/>" +
|
" <b:property name='key' value='ourkey' />" +
|
||||||
" <b:property name='tokenValiditySeconds' value='5000'/>" +
|
" <b:property name='tokenValiditySeconds' value='5000'/>" +
|
||||||
"</b:bean>" +
|
"</b:bean>" +
|
||||||
AUTH_PROVIDER_XML);
|
AUTH_PROVIDER_XML);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user