diff --git a/core/src/main/java/org/acegisecurity/intercept/method/MethodInvocationPrivilegeEvaluator.java b/core/src/main/java/org/acegisecurity/intercept/method/MethodInvocationPrivilegeEvaluator.java new file mode 100644 index 0000000000..d7060b5203 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/intercept/method/MethodInvocationPrivilegeEvaluator.java @@ -0,0 +1,102 @@ +/* Copyright 2004, 2005 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.method; + +import org.acegisecurity.AccessDeniedException; +import org.acegisecurity.Authentication; +import org.acegisecurity.ConfigAttributeDefinition; + +import org.acegisecurity.intercept.AbstractSecurityInterceptor; + +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.beans.factory.InitializingBean; + +import org.springframework.util.Assert; + + +/** + * Allows users to determine whether they have "before invocation" privileges + * for a given method invocation. + * + *

+ * Of course, if an {@link org.acegisecurity.AfterInvocationManager} is used to + * authorize the result of a method invocation, this class cannot + * assist determine whether or not the AfterInvocationManager + * will enable access. Instead this class aims to allow applications to + * determine whether or not the current principal would be allowed to at least + * attempt to invoke the method, irrespective of the "after" invocation + * handling. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public class MethodInvocationPrivilegeEvaluator implements InitializingBean { + //~ Instance fields ======================================================== + + private AbstractSecurityInterceptor securityInterceptor; + + //~ Methods ================================================================ + + public boolean isAllowed(MethodInvocation mi, Authentication authentication) { + Assert.notNull(authentication, "Authentication required"); + Assert.notNull(authentication.getAuthorities(), + "Authentication must provided non-null GrantedAuthority[]s"); + Assert.notNull(mi, "MethodInvocation required"); + Assert.notNull(mi.getMethod(), + "MethodInvocation must provide a non-null getMethod()"); + + ConfigAttributeDefinition attrs = securityInterceptor.obtainObjectDefinitionSource() + .getAttributes(mi); + + if (attrs == null) { + // TODO: This should be reviewed when we complete SEC-47 + return true; + } + + if (authentication == null) { + return false; + } + + try { + securityInterceptor.getAccessDecisionManager().decide(authentication, + mi, attrs); + } catch (AccessDeniedException unauthorized) { + unauthorized.printStackTrace(); + + return false; + } + + return true; + } + + public void setSecurityInterceptor( + AbstractSecurityInterceptor securityInterceptor) { + Assert.notNull(securityInterceptor, + "AbstractSecurityInterceptor cannot be null"); + Assert.isTrue(MethodInvocation.class.equals( + securityInterceptor.getSecureObjectClass()), + "AbstractSecurityInterceptor does not support MethodInvocations"); + Assert.notNull(securityInterceptor.getAccessDecisionManager(), + "AbstractSecurityInterceptor must provide a non-null AccessDecisionManager"); + this.securityInterceptor = securityInterceptor; + } + + public void afterPropertiesSet() throws Exception { + Assert.notNull(securityInterceptor, "SecurityInterceptor required"); + } +} diff --git a/core/src/test/java/org/acegisecurity/intercept/method/MethodInvocationPrivilegeEvaluatorTests.java b/core/src/test/java/org/acegisecurity/intercept/method/MethodInvocationPrivilegeEvaluatorTests.java new file mode 100644 index 0000000000..bc06e7bfa7 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/intercept/method/MethodInvocationPrivilegeEvaluatorTests.java @@ -0,0 +1,97 @@ +/* Copyright 2004, 2005 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.method; + +import junit.framework.TestCase; + +import org.acegisecurity.GrantedAuthority; +import org.acegisecurity.GrantedAuthorityImpl; +import org.acegisecurity.ITargetObject; + +import org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor; + +import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; + +import org.acegisecurity.util.MethodInvocationUtils; + +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + + +/** + * Tests {@link + * org.acegisecurity.intercept.method.MethodInvocationPrivilegeEvaluator}. + * + * @author Ben Alex + * @version $Id$ + */ +public class MethodInvocationPrivilegeEvaluatorTests extends TestCase { + //~ Constructors =========================================================== + + public MethodInvocationPrivilegeEvaluatorTests() { + super(); + } + + public MethodInvocationPrivilegeEvaluatorTests(String arg0) { + super(arg0); + } + + //~ Methods ================================================================ + + public static void main(String[] args) { + junit.textui.TestRunner.run(MethodInvocationPrivilegeEvaluatorTests.class); + } + + public void testAllowsAccess() throws Exception { + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", + "Password", + new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_LOWER")}); + MethodInvocation mi = MethodInvocationUtils.createFromClass(ITargetObject.class, + "makeLowerCase", new Class[] {String.class}); + MethodSecurityInterceptor interceptor = makeSecurityInterceptor(); + + MethodInvocationPrivilegeEvaluator mipe = new MethodInvocationPrivilegeEvaluator(); + mipe.setSecurityInterceptor(interceptor); + mipe.afterPropertiesSet(); + + assertTrue(mipe.isAllowed(mi, token)); + } + + public void testDeclinesAccess() throws Exception { + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", + "Password", + new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_NOT_HELD")}); + MethodInvocation mi = MethodInvocationUtils.createFromClass(ITargetObject.class, + "makeLowerCase", new Class[] {String.class}); + MethodSecurityInterceptor interceptor = makeSecurityInterceptor(); + + MethodInvocationPrivilegeEvaluator mipe = new MethodInvocationPrivilegeEvaluator(); + mipe.setSecurityInterceptor(interceptor); + mipe.afterPropertiesSet(); + + assertFalse(mipe.isAllowed(mi, token)); + } + + private MethodSecurityInterceptor makeSecurityInterceptor() { + ApplicationContext context = new ClassPathXmlApplicationContext( + "org/acegisecurity/intercept/method/aopalliance/applicationContext.xml"); + + return (MethodSecurityInterceptor) context.getBean( + "securityInterceptor"); + } +}