diff --git a/core/src/main/java/org/acegisecurity/intercept/web/WebInvocationPrivilegeEvaluator.java b/core/src/main/java/org/acegisecurity/intercept/web/WebInvocationPrivilegeEvaluator.java
new file mode 100644
index 0000000000..f5fea4f24d
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/intercept/web/WebInvocationPrivilegeEvaluator.java
@@ -0,0 +1,99 @@
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.acegisecurity.intercept.web;
+
+import org.acegisecurity.AccessDeniedException;
+import org.acegisecurity.Authentication;
+import org.acegisecurity.ConfigAttributeDefinition;
+
+import org.acegisecurity.intercept.AbstractSecurityInterceptor;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.factory.InitializingBean;
+
+import org.springframework.util.Assert;
+
+
+/**
+ * Allows users to determine whether they have privileges for a given web URI.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class WebInvocationPrivilegeEvaluator implements InitializingBean {
+ //~ Static fields/initializers =============================================
+
+ protected static final Log logger = LogFactory.getLog(WebInvocationPrivilegeEvaluator.class);
+
+ //~ Instance fields ========================================================
+
+ private AbstractSecurityInterceptor securityInterceptor;
+
+ //~ Methods ================================================================
+
+ public void afterPropertiesSet() throws Exception {
+ Assert.notNull(securityInterceptor, "SecurityInterceptor required");
+ }
+
+ public boolean isAllowed(FilterInvocation fi, Authentication authentication) {
+ Assert.notNull(fi, "FilterInvocation required");
+
+ ConfigAttributeDefinition attrs = securityInterceptor.obtainObjectDefinitionSource()
+ .getAttributes(fi);
+
+ if (attrs == null) {
+ if (securityInterceptor.isRejectPublicInvocations()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ if ((authentication == null)
+ || (authentication.getAuthorities() == null)
+ || (authentication.getAuthorities().length == 0)) {
+ return false;
+ }
+
+ try {
+ securityInterceptor.getAccessDecisionManager()
+ .decide(authentication, fi, attrs);
+ } catch (AccessDeniedException unauthorized) {
+ if (logger.isDebugEnabled()) {
+ logger.debug(fi.toString() + " denied for "
+ + authentication.toString(), unauthorized);
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ public void setSecurityInterceptor(
+ AbstractSecurityInterceptor securityInterceptor) {
+ Assert.notNull(securityInterceptor,
+ "AbstractSecurityInterceptor cannot be null");
+ Assert.isTrue(FilterInvocation.class.equals(
+ securityInterceptor.getSecureObjectClass()),
+ "AbstractSecurityInterceptor does not support FilterInvocations");
+ Assert.notNull(securityInterceptor.getAccessDecisionManager(),
+ "AbstractSecurityInterceptor must provide a non-null AccessDecisionManager");
+ this.securityInterceptor = securityInterceptor;
+ }
+}
diff --git a/core/src/main/java/org/acegisecurity/util/FilterInvocationUtils.java b/core/src/main/java/org/acegisecurity/util/FilterInvocationUtils.java
new file mode 100644
index 0000000000..eed8ad8b6d
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/util/FilterInvocationUtils.java
@@ -0,0 +1,104 @@
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.acegisecurity.util;
+
+import org.acegisecurity.intercept.web.FilterInvocation;
+
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+
+import org.springframework.util.Assert;
+
+import java.io.IOException;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+
+/**
+ * Static utility methods for creating FilterInvocations usable
+ * within Acegi Security.
+ *
+ *
+ * The generated FilterInvocation objects are not intended for use
+ * with AbstractSecurityInterceptor subclasses. Instead they are
+ * generally used by WebInvocationPrivilegeEvaluator.
+ *
FilterInvocation for the specified
+ * contextPath and Uri. Note the normal
+ * subclasses of AbstractFilterInvocationDefinitionSource
+ * disregard the contextPath when evaluating which secure
+ * object metadata applies to a given FilterInvocation, so
+ * generally the contextPath is unimportant unless you are
+ * using a custom FilterInvocationDefinitionSource.
+ *
+ * @param contextPath the contextPath that will be contained
+ * within the
+ * FilterInvocationHttpServletRequest
+ * @param uri the URI of the request, such as /foo/default.jsp
+ *
+ * @return a fully-formed FilterInvocation (never
+ * null)
+ *
+ * @throws UnsupportedOperationException DOCUMENT ME!
+ */
+ public static FilterInvocation create(String contextPath, String uri) {
+ Assert.hasText(contextPath, "contextPath required");
+ Assert.hasText(uri, "URI required");
+
+ MockHttpServletRequest req = new MockHttpServletRequest();
+ req.setRequestURI(contextPath + uri);
+ req.setContextPath(contextPath);
+ req.setServletPath(null);
+
+ FilterInvocation fi = new FilterInvocation(req,
+ new MockHttpServletResponse(),
+ new FilterChain() {
+ public void doFilter(ServletRequest arg0,
+ ServletResponse arg1)
+ throws IOException, ServletException {
+ throw new UnsupportedOperationException(
+ "WebInvocationPrivilegeEvaluator does not support filter chains");
+ }
+ });
+
+ return fi;
+ }
+
+ /**
+ * Creates a FilterInvocation for the specified
+ * Uri. The contextPath is set to a default
+ * value.
+ *
+ * @param uri the URI of the request, such as /foo/default.jsp
+ *
+ * @return a fully-formed FilterInvocation (never
+ * null)
+ */
+ public static FilterInvocation create(String uri) {
+ return create("/notused", uri);
+ }
+}
diff --git a/core/src/test/java/org/acegisecurity/intercept/web/WebInvocationPrivilegeEvaluatorTests.java b/core/src/test/java/org/acegisecurity/intercept/web/WebInvocationPrivilegeEvaluatorTests.java
new file mode 100644
index 0000000000..07b99a7465
--- /dev/null
+++ b/core/src/test/java/org/acegisecurity/intercept/web/WebInvocationPrivilegeEvaluatorTests.java
@@ -0,0 +1,104 @@
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.acegisecurity.intercept.web;
+
+import junit.framework.TestCase;
+
+import org.acegisecurity.GrantedAuthority;
+import org.acegisecurity.GrantedAuthorityImpl;
+
+import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
+
+import org.acegisecurity.util.FilterInvocationUtils;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+
+/**
+ * Tests {@link
+ * org.acegisecurity.intercept.web.WebInvocationPrivilegeEvaluator}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class WebInvocationPrivilegeEvaluatorTests extends TestCase {
+ //~ Constructors ===========================================================
+
+ public WebInvocationPrivilegeEvaluatorTests() {
+ super();
+ }
+
+ public WebInvocationPrivilegeEvaluatorTests(String arg0) {
+ super(arg0);
+ }
+
+ //~ Methods ================================================================
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(WebInvocationPrivilegeEvaluatorTests.class);
+ }
+
+ private FilterSecurityInterceptor makeFilterSecurityInterceptor() {
+ ApplicationContext context = new ClassPathXmlApplicationContext(
+ "org/acegisecurity/intercept/web/applicationContext.xml");
+
+ return (FilterSecurityInterceptor) context.getBean(
+ "securityInterceptor");
+ }
+
+ public void testAllowsAccess1() throws Exception {
+ UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
+ "Password",
+ new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_INDEX")});
+ FilterInvocation fi = FilterInvocationUtils.create("/foo/index.jsp");
+ FilterSecurityInterceptor interceptor = makeFilterSecurityInterceptor();
+
+ WebInvocationPrivilegeEvaluator wipe = new WebInvocationPrivilegeEvaluator();
+ wipe.setSecurityInterceptor(interceptor);
+ wipe.afterPropertiesSet();
+
+ assertTrue(wipe.isAllowed(fi, token));
+ }
+
+ public void testAllowsAccess2() throws Exception {
+ UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
+ "Password",
+ new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_USER")});
+ FilterInvocation fi = FilterInvocationUtils.create("/anything.jsp");
+ FilterSecurityInterceptor interceptor = makeFilterSecurityInterceptor();
+
+ WebInvocationPrivilegeEvaluator wipe = new WebInvocationPrivilegeEvaluator();
+ wipe.setSecurityInterceptor(interceptor);
+ wipe.afterPropertiesSet();
+
+ assertTrue(wipe.isAllowed(fi, token));
+ }
+
+ public void testDeniesAccess1() throws Exception {
+ UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
+ "Password",
+ new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_NOTHING_USEFUL")});
+ FilterInvocation fi = FilterInvocationUtils.create("/anything.jsp");
+ FilterSecurityInterceptor interceptor = makeFilterSecurityInterceptor();
+
+ WebInvocationPrivilegeEvaluator wipe = new WebInvocationPrivilegeEvaluator();
+ wipe.setSecurityInterceptor(interceptor);
+ wipe.afterPropertiesSet();
+
+ assertFalse(wipe.isAllowed(fi, token));
+ }
+}
diff --git a/core/src/test/resources/org/acegisecurity/intercept/web/applicationContext.xml b/core/src/test/resources/org/acegisecurity/intercept/web/applicationContext.xml
new file mode 100644
index 0000000000..e40ed74516
--- /dev/null
+++ b/core/src/test/resources/org/acegisecurity/intercept/web/applicationContext.xml
@@ -0,0 +1,41 @@
+
+
+
+
+