SEC-1201: Allow requires-channel attribute to take placeholders.
This commit is contained in:
parent
00352227ac
commit
fe33f08b73
|
@ -0,0 +1,37 @@
|
|||
package org.springframework.security.config.http;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl;
|
||||
|
||||
/**
|
||||
* Used as a factory bean to create config attribute values for the <tt>requires-channel</tt> attribute.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 3.0
|
||||
*/
|
||||
public class ChannelAttributeFactory {
|
||||
private static final String OPT_REQUIRES_HTTP = "http";
|
||||
private static final String OPT_REQUIRES_HTTPS = "https";
|
||||
private static final String OPT_ANY_CHANNEL = "any";
|
||||
|
||||
public static final List<ConfigAttribute> createChannelAttributes(String requiredChannel) {
|
||||
String channelConfigAttribute = null;
|
||||
|
||||
if (requiredChannel.equals(OPT_REQUIRES_HTTPS)) {
|
||||
channelConfigAttribute = "REQUIRES_SECURE_CHANNEL";
|
||||
} else if (requiredChannel.equals(OPT_REQUIRES_HTTP)) {
|
||||
channelConfigAttribute = "REQUIRES_INSECURE_CHANNEL";
|
||||
} else if (requiredChannel.equals(OPT_ANY_CHANNEL)) {
|
||||
channelConfigAttribute = ChannelDecisionManagerImpl.ANY_CHANNEL;
|
||||
} else {
|
||||
throw new BeanCreationException("Unknown channel attribute " + requiredChannel);
|
||||
}
|
||||
|
||||
return SecurityConfig.createList(channelConfigAttribute);
|
||||
}
|
||||
}
|
|
@ -27,8 +27,6 @@ import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
|||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.access.vote.AffirmativeBased;
|
||||
import org.springframework.security.access.vote.AuthenticatedVoter;
|
||||
import org.springframework.security.access.vote.RoleVoter;
|
||||
|
@ -102,9 +100,6 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||
private static final String OPT_SESSION_FIXATION_MIGRATE_SESSION = "migrateSession";
|
||||
|
||||
static final String ATT_REQUIRES_CHANNEL = "requires-channel";
|
||||
private static final String OPT_REQUIRES_HTTP = "http";
|
||||
private static final String OPT_REQUIRES_HTTPS = "https";
|
||||
private static final String OPT_ANY_CHANNEL = "any";
|
||||
|
||||
private static final String ATT_CREATE_SESSION = "create-session";
|
||||
private static final String DEF_CREATE_SESSION_IF_REQUIRED = "ifRequired";
|
||||
|
@ -180,7 +175,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||
// Use ManagedMap to allow placeholder resolution
|
||||
final ManagedMap<String, List<BeanMetadataElement>> filterChainMap =
|
||||
parseInterceptUrlsForEmptyFilterChains(interceptUrls, convertPathsToLowerCase, pc);
|
||||
final ManagedMap<BeanDefinition,List<ConfigAttribute>> channelRequestMap =
|
||||
final ManagedMap<BeanDefinition,BeanDefinition> channelRequestMap =
|
||||
parseInterceptUrlsForChannelSecurity(interceptUrls, convertPathsToLowerCase, pc);
|
||||
|
||||
BeanDefinition cpf = null;
|
||||
|
@ -893,7 +888,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||
}
|
||||
|
||||
private BeanDefinition createChannelProcessingFilter(ParserContext pc, UrlMatcher matcher,
|
||||
ManagedMap<BeanDefinition,List<ConfigAttribute>> channelRequestMap, String portMapperBeanName) {
|
||||
ManagedMap<BeanDefinition,BeanDefinition> channelRequestMap, String portMapperBeanName) {
|
||||
RootBeanDefinition channelFilter = new RootBeanDefinition(ChannelProcessingFilter.class);
|
||||
BeanDefinitionBuilder metadataSourceBldr = BeanDefinitionBuilder.rootBeanDefinition(DefaultFilterInvocationSecurityMetadataSource.class);
|
||||
metadataSourceBldr.addConstructorArgValue(matcher);
|
||||
|
@ -1189,10 +1184,10 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||
* Parses the intercept-url elements to obtain the map used by channel security.
|
||||
* This will be empty unless the <tt>requires-channel</tt> attribute has been used on a URL path.
|
||||
*/
|
||||
private ManagedMap<BeanDefinition,List<ConfigAttribute>> parseInterceptUrlsForChannelSecurity(List<Element> urlElts,
|
||||
private ManagedMap<BeanDefinition,BeanDefinition> parseInterceptUrlsForChannelSecurity(List<Element> urlElts,
|
||||
boolean useLowerCasePaths, ParserContext parserContext) {
|
||||
|
||||
ManagedMap<BeanDefinition, List<ConfigAttribute>> channelRequestMap = new ManagedMap<BeanDefinition, List<ConfigAttribute>>();
|
||||
ManagedMap<BeanDefinition, BeanDefinition> channelRequestMap = new ManagedMap<BeanDefinition, BeanDefinition>();
|
||||
|
||||
for (Element urlElt : urlElts) {
|
||||
String path = urlElt.getAttribute(ATT_PATH_PATTERN);
|
||||
|
@ -1208,22 +1203,14 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||
String requiredChannel = urlElt.getAttribute(ATT_REQUIRES_CHANNEL);
|
||||
|
||||
if (StringUtils.hasText(requiredChannel)) {
|
||||
String channelConfigAttribute = null;
|
||||
|
||||
if (requiredChannel.equals(OPT_REQUIRES_HTTPS)) {
|
||||
channelConfigAttribute = "REQUIRES_SECURE_CHANNEL";
|
||||
} else if (requiredChannel.equals(OPT_REQUIRES_HTTP)) {
|
||||
channelConfigAttribute = "REQUIRES_INSECURE_CHANNEL";
|
||||
} else if (requiredChannel.equals(OPT_ANY_CHANNEL)) {
|
||||
channelConfigAttribute = ChannelDecisionManagerImpl.ANY_CHANNEL;
|
||||
} else {
|
||||
parserContext.getReaderContext().error("Unsupported channel " + requiredChannel, urlElt);
|
||||
}
|
||||
|
||||
BeanDefinition requestKey = new RootBeanDefinition(RequestKey.class);
|
||||
requestKey.getConstructorArgumentValues().addGenericArgumentValue(path);
|
||||
|
||||
channelRequestMap.put(requestKey, SecurityConfig.createList(channelConfigAttribute));
|
||||
RootBeanDefinition channelAttributes = new RootBeanDefinition(ChannelAttributeFactory.class);
|
||||
channelAttributes.getConstructorArgumentValues().addGenericArgumentValue(requiredChannel);
|
||||
channelAttributes.setFactoryMethodName("createChannelAttributes");
|
||||
|
||||
channelRequestMap.put(requestKey, channelAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import org.springframework.util.StringUtils;
|
|||
*
|
||||
* @author Luke Taylor
|
||||
* @author Ben Alex
|
||||
* @version $Id: WebConfigUtils.java 3770 2009-07-15 23:09:47Z ltaylor $
|
||||
* @version $Id$
|
||||
*/
|
||||
abstract class WebConfigUtils {
|
||||
|
||||
|
|
|
@ -316,8 +316,8 @@ intercept-url.attlist &=
|
|||
## The filter list for the path. Currently can be set to "none" to remove a path from having any filters applied. The full filter stack (consisting of all filters created by the namespace configuration, and any added using 'custom-filter'), will be applied to any other paths.
|
||||
attribute filters {"none"}?
|
||||
intercept-url.attlist &=
|
||||
## Used to specify that a URL must be accessed over http or https, or that there is no preference.
|
||||
attribute requires-channel {"http" | "https" | "any"}?
|
||||
## Used to specify that a URL must be accessed over http or https, or that there is no preference. The value should be "http", "https" or "any", respectively.
|
||||
attribute requires-channel {xsd:token}?
|
||||
|
||||
logout =
|
||||
## Incorporates a logout processing filter. Most web applications require a logout filter, although you may not require one if you write a controller to provider similar logic.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -391,18 +391,24 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||
@Test
|
||||
public void requiresChannelSupportsPlaceholder() throws Exception {
|
||||
System.setProperty("secure.url", "/secure");
|
||||
System.setProperty("required.channel", "https");
|
||||
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'>" +
|
||||
" <intercept-url pattern='${secure.url}' requires-channel='https' />" +
|
||||
" <intercept-url pattern='${secure.url}' requires-channel='${required.channel}' />" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
List<Filter> filters = getFilters("/secure");
|
||||
|
||||
assertEquals("Expected " + (AUTO_CONFIG_FILTERS + 1) +" filters in chain", AUTO_CONFIG_FILTERS + 1, filters.size());
|
||||
|
||||
assertTrue(filters.get(0) instanceof ChannelProcessingFilter);
|
||||
}
|
||||
|
||||
ChannelProcessingFilter filter = (ChannelProcessingFilter) filters.get(0);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/secure");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
filter.doFilter(request, response, new MockFilterChain());
|
||||
assertNotNull(response.getRedirectedUrl());
|
||||
assertTrue(response.getRedirectedUrl().startsWith("https"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void portMappingsAreParsedCorrectly() throws Exception {
|
||||
setContext(
|
||||
|
|
|
@ -111,11 +111,11 @@ public class ChannelProcessingFilter extends GenericFilterBean {
|
|||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
public ChannelDecisionManager getChannelDecisionManager() {
|
||||
protected ChannelDecisionManager getChannelDecisionManager() {
|
||||
return channelDecisionManager;
|
||||
}
|
||||
|
||||
public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
|
||||
protected FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
|
||||
return securityMetadataSource;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue