diff --git a/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java b/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java index d949ae0319..e9f42dd1f8 100644 --- a/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java +++ b/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java @@ -60,6 +60,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { static final String ATT_ACCESS_CONFIG = "access"; static final String ATT_REQUIRES_CHANNEL = "requires-channel"; + static final String OPT_REQUIRES_HTTP = "http"; + static final String OPT_REQUIRES_HTTPS = "https"; + static final String OPT_ANY_CHANNEL = "any"; static final String ATT_CREATE_SESSION = "create-session"; static final String DEF_CREATE_SESSION_IF_REQUIRED = "ifRequired"; @@ -176,12 +179,12 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { channelFilter.getPropertyValues().addPropertyValue("filterInvocationDefinitionSource", channelFilterInvDefSource); RootBeanDefinition channelDecisionManager = new RootBeanDefinition(ChannelDecisionManagerImpl.class); - ManagedList channelProcessors = new ManagedList(2); + ManagedList channelProcessors = new ManagedList(3); 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); + retryWithHttps.getPropertyValues().addPropertyValue("portMapper", portMapperRef); secureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttps); RootBeanDefinition inSecureChannelProcessor = new RootBeanDefinition(InsecureChannelProcessor.class); inSecureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttp); @@ -277,10 +280,12 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { if (StringUtils.hasText(requiredChannel)) { String channelConfigAttribute = null; - if (requiredChannel.equals("https")) { + if (requiredChannel.equals(OPT_REQUIRES_HTTPS)) { channelConfigAttribute = "REQUIRES_SECURE_CHANNEL"; - } else if (requiredChannel.equals("http")) { + } 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); } diff --git a/core/src/main/java/org/springframework/security/securechannel/ChannelDecisionManagerImpl.java b/core/src/main/java/org/springframework/security/securechannel/ChannelDecisionManagerImpl.java index 41698cf8b4..603cd17b62 100644 --- a/core/src/main/java/org/springframework/security/securechannel/ChannelDecisionManagerImpl.java +++ b/core/src/main/java/org/springframework/security/securechannel/ChannelDecisionManagerImpl.java @@ -21,6 +21,7 @@ import org.springframework.security.ConfigAttributeDefinition; import org.springframework.security.intercept.web.FilterInvocation; import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.Assert; import java.io.IOException; @@ -31,16 +32,25 @@ import javax.servlet.ServletException; /** - * Implementation of {@link ChannelDecisionManager}.
Iterates through each configured {@link ChannelProcessor}.
- * If a ChannelProcessor has any issue with the security of the request, it should cause a redirect,
- * exception or whatever other action is appropriate for the ChannelProcessor implementation.
Once any response is committed (ie a redirect is written to the response object), the
- * ChannelDecisionManagerImpl will not iterate through any further ChannelProcessors.
+ * Iterates through each configured {@link ChannelProcessor}. If a ChannelProcessor has any issue with the
+ * security of the request, it should cause a redirect, exception or whatever other action is appropriate for the
+ * ChannelProcessor implementation.
+ *
+ * Once any response is committed (ie a redirect is written to the response object), the
+ * ChannelDecisionManagerImpl will not iterate through any further ChannelProcessors.
+ *
+ * The attribute "ANY_CHANNEL" if applied to a particular URL, the iteration through the channel processors will be
+ * skipped (see SEC-494, SEC-335).
*
* @author Ben Alex
* @version $Id$
*/
public class ChannelDecisionManagerImpl implements ChannelDecisionManager, InitializingBean {
+
+ public static final String ANY_CHANNEL = "ANY_CHANNEL";
+
//~ Instance fields ================================================================================================
private List channelProcessors;
@@ -52,13 +62,21 @@ public class ChannelDecisionManagerImpl implements ChannelDecisionManager, Initi
}
private void checkIfValidList(List listToCheck) {
- if ((listToCheck == null) || (listToCheck.size() == 0)) {
- throw new IllegalArgumentException("A list of ChannelProcessors is required");
- }
+ Assert.notEmpty(listToCheck, "A list of ChannelProcessors is required");
}
public void decide(FilterInvocation invocation, ConfigAttributeDefinition config)
- throws IOException, ServletException {
+ throws IOException, ServletException {
+
+ Iterator attrs = config.getConfigAttributes();
+
+ while (attrs.hasNext()) {
+ ConfigAttribute attribute = (ConfigAttribute) attrs.next();
+ if (ANY_CHANNEL.equals(attribute.getAttribute())) {
+ return;
+ }
+ }
+
Iterator iter = this.channelProcessors.iterator();
while (iter.hasNext()) {
@@ -72,7 +90,7 @@ public class ChannelDecisionManagerImpl implements ChannelDecisionManager, Initi
}
}
- public List getChannelProcessors() {
+ protected List getChannelProcessors() {
return this.channelProcessors;
}
@@ -82,22 +100,19 @@ public class ChannelDecisionManagerImpl implements ChannelDecisionManager, Initi
Iterator iter = newList.iterator();
while (iter.hasNext()) {
- Object currentObject = null;
-
- try {
- currentObject = iter.next();
-
- ChannelProcessor attemptToCast = (ChannelProcessor) currentObject;
- } catch (ClassCastException cce) {
- throw new IllegalArgumentException("ChannelProcessor " + currentObject.getClass().getName()
- + " must implement ChannelProcessor");
- }
+ Object currentObject = iter.next();
+ Assert.isInstanceOf(ChannelProcessor.class, currentObject, "ChannelProcessor " +
+ currentObject.getClass().getName() + " must implement ChannelProcessor");
}
this.channelProcessors = newList;
}
public boolean supports(ConfigAttribute attribute) {
+ if (ANY_CHANNEL.equals(attribute.getAttribute())) {
+ return true;
+ }
+
Iterator iter = this.channelProcessors.iterator();
while (iter.hasNext()) {
diff --git a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc
index 46d6db99a6..75fdfcb36b 100644
--- a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc
+++ b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc
@@ -135,7 +135,7 @@ intercept-url.attlist &=
attribute filters {"none"}?
intercept-url.attlist &=
## Used to specify that a URL must be accessed over http or https
- attribute requires-channel {"http" | "https"}?
+ attribute requires-channel {"http" | "https" | "any"}?
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.
diff --git a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd
index 538659da76..20a71215e8 100644
--- a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd
+++ b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd
@@ -368,6 +368,7 @@