Clover coverage report - Acegi Security System for Spring - 1.0.0-RC1
Coverage timestamp: Mon Dec 5 2005 09:05:15 EST
file stats: LOC: 166   Methods: 4
NCLOC: 35   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
AbstractAclVoter.java 75% 100% 100% 94.7%
coverage coverage
 1    /* Copyright 2004, 2005 Acegi Technology Pty Limited
 2    *
 3    * Licensed under the Apache License, Version 2.0 (the "License");
 4    * you may not use this file except in compliance with the License.
 5    * You may obtain a copy of the License at
 6    *
 7    * http://www.apache.org/licenses/LICENSE-2.0
 8    *
 9    * Unless required by applicable law or agreed to in writing, software
 10    * distributed under the License is distributed on an "AS IS" BASIS,
 11    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12    * See the License for the specific language governing permissions and
 13    * limitations under the License.
 14    */
 15   
 16    package org.acegisecurity.vote;
 17   
 18    import org.acegisecurity.AuthorizationServiceException;
 19    import org.acegisecurity.ConfigAttribute;
 20    import org.acegisecurity.acl.AclEntry;
 21    import org.acegisecurity.acl.AclManager;
 22   
 23    import org.aopalliance.intercept.MethodInvocation;
 24   
 25    import org.springframework.util.Assert;
 26   
 27    import java.lang.reflect.Method;
 28   
 29   
 30    /**
 31    * <p>
 32    * Given a domain object instance passed as a method argument, ensures the
 33    * principal has appropriate permission as defined by the {@link AclManager}.
 34    * </p>
 35    *
 36    * <p>
 37    * The <code>AclManager</code> is used to retrieve the access control list
 38    * (ACL) permissions associated with a domain object instance for the current
 39    * <code>Authentication</code> object. This class is designed to process
 40    * {@link AclEntry}s that are subclasses of {@link
 41    * org.acegisecurity.acl.basic.BasicAclEntry} only. Generally these are
 42    * obtained by using the {@link
 43    * org.acegisecurity.acl.basic.BasicAclProvider}.
 44    * </p>
 45    *
 46    * <p>
 47    * The voter will vote if any {@link ConfigAttribute#getAttribute()} matches
 48    * the {@link #processConfigAttribute}. The provider will then locate the
 49    * first method argument of type {@link #processDomainObjectClass}. Assuming
 50    * that method argument is non-null, the provider will then lookup the ACLs
 51    * from the <code>AclManager</code> and ensure the principal is {@link
 52    * org.acegisecurity.acl.basic.BasicAclEntry#isPermitted(int)} for at least
 53    * one of the {@link #requirePermission}s.
 54    * </p>
 55    *
 56    * <p>
 57    * If the method argument is <code>null</code>, the voter will abstain from
 58    * voting. If the method argument could not be found, an {@link
 59    * org.acegisecurity.AuthorizationServiceException} will be thrown.
 60    * </p>
 61    *
 62    * <p>
 63    * In practical terms users will typically setup a number of
 64    * <code>BasicAclEntryVoter</code>s. Each will have a different {@link
 65    * #processDomainObjectClass}, {@link #processConfigAttribute} and {@link
 66    * #requirePermission} combination. For example, a small application might
 67    * employ the following instances of <code>BasicAclEntryVoter</code>:
 68    *
 69    * <ul>
 70    * <li>
 71    * Process domain object class <code>BankAccount</code>, configuration
 72    * attribute <code>VOTE_ACL_BANK_ACCONT_READ</code>, require permission
 73    * <code>SimpleAclEntry.READ</code>
 74    * </li>
 75    * <li>
 76    * Process domain object class <code>BankAccount</code>, configuration
 77    * attribute <code>VOTE_ACL_BANK_ACCOUNT_WRITE</code>, require permission list
 78    * <code>SimpleAclEntry.WRITE</code> and <code>SimpleAclEntry.CREATE</code>
 79    * (allowing the principal to have <b>either</b> of these two permissions
 80    * </li>
 81    * <li>
 82    * Process domain object class <code>Customer</code>, configuration attribute
 83    * <code>VOTE_ACL_CUSTOMER_READ</code>, require permission
 84    * <code>SimpleAclEntry.READ</code>
 85    * </li>
 86    * <li>
 87    * Process domain object class <code>Customer</code>, configuration attribute
 88    * <code>VOTE_ACL_CUSTOMER_WRITE</code>, require permission list
 89    * <code>SimpleAclEntry.WRITE</code> and <code>SimpleAclEntry.CREATE</code>
 90    * </li>
 91    * </ul>
 92    *
 93    * Alternatively, you could have used a common superclass or interface for the
 94    * {@link #processDomainObjectClass} if both <code>BankAccount</code> and
 95    * <code>Customer</code> had common parents.
 96    * </p>
 97    *
 98    * <p>
 99    * If the principal does not have sufficient permissions, the voter will vote
 100    * to deny access.
 101    * </p>
 102    *
 103    * <p>
 104    * The <code>AclManager</code> is allowed to return any implementations of
 105    * <code>AclEntry</code> it wishes. However, this provider will only be able
 106    * to validate against <code>AbstractBasicAclEntry</code>s, and thus a vote to
 107    * deny access will be made if no <code>AclEntry</code> is of type
 108    * <code>AbstractBasicAclEntry</code>.
 109    * </p>
 110    *
 111    * <p>
 112    * All comparisons and prefixes are case sensitive.
 113    * </p>
 114    *
 115    * @author Ben Alex
 116    * @version $Id: AbstractAclVoter.java,v 1.2 2005/11/17 00:55:47 benalex Exp $
 117    */
 118    public abstract class AbstractAclVoter implements AccessDecisionVoter {
 119    //~ Instance fields ========================================================
 120   
 121    private Class processDomainObjectClass;
 122   
 123    //~ Methods ================================================================
 124   
 125  12 public void setProcessDomainObjectClass(Class processDomainObjectClass) {
 126  12 Assert.notNull(processDomainObjectClass,
 127    "processDomainObjectClass cannot be set to null");
 128  11 this.processDomainObjectClass = processDomainObjectClass;
 129    }
 130   
 131  1 public Class getProcessDomainObjectClass() {
 132  1 return processDomainObjectClass;
 133    }
 134   
 135    /**
 136    * This implementation supports only
 137    * <code>MethodSecurityInterceptor</code>, because it queries the
 138    * presented <code>MethodInvocation</code>.
 139    *
 140    * @param clazz the secure object
 141    *
 142    * @return <code>true</code> if the secure object is
 143    * <code>MethodInvocation</code>, <code>false</code> otherwise
 144    */
 145  2 public boolean supports(Class clazz) {
 146  2 return (MethodInvocation.class.isAssignableFrom(clazz));
 147    }
 148   
 149  7 protected Object getDomainObjectInstance(Object secureObject) {
 150  7 MethodInvocation invocation = (MethodInvocation) secureObject;
 151   
 152    // Check if this MethodInvocation provides the required argument
 153  7 Method method = invocation.getMethod();
 154  7 Class[] params = method.getParameterTypes();
 155   
 156  7 for (int i = 0; i < params.length; i++) {
 157  6 if (processDomainObjectClass.isAssignableFrom(params[i])) {
 158  6 return invocation.getArguments()[i];
 159    }
 160    }
 161   
 162  1 throw new AuthorizationServiceException("MethodInvocation: "
 163    + invocation + " did not provide any argument of type: "
 164    + processDomainObjectClass);
 165    }
 166    }