1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.acegisecurity.acl.basic;
17
18 import org.apache.commons.logging.Log;
19 import org.apache.commons.logging.LogFactory;
20 import org.springframework.util.Assert;
21
22 import java.util.Arrays;
23
24
25 /***
26 * Abstract implementation of {@link BasicAclEntry}.
27 *
28 * <P>
29 * Provides core bit mask handling methods.
30 * </p>
31 *
32 * @author Ben Alex
33 * @version $Id: AbstractBasicAclEntry.java,v 1.5 2005/11/17 00:55:47 benalex Exp $
34 */
35 public abstract class AbstractBasicAclEntry implements BasicAclEntry {
36
37
38 private static final Log logger = LogFactory.getLog(AbstractBasicAclEntry.class);
39
40
41
42 private AclObjectIdentity aclObjectIdentity;
43 private AclObjectIdentity aclObjectParentIdentity;
44 private Object recipient;
45 private int[] validPermissions;
46 private int mask = 0;
47
48
49
50 public AbstractBasicAclEntry(Object recipient,
51 AclObjectIdentity aclObjectIdentity,
52 AclObjectIdentity aclObjectParentIdentity, int mask) {
53 Assert.notNull(recipient, "recipient cannot be null");
54
55 Assert.notNull(aclObjectIdentity, "aclObjectIdentity cannot be null");
56
57 validPermissions = getValidPermissions();
58 Arrays.sort(validPermissions);
59
60 for (int i = 0; i < validPermissions.length; i++) {
61 if (logger.isDebugEnabled()) {
62 logger.debug("Valid permission: "
63 + printPermissionsBlock(validPermissions[i]) + " "
64 + printBinary(validPermissions[i]) + " ("
65 + validPermissions[i] + ")");
66 }
67 }
68
69 this.recipient = recipient;
70 this.aclObjectIdentity = aclObjectIdentity;
71 this.aclObjectParentIdentity = aclObjectParentIdentity;
72 this.mask = mask;
73 }
74
75 /***
76 * A protected constructor for use by Hibernate.
77 */
78 protected AbstractBasicAclEntry() {
79 validPermissions = getValidPermissions();
80 Arrays.sort(validPermissions);
81 }
82
83
84
85 public void setAclObjectIdentity(AclObjectIdentity aclObjectIdentity) {
86 this.aclObjectIdentity = aclObjectIdentity;
87 }
88
89 public AclObjectIdentity getAclObjectIdentity() {
90 return this.aclObjectIdentity;
91 }
92
93 public void setAclObjectParentIdentity(
94 AclObjectIdentity aclObjectParentIdentity) {
95 this.aclObjectParentIdentity = aclObjectParentIdentity;
96 }
97
98 public AclObjectIdentity getAclObjectParentIdentity() {
99 return this.aclObjectParentIdentity;
100 }
101
102 /***
103 * Subclasses must indicate the permissions they support. Each base
104 * permission should be an integer with a base 2. ie: the first permission
105 * is 2^^0 (1), the second permission is 2^^1 (2), the third permission is
106 * 2^^2 (4) etc. Each base permission should be exposed by the subclass as
107 * a <code>public static final int</code>. It is further recommended that
108 * valid combinations of permissions are also exposed as <code>public
109 * static final int</code>s.
110 *
111 * <P>
112 * This method returns all permission integers that are allowed to be used
113 * together. <B>This must include any combinations of valid
114 * permissions</b>. So if the permissions indicated by 2^^2 (4) and 2^^1
115 * (2) can be used together, one of the integers returned by this method
116 * must be 6 (4 + 2). Otherwise attempts to set the permission will be
117 * rejected, as the final resulting mask will be rejected.
118 * </p>
119 *
120 * <P>
121 * Whilst it may seem unduly time onerous to return every valid permission
122 * <B>combination</B>, doing so delivers maximum flexibility in ensuring
123 * ACLs only reflect logical combinations. For example, it would be
124 * inappropriate to grant a "read" and "write" permission along with an
125 * "unrestricted" permission, as the latter implies the former
126 * permissions.
127 * </p>
128 *
129 * @return <b>every</b> valid combination of permissions
130 */
131 public abstract int[] getValidPermissions();
132
133 /***
134 * Outputs the permissions in a human-friendly format. For example, this
135 * method may return "CR-D" to indicate the passed integer permits create,
136 * permits read, does not permit update, and permits delete.
137 *
138 * @param i the integer containing the mask which should be printed
139 *
140 * @return the human-friend formatted block
141 */
142 public abstract String printPermissionsBlock(int i);
143
144 public void setMask(int mask) {
145 this.mask = mask;
146 }
147
148 public int getMask() {
149 return this.mask;
150 }
151
152 public boolean isPermitted(int permissionToCheck) {
153 return isPermitted(this.mask, permissionToCheck);
154 }
155
156 public void setRecipient(Object recipient) {
157 this.recipient = recipient;
158 }
159
160 public Object getRecipient() {
161 return this.recipient;
162 }
163
164 public int addPermission(int permissionToAdd) {
165 return addPermissions(new int[] {permissionToAdd});
166 }
167
168 public int addPermissions(int[] permissionsToAdd) {
169 if (logger.isDebugEnabled()) {
170 logger.debug("BEFORE Permissions: " + printPermissionsBlock(mask)
171 + " " + printBinary(mask) + " (" + mask + ")");
172 }
173
174 for (int i = 0; i < permissionsToAdd.length; i++) {
175 if (logger.isDebugEnabled()) {
176 logger.debug("Add permission: "
177 + printPermissionsBlock(permissionsToAdd[i]) + " "
178 + printBinary(permissionsToAdd[i]) + " ("
179 + permissionsToAdd[i] + ")");
180 }
181
182 this.mask |= permissionsToAdd[i];
183 }
184
185 if (Arrays.binarySearch(validPermissions, this.mask) < 0) {
186 throw new IllegalArgumentException(
187 "Resulting permission set will be invalid.");
188 } else {
189 if (logger.isDebugEnabled()) {
190 logger.debug("AFTER Permissions: "
191 + printPermissionsBlock(mask) + " " + printBinary(mask)
192 + " (" + mask + ")");
193 }
194
195 return this.mask;
196 }
197 }
198
199 public int deletePermission(int permissionToDelete) {
200 return deletePermissions(new int[] {permissionToDelete});
201 }
202
203 public int deletePermissions(int[] permissionsToDelete) {
204 if (logger.isDebugEnabled()) {
205 logger.debug("BEFORE Permissions: " + printPermissionsBlock(mask)
206 + " " + printBinary(mask) + " (" + mask + ")");
207 }
208
209 for (int i = 0; i < permissionsToDelete.length; i++) {
210 if (logger.isDebugEnabled()) {
211 logger.debug("Delete permission: "
212 + printPermissionsBlock(permissionsToDelete[i]) + " "
213 + printBinary(permissionsToDelete[i]) + " ("
214 + permissionsToDelete[i] + ")");
215 }
216
217 this.mask &= ~permissionsToDelete[i];
218 }
219
220 if (Arrays.binarySearch(validPermissions, this.mask) < 0) {
221 throw new IllegalArgumentException(
222 "Resulting permission set will be invalid.");
223 } else {
224 if (logger.isDebugEnabled()) {
225 logger.debug("AFTER Permissions: "
226 + printPermissionsBlock(mask) + " " + printBinary(mask)
227 + " (" + mask + ")");
228 }
229
230 return this.mask;
231 }
232 }
233
234 /***
235 * Outputs the permissions in human-friendly format for the current
236 * <code>AbstractBasicAclEntry</code>'s mask.
237 *
238 * @return the human-friendly formatted block for this instance
239 */
240 public String printPermissionsBlock() {
241 return printPermissionsBlock(this.mask);
242 }
243
244 public String toString() {
245 StringBuffer sb = new StringBuffer();
246 sb.append(getClass().getName());
247 sb.append("[").append(aclObjectIdentity).append(",").append(recipient);
248 sb.append("=").append(printPermissionsBlock(mask)).append(" ");
249 sb.append(printBinary(mask)).append(" (");
250 sb.append(mask).append(")").append("]");
251
252 return sb.toString();
253 }
254
255 public int togglePermission(int permissionToToggle) {
256 this.mask ^= permissionToToggle;
257
258 if (Arrays.binarySearch(validPermissions, this.mask) < 0) {
259 throw new IllegalArgumentException(
260 "Resulting permission set will be invalid.");
261 } else {
262 return this.mask;
263 }
264 }
265
266 protected boolean isPermitted(int maskToCheck, int permissionToCheck) {
267 return ((maskToCheck & permissionToCheck) == permissionToCheck);
268 }
269
270 private String printBinary(int i) {
271 String s = Integer.toString(i, 2);
272
273 String pattern = "................................";
274
275 String temp1 = pattern.substring(0, pattern.length() - s.length());
276
277 String temp2 = temp1 + s;
278
279 return temp2.replace('0', '.');
280 }
281 }