|
|||||||||||||||||||
| Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
| AbstractAclVoter.java | 75% | 100% | 100% | 94.7% |
|
||||||||||||||
| 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 | } |
|
||||||||||