mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-10-30 22:28:46 +00:00 
			
		
		
		
	SEC-239: Initial commit. Work-in-progress only.
This commit is contained in:
		
							parent
							
								
									4d24c88d1e
								
							
						
					
					
						commit
						5ba40705e8
					
				| @ -0,0 +1,30 @@ | ||||
| package org.acegisecurity.acls; | ||||
| 
 | ||||
| import java.io.Serializable; | ||||
| 
 | ||||
| import org.acegisecurity.acls.sid.Sid; | ||||
| 
 | ||||
| /** | ||||
|  * Represents an individual permission assignment within an {@link Acl}.  | ||||
|  *  | ||||
|  * <p> | ||||
|  * Instances MUST be immutable, as they are returned by <code>Acl</code> | ||||
|  * and should not allow client modification. | ||||
|  *  | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  * | ||||
|  */ | ||||
| public interface AccessControlEntry { | ||||
|     /** | ||||
|      * Obtains an identifier that represents this ACE. | ||||
|      * | ||||
|      * @return the identifier, or <code>null</code> if unsaved | ||||
|      */ | ||||
|     public Serializable getId(); | ||||
|      | ||||
| 	public Acl getAcl(); | ||||
| 	public Sid getSid(); | ||||
| 	public Permission getPermission(); | ||||
| 	public boolean isGranting(); | ||||
| } | ||||
							
								
								
									
										206
									
								
								sandbox/src/main/java/org/acegisecurity/acls/Acl.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								sandbox/src/main/java/org/acegisecurity/acls/Acl.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,206 @@ | ||||
| /* 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.acls; | ||||
| 
 | ||||
| import java.io.Serializable; | ||||
| 
 | ||||
| import org.acegisecurity.acls.objectidentity.ObjectIdentity; | ||||
| import org.acegisecurity.acls.sid.Sid; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Represents an access control list (ACL) for a domain object. | ||||
|  *  | ||||
|  * <p> | ||||
|  * An <code>Acl</code> represents all ACL entries for a given domain object. In | ||||
|  * order to avoid needing references to the domain object itself, this | ||||
|  * interface handles indirection between a domain object and an ACL object | ||||
|  * identity via the {@link | ||||
|  * org.acegisecurity.acls.objectidentity.ObjectIdentity} interface. | ||||
|  * </p> | ||||
|  *  | ||||
|  * <p> | ||||
|  * An implementation represents the {@link org.acegisecurity.acls.Permission} | ||||
|  * list applicable for some or all {@link org.acegisecurity.acls.sid.Sid} | ||||
|  * instances. | ||||
|  * </p> | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public interface Acl extends Serializable { | ||||
|     //~ Methods ================================================================ | ||||
| 
 | ||||
| 	 | ||||
|     /** | ||||
|      * Returns all of the entries represented by the present <code>Acl</code> | ||||
|      * (not parents). | ||||
|      *  | ||||
|      * <p> | ||||
|      * This method is typically used for administrative purposes. | ||||
|      * </p> | ||||
|      *  | ||||
|      * <p> | ||||
|      * The order that entries appear in the array is unspecified. However, if | ||||
|      * implementations use particular ordering logic in authorization | ||||
|      * decisions, the entries returned by this method <em>MUST</em> be ordered | ||||
|      * in that manner. | ||||
|      * </p> | ||||
|      *  | ||||
|      * <p> | ||||
|      * Do <em>NOT</em> use this method for making authorization decisions. | ||||
|      * Instead use {@link #isGranted(Permission[], Sid[])}. | ||||
|      * </p> | ||||
|      *  | ||||
|      * <p> | ||||
|      * This method must operate correctly even if the <code>Acl</code> only | ||||
|      * represents a subset of <code>Sid</code>s. The caller is responsible for | ||||
|      * correctly handling the result if only a subset of <code>Sid</code>s is | ||||
|      * represented. | ||||
|      * </p> | ||||
|      * | ||||
|      * @return the list of entries represented by the <code>Acl</code> | ||||
|      */ | ||||
|     public AccessControlEntry[] getEntries(); | ||||
| 
 | ||||
|     /** | ||||
|      * Obtains the domain object this <code>Acl</code> provides entries for. | ||||
|      * This is immutable once an <code>Acl</code> is created. | ||||
|      * | ||||
|      * @return the object identity | ||||
|      */ | ||||
|     public ObjectIdentity getObjectIdentity(); | ||||
| 
 | ||||
|     /** | ||||
|      * A domain object may have a parent for the purpose of ACL inheritance. If | ||||
|      * there is a parent, its ACL can be accessed via this method. In turn, | ||||
|      * the parent's parent (grandparent) can be accessed and so on. | ||||
|      *  | ||||
|      * <p> | ||||
|      * This method solely represents the presence of a navigation hierarchy | ||||
|      * between the parent <code>Acl</code> and this <code>Acl</code>. For | ||||
|      * actual inheritance to take place, the {@link #isEntriesInheriting()} | ||||
|      * must also be <code>true</code>. | ||||
|      * </p> | ||||
|      *  | ||||
|      * <p> | ||||
|      * This method must operate correctly even if the <code>Acl</code> only | ||||
|      * represents a subset of <code>Sid</code>s. The caller is responsible for | ||||
|      * correctly handling the result if only a subset of <code>Sid</code>s is | ||||
|      * represented. | ||||
|      * </p> | ||||
|      * | ||||
|      * @return the parent <code>Acl</code> | ||||
|      */ | ||||
|     public Acl getParentAcl(); | ||||
| 
 | ||||
|     /** | ||||
|      * Indicates whether the ACL entries from the {@link #getParentAcl()} | ||||
|      * should flow down into the current <code>Acl</code>. | ||||
|      *  | ||||
|      * <p> | ||||
|      * The mere link between an <code>Acl</code> and a parent <code>Acl</code> | ||||
|      * on its own is insufficient to cause ACL entries to inherit down. This | ||||
|      * is because a domain object may wish to have entirely independent | ||||
|      * entries, but maintain the link with the parent for navigation purposes. | ||||
|      * Thus, this method denotes whether or not the navigation relationship | ||||
|      * also extends to the actual inheritence of entries. | ||||
|      * </p> | ||||
|      * | ||||
|      * @return <code>true</code> if parent ACL entries inherit into the current | ||||
|      *         <code>Acl</code> | ||||
|      */ | ||||
|     public boolean isEntriesInheriting(); | ||||
| 
 | ||||
|     /** | ||||
|      * This is the actual authorization logic method, and must be used whenever | ||||
|      * ACL authorization decisions are required. | ||||
|      *  | ||||
|      * <p> | ||||
|      * An array of <code>Sid</code>s are presented, representing security | ||||
|      * identifies of the current principal. In addition, an array of | ||||
|      * <code>Permission</code>s is presented which will have one or more bits | ||||
|      * set in order to indicate the permissions needed for an affirmative | ||||
|      * authorization decision. An array is presented because holding | ||||
|      * <em>any</em> of the <code>Permission</code>s inside the array will be | ||||
|      * sufficient for an affirmative authorization. | ||||
|      * </p> | ||||
|      *  | ||||
|      * <p> | ||||
|      * The actual approach used to make authorization decisions is left to the | ||||
|      * implementation and is not specified by this interface. For example, an | ||||
|      * implementation <em>MAY</em> search the current ACL in the order the ACL | ||||
|      * entries have been stored. If a single entry is found that has the same | ||||
|      * active bits as are shown in a passed <code>Permission</code>, that | ||||
|      * entry's grant or deny state may determine the authorization decision. | ||||
|      * If the case of a deny state, the deny decision will only be relevant if | ||||
|      * all other <code>Permission</code>s passed in the array have also been | ||||
|      * unsuccessfully searched. If no entry is found that match the bits in | ||||
|      * the current ACL, provided that {@link #isEntriesInheriting()} is | ||||
|      * <code>true</code>, the authorization decision may be passed to the | ||||
|      * parent ACL. If there is no matching entry, the implementation MAY throw | ||||
|      * an exception, or make a predefined authorization decision. | ||||
|      * </p> | ||||
|      *  | ||||
|      * <p> | ||||
|      * This method must operate correctly even if the <code>Acl</code> only | ||||
|      * represents a subset of <code>Sid</code>s. The caller is responsible for | ||||
|      * correctly handling the result if only a subset of <code>Sid</code>s is | ||||
|      * represented. | ||||
|      * </p> | ||||
|      * | ||||
|      * @param permission the permission or permissions required | ||||
|      * @param sids the security identities held by the principal | ||||
|      * @param administrativeMode if <code>true</code> denotes the query is for | ||||
|      *        administrative purposes and no logger or auditing (if supported | ||||
|      *        by the implementation) should be undertaken | ||||
|      * | ||||
|      * @return <code>true</code> is authorization is granted | ||||
|      * | ||||
|      * @throws NotFoundException MAY be thrown if an implementation cannot make | ||||
|      *         an authoritative authorization decision | ||||
|      * @throws UnloadedSidException thrown if the <code>Acl</code> does not | ||||
|      *         have details for one or more of the <code>Sid</code>s passed as | ||||
|      *         arguments | ||||
|      */ | ||||
|     public boolean isGranted(Permission[] permission, Sid[] sids, | ||||
|         boolean administrativeMode) | ||||
|         throws NotFoundException, UnloadedSidException; | ||||
| 
 | ||||
|     /** | ||||
|      * For efficiency reasons an <code>Acl</code> may be loaded and | ||||
|      * <em>not</em> contain entries for every <code>Sid</code> in the system. | ||||
|      * If an <code>Acl</code> has been loaded and does not represent every | ||||
|      * <code>Sid</code>, all methods of the <code>Sid</code> can only be used | ||||
|      * within the limited scope of the <code>Sid</code> instances it actually | ||||
|      * represents. | ||||
|      *  | ||||
|      * <p> | ||||
|      * It is normal to load an <code>Acl</code> for only particular | ||||
|      * <code>Sid</code>s if read-only authorization decisions are being made. | ||||
|      * However, if user interface reporting or modification of | ||||
|      * <code>Acl</code>s are desired, an <code>Acl</code> should be loaded | ||||
|      * with all <code>Sid</code>s. This method denotes whether or not the | ||||
|      * specified <code>Sid</code>s have been loaded or not. | ||||
|      * </p> | ||||
|      * | ||||
|      * @param sids DOCUMENT ME! | ||||
|      * | ||||
|      * @return <code>true</code> if every passed <code>Sid</code> is | ||||
|      *         represented by this <code>Acl</code> instance | ||||
|      */ | ||||
|     public boolean isSidLoaded(Sid[] sids); | ||||
| } | ||||
| @ -0,0 +1,118 @@ | ||||
| /* 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.acls; | ||||
| 
 | ||||
| import org.springframework.util.Assert; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Utility methods for displaying ACL information. | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public class AclFormattingUtils { | ||||
|     //~ Methods ================================================================ | ||||
| 
 | ||||
|     public static String demergePatterns(String original, String removeBits) { | ||||
|         Assert.notNull(original, "Original string required"); | ||||
|         Assert.notNull(removeBits, "Bits To Remove string required"); | ||||
|         Assert.isTrue(original.length() == removeBits.length(), | ||||
|             "Original and Bits To Remove strings must be identical length"); | ||||
| 
 | ||||
|         char[] replacement = new char[original.length()]; | ||||
| 
 | ||||
|         for (int i = 0; i < original.length(); i++) { | ||||
|             if (removeBits.charAt(i) == Permission.RESERVED_OFF) { | ||||
|                 replacement[i] = original.charAt(i); | ||||
|             } else { | ||||
|                 replacement[i] = Permission.RESERVED_OFF; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return new String(replacement); | ||||
|     } | ||||
| 
 | ||||
|     public static String mergePatterns(String original, String extraBits) { | ||||
|         Assert.notNull(original, "Original string required"); | ||||
|         Assert.notNull(extraBits, "Extra Bits string required"); | ||||
|         Assert.isTrue(original.length() == extraBits.length(), | ||||
|             "Original and Extra Bits strings must be identical length"); | ||||
| 
 | ||||
|         char[] replacement = new char[extraBits.length()]; | ||||
| 
 | ||||
|         for (int i = 0; i < extraBits.length(); i++) { | ||||
|             if (extraBits.charAt(i) == Permission.RESERVED_OFF) { | ||||
|                 replacement[i] = original.charAt(i); | ||||
|             } else { | ||||
|                 replacement[i] = extraBits.charAt(i); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return new String(replacement); | ||||
|     } | ||||
| 
 | ||||
|     private static String printBinary(int i, char on, char off) { | ||||
|         String s = Integer.toString(i, 2); | ||||
|         String pattern = Permission.THIRTY_TWO_RESERVED_OFF; | ||||
|         String temp2 = pattern.substring(0, pattern.length() - s.length()) + s; | ||||
| 
 | ||||
|         return temp2.replace('0', off).replace('1', on); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns a representation of the active bits in the presented mask, with | ||||
|      * each active bit being denoted by character "". | ||||
|      *  | ||||
|      * <p> | ||||
|      * Inactive bits will be denoted by character {@link | ||||
|      * Permission#RESERVED_OFF}. | ||||
|      * </p> | ||||
|      * | ||||
|      * @param i the integer bit mask to print the active bits for | ||||
|      * | ||||
|      * @return a 32-character representation of the bit mask | ||||
|      */ | ||||
|     public static String printBinary(int i) { | ||||
|         return AclFormattingUtils.printBinary(i, '*', Permission.RESERVED_OFF); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns a representation of the active bits in the presented mask, with | ||||
|      * each active bit being denoted by the passed character. | ||||
|      *  | ||||
|      * <p> | ||||
|      * Inactive bits will be denoted by character {@link | ||||
|      * Permission#RESERVED_OFF}. | ||||
|      * </p> | ||||
|      * | ||||
|      * @param mask the integer bit mask to print the active bits for | ||||
|      * @param code the character to print when an active bit is detected | ||||
|      * | ||||
|      * @return a 32-character representation of the bit mask | ||||
|      */ | ||||
|     public static String printBinary(int mask, char code) { | ||||
|         Assert.doesNotContain(new Character(code).toString(), | ||||
|             new Character(Permission.RESERVED_ON).toString(), | ||||
|             Permission.RESERVED_ON + " is a reserved character code"); | ||||
|         Assert.doesNotContain(new Character(code).toString(), | ||||
|             new Character(Permission.RESERVED_OFF).toString(), | ||||
|             Permission.RESERVED_OFF + " is a reserved character code"); | ||||
| 
 | ||||
|         return AclFormattingUtils.printBinary(mask, Permission.RESERVED_ON, | ||||
|             Permission.RESERVED_OFF).replace(Permission.RESERVED_ON, code); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										75
									
								
								sandbox/src/main/java/org/acegisecurity/acls/AclService.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								sandbox/src/main/java/org/acegisecurity/acls/AclService.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | ||||
| /* 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.acls; | ||||
| 
 | ||||
| import org.acegisecurity.acls.objectidentity.ObjectIdentity; | ||||
| import org.acegisecurity.acls.sid.Sid; | ||||
| 
 | ||||
| import java.util.Map; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Provides retrieval of {@link Acl} instances. | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public interface AclService { | ||||
|     //~ Methods ================================================================ | ||||
| 
 | ||||
|     /** | ||||
|      * Obtains all the <code>Acl</code>s that apply for the passed | ||||
|      * <code>Object</code>s. | ||||
|      *  | ||||
|      * <p> | ||||
|      * The returned map is keyed on the passed objects, with the values being | ||||
|      * the <code>Acl</code> instances. Any unknown objects will not have a map | ||||
|      * key. | ||||
|      * </p> | ||||
|      * | ||||
|      * @param objects the objects to find ACL information for | ||||
|      * | ||||
|      * @return a map with zero or more elements (never <code>null</code>) | ||||
|      */ | ||||
|     public Map readAclsById(ObjectIdentity[] objects) throws NotFoundException; | ||||
| 
 | ||||
|     /** | ||||
|      * Obtains all the <code>Acl</code>s that apply for the passed | ||||
|      * <code>Object</code>s, but only for the security identifies passed. | ||||
|      *  | ||||
|      * <p> | ||||
|      * Implementations <em>MAY</em> provide a subset of the ACLs via this | ||||
|      * method although this is NOT a requirement. This is intended to allow | ||||
|      * performance optimisations within implementations. Callers should | ||||
|      * therefore use this method in preference to the alternative overloaded | ||||
|      * version which does not have performance optimisation opportunities. | ||||
|      * </p> | ||||
|      *  | ||||
|      * <p> | ||||
|      * The returned map is keyed on the passed objects, with the values being | ||||
|      * the <code>Acl</code> instances. Any unknown objects (or objects for | ||||
|      * which the interested <code>Sid</code>s do not have entries) will not | ||||
|      * have a map key. | ||||
|      * </p> | ||||
|      * | ||||
|      * @param objects the objects to find ACL information for | ||||
|      * @param sids the security identities for which ACL information is | ||||
|      *        required (may be <code>null</code> to denote all entries) | ||||
|      * | ||||
|      * @return a map with zero or more elements (never <code>null</code>) | ||||
|      */ | ||||
|     public Map readAclsById(ObjectIdentity[] objects, Sid[] sids) throws NotFoundException; | ||||
| } | ||||
| @ -0,0 +1,49 @@ | ||||
| /* 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.acls; | ||||
| 
 | ||||
| import org.acegisecurity.AcegiSecurityException; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Thrown if an <code>Acl</code> entry already exists for the object. | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public class AlreadyExistsException extends AcegiSecurityException { | ||||
|     //~ Constructors =========================================================== | ||||
| 
 | ||||
|     /** | ||||
|      * Constructs an <code>AlreadyExistsException</code> with the specified message. | ||||
|      * | ||||
|      * @param msg the detail message | ||||
|      */ | ||||
|     public AlreadyExistsException(String msg) { | ||||
|         super(msg); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Constructs an <code>AlreadyExistsException</code> with the specified message | ||||
|      * and root cause. | ||||
|      * | ||||
|      * @param msg the detail message | ||||
|      * @param t root cause | ||||
|      */ | ||||
|     public AlreadyExistsException(String msg, Throwable t) { | ||||
|         super(msg, t); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,13 @@ | ||||
| package org.acegisecurity.acls; | ||||
| 
 | ||||
| /** | ||||
|  * Represents an ACE that provides auditing information. | ||||
|  *  | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  * | ||||
|  */ | ||||
| public interface AuditableAccessControlEntry extends AccessControlEntry { | ||||
| 	public boolean isAuditSuccess(); | ||||
| 	public boolean isAuditFailure(); | ||||
| } | ||||
| @ -0,0 +1,12 @@ | ||||
| package org.acegisecurity.acls; | ||||
| 
 | ||||
| /** | ||||
|  * A mutable ACL that provides audit capabilities. | ||||
|  *  | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  * | ||||
|  */ | ||||
| public interface AuditableAcl extends MutableAcl { | ||||
| 	public void updateAuditing(Long aceId, boolean auditSuccess, boolean auditFailure); | ||||
| } | ||||
| @ -0,0 +1,51 @@ | ||||
| /* 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.acls; | ||||
| 
 | ||||
| import org.acegisecurity.AcegiSecurityException; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Thrown if an {@link Acl} cannot be deleted because children | ||||
|  * <code>Acl</code>s exist. | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public class ChildrenExistException extends AcegiSecurityException { | ||||
|     //~ Constructors =========================================================== | ||||
| 
 | ||||
|     /** | ||||
|      * Constructs an <code>ChildrenExistException</code> with the specified | ||||
|      * message. | ||||
|      * | ||||
|      * @param msg the detail message | ||||
|      */ | ||||
|     public ChildrenExistException(String msg) { | ||||
|         super(msg); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Constructs an <code>ChildrenExistException</code> with the specified | ||||
|      * message and root cause. | ||||
|      * | ||||
|      * @param msg the detail message | ||||
|      * @param t root cause | ||||
|      */ | ||||
|     public ChildrenExistException(String msg, Throwable t) { | ||||
|         super(msg, t); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,49 @@ | ||||
| /* 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.acls; | ||||
| 
 | ||||
| import org.acegisecurity.AcegiSecurityException; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Thrown if an ACL identity could not be extracted from an object. | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public class IdentityUnavailableException extends AcegiSecurityException { | ||||
|     //~ Constructors =========================================================== | ||||
| 
 | ||||
|     /** | ||||
|      * Constructs an <code>IdentityUnavailableException</code> with the specified message. | ||||
|      * | ||||
|      * @param msg the detail message | ||||
|      */ | ||||
|     public IdentityUnavailableException(String msg) { | ||||
|         super(msg); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Constructs an <code>IdentityUnavailableException</code> with the specified message | ||||
|      * and root cause. | ||||
|      * | ||||
|      * @param msg the detail message | ||||
|      * @param t root cause | ||||
|      */ | ||||
|     public IdentityUnavailableException(String msg, Throwable t) { | ||||
|         super(msg, t); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										61
									
								
								sandbox/src/main/java/org/acegisecurity/acls/MutableAcl.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								sandbox/src/main/java/org/acegisecurity/acls/MutableAcl.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,61 @@ | ||||
| /* 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.acls; | ||||
| 
 | ||||
| import java.io.Serializable; | ||||
| 
 | ||||
| import org.acegisecurity.acls.sid.Sid; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * A mutable <code>Acl</code>. | ||||
|  *  | ||||
|  * <p> | ||||
|  * A mutable ACL must ensure that appropriate security checks are performed | ||||
|  * before allowing access to its methods. | ||||
|  * </p> | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public interface MutableAcl extends Acl { | ||||
|     //~ Methods ================================================================ | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * Obtains an identifier that represents this <code>MutableAcl</code>. | ||||
|      * | ||||
|      * @return the identifier, or <code>null</code> if unsaved | ||||
|      */ | ||||
|     public Serializable getId(); | ||||
| 
 | ||||
| 	 | ||||
|     public void deleteAce(Long aceId) throws NotFoundException ; | ||||
| 
 | ||||
|     public void insertAce(Long afterAceId, Permission permission, Sid sid, | ||||
|         boolean granting) throws NotFoundException; | ||||
| 
 | ||||
|     /** | ||||
|      * Changes the parent of this ACL. | ||||
|      * | ||||
|      * @param newParent the new parent | ||||
|      */ | ||||
|     public void setParent(MutableAcl newParent); | ||||
|      | ||||
|     public void updateAce(Long aceId, Permission permission) throws NotFoundException; | ||||
|      | ||||
|     public void setEntriesInheriting(boolean entriesInheriting); | ||||
| } | ||||
| @ -0,0 +1,77 @@ | ||||
| /* 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.acls; | ||||
| 
 | ||||
| import org.acegisecurity.acls.objectidentity.ObjectIdentity; | ||||
| 
 | ||||
| /** | ||||
|  * Provides support for creating and storing <code>Acl</code> instances. | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public interface MutableAclService extends AclService { | ||||
|     //~ Methods ================================================================ | ||||
| 
 | ||||
|     /** | ||||
|      * Creates an empty <code>Acl</code> object in the database. It will have | ||||
|      * no entries. The returned object will then be used to add entries. | ||||
|      * | ||||
|      * @param object the object identity to create | ||||
|      * | ||||
|      * @return an ACL object with its ID set | ||||
|      * | ||||
|      * @throws AlreadyExistsException if the passed object identity already has | ||||
|      *         a record | ||||
|      */ | ||||
|     public MutableAcl createAcl(ObjectIdentity object) | ||||
|         throws AlreadyExistsException; | ||||
| 
 | ||||
|     /** | ||||
|      * Removes the specified entry from the database. | ||||
|      * | ||||
|      * @param object the object identity to remove | ||||
|      * @param deleteChildren whether to cascade the delete to children | ||||
|      * | ||||
|      * @throws ChildrenExistException if the deleteChildren argument was | ||||
|      *         <code>false</code> but children exist | ||||
|      */ | ||||
|     public void deleteAcl(ObjectIdentity object, boolean deleteChildren) | ||||
|         throws ChildrenExistException; | ||||
| 
 | ||||
|     /** | ||||
|      * Locates all object identities that use the specified parent.  This is | ||||
|      * useful for administration tools, and before issuing a {@link | ||||
|      * #deleteAcl(ObjectIdentity, boolean)}. | ||||
|      * | ||||
|      * @param parentIdentity to locate children of | ||||
|      * | ||||
|      * @return the children (or <code>null</code> if none were found) | ||||
|      */ | ||||
|     public ObjectIdentity[] findChildren(ObjectIdentity parentIdentity); | ||||
| 
 | ||||
|     /** | ||||
|      * Changes an existing <code>Acl</code> in the database. | ||||
|      * | ||||
|      * @param acl to modify | ||||
|      * | ||||
|      * @throws NotFoundException if the relevant record could not be found (did | ||||
|      *         you remember to use {@link #createAcl(ObjectIdentity)} to | ||||
|      *         create the object, rather than creating it with the | ||||
|      *         <code>new</code> keyword?) | ||||
|      */ | ||||
|     public void updateAcl(MutableAcl acl) throws NotFoundException; | ||||
| } | ||||
| @ -0,0 +1,49 @@ | ||||
| /* 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.acls; | ||||
| 
 | ||||
| import org.acegisecurity.AcegiSecurityException; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Thrown if an ACL-related object cannot be found. | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public class NotFoundException extends AcegiSecurityException { | ||||
|     //~ Constructors =========================================================== | ||||
| 
 | ||||
|     /** | ||||
|      * Constructs an <code>NotFoundException</code> with the specified message. | ||||
|      * | ||||
|      * @param msg the detail message | ||||
|      */ | ||||
|     public NotFoundException(String msg) { | ||||
|         super(msg); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Constructs an <code>NotFoundException</code> with the specified message | ||||
|      * and root cause. | ||||
|      * | ||||
|      * @param msg the detail message | ||||
|      * @param t root cause | ||||
|      */ | ||||
|     public NotFoundException(String msg, Throwable t) { | ||||
|         super(msg, t); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,37 @@ | ||||
| /* 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.acls; | ||||
| 
 | ||||
| import org.acegisecurity.acls.sid.Sid; | ||||
| 
 | ||||
| /** | ||||
|  * A mutable ACL that provides ownership capabilities. | ||||
|  *  | ||||
|  * <p> | ||||
|  * Generally the owner of an ACL is able to call any ACL mutator method, as | ||||
|  * well as assign a new owner. | ||||
|  * </p> | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public interface OwnershipAcl extends MutableAcl { | ||||
|     //~ Methods ================================================================ | ||||
| 
 | ||||
|     public Sid getOwner(); | ||||
| 
 | ||||
|     public void setOwner(Sid newOwner); | ||||
| } | ||||
							
								
								
									
										70
									
								
								sandbox/src/main/java/org/acegisecurity/acls/Permission.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								sandbox/src/main/java/org/acegisecurity/acls/Permission.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,70 @@ | ||||
| /* 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.acls; | ||||
| 
 | ||||
| import org.acegisecurity.acls.sid.Sid; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Represents a permission granted to a {@link Sid} for a given domain object. | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public interface Permission { | ||||
|     //~ Static fields/initializers ============================================= | ||||
| 
 | ||||
|     public static final char RESERVED_ON = '~'; | ||||
|     public static final char RESERVED_OFF = '.'; | ||||
| 	public static final String THIRTY_TWO_RESERVED_OFF = "................................"; | ||||
| 
 | ||||
|     //~ Methods ================================================================ | ||||
| 
 | ||||
|     /** | ||||
|      * Returns the bits that represents the permission. | ||||
|      * | ||||
|      * @return the bits that represent the permission | ||||
|      */ | ||||
|     public int getMask(); | ||||
| 
 | ||||
|     /** | ||||
|      * Returns a 32-character long bit pattern <code>String</code> representing | ||||
|      * this permission. | ||||
|      *  | ||||
|      * <p> | ||||
|      * Implementations are free to format the pattern as they see fit, although | ||||
|      * under no circumstances may {@link #RESERVED_OFF} or {@link | ||||
|      * #RESERVED_ON} be used within the pattern. An exemption is in the case | ||||
|      * of {@link #RESERVED_OFF} which is used to denote a bit that is off | ||||
|      * (clear). Implementations may also elect to use {@link #RESERVED_ON} | ||||
|      * internally for computation purposes, although this method may not | ||||
|      * return any <code>String</code> containing {@link #RESERVED_ON}. | ||||
|      * </p> | ||||
|      *  | ||||
|      * <p> | ||||
|      * The returned String must be 32 characters in length. | ||||
|      * </p> | ||||
|      *  | ||||
|      * <p> | ||||
|      * This method is only used for user interface and logging purposes. It is | ||||
|      * not used in any permission calculations. Therefore, duplication of | ||||
|      * characters within the output is permitted. | ||||
|      * </p> | ||||
|      * | ||||
|      * @return a 32-character bit pattern | ||||
|      */ | ||||
|     public String getPattern(); | ||||
| } | ||||
| @ -0,0 +1,51 @@ | ||||
| /* 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.acls; | ||||
| 
 | ||||
| import org.acegisecurity.AcegiSecurityException; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Thrown if an {@link Acl} cannot perform an operation because it only | ||||
|  * loaded a subset of <code>Sid</code>s and the caller has requested details | ||||
|  * for an unloaded <code>Sid</code>. | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public class UnloadedSidException extends AcegiSecurityException { | ||||
|     //~ Constructors =========================================================== | ||||
| 
 | ||||
|     /** | ||||
|      * Constructs an <code>NotFoundException</code> with the specified message. | ||||
|      * | ||||
|      * @param msg the detail message | ||||
|      */ | ||||
|     public UnloadedSidException(String msg) { | ||||
|         super(msg); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Constructs an <code>NotFoundException</code> with the specified message | ||||
|      * and root cause. | ||||
|      * | ||||
|      * @param msg the detail message | ||||
|      * @param t root cause | ||||
|      */ | ||||
|     public UnloadedSidException(String msg, Throwable t) { | ||||
|         super(msg, t); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,124 @@ | ||||
| package org.acegisecurity.acls.domain; | ||||
| 
 | ||||
| import java.io.Serializable; | ||||
| 
 | ||||
| import org.acegisecurity.acls.AccessControlEntry; | ||||
| import org.acegisecurity.acls.Acl; | ||||
| import org.acegisecurity.acls.AuditableAccessControlEntry; | ||||
| import org.acegisecurity.acls.Permission; | ||||
| import org.acegisecurity.acls.sid.Sid; | ||||
| import org.springframework.util.Assert; | ||||
| 
 | ||||
| /** | ||||
|  * An immutable default implementation of <code>AccessControlEntry</code>. | ||||
|  *  | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public class AccessControlEntryImpl implements AccessControlEntry, AuditableAccessControlEntry { | ||||
| 	private Serializable id; | ||||
| 	private Acl acl; | ||||
| 	private Sid sid; | ||||
| 	private Permission permission; | ||||
| 	private boolean granting; | ||||
| 	private boolean auditSuccess = false; | ||||
| 	private boolean auditFailure = false; | ||||
| 	private boolean aceDirty = false; | ||||
| 	 | ||||
| 	public void clearDirtyFlags() { | ||||
| 		this.aceDirty = false; | ||||
| 	} | ||||
| 	 | ||||
| 	public boolean equals(Object arg0) { | ||||
| 		if (!(arg0 instanceof AccessControlEntryImpl)) { | ||||
| 			return false; | ||||
| 		} | ||||
| 		AccessControlEntryImpl rhs = (AccessControlEntryImpl) arg0; | ||||
| 		if (this.aceDirty != rhs.isAceDirty() || | ||||
| 			this.auditFailure != rhs.isAuditFailure() || | ||||
| 			this.auditSuccess != rhs.isAuditSuccess() || | ||||
| 			this.granting != rhs.isGranting() || | ||||
| 			!this.acl.equals(rhs.getAcl()) || | ||||
| 			!this.id.equals(rhs.getId()) || | ||||
| 			!this.permission.equals(rhs.getPermission()) || | ||||
| 			!this.sid.equals(rhs.getSid()) ) { | ||||
| 			return false; | ||||
| 		} | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 	public AccessControlEntryImpl(Serializable id, Acl acl, Sid sid, Permission permission, boolean granting, boolean auditSuccess, boolean auditFailure) { | ||||
| 		Assert.notNull(acl, "Acl required"); | ||||
| 		Assert.notNull(sid, "Sid required"); | ||||
| 		Assert.notNull(permission, "Permission required"); | ||||
| 		this.id = id; | ||||
| 		this.acl = acl; // can be null | ||||
| 		this.sid = sid; | ||||
| 		this.permission = permission; | ||||
| 		this.granting = granting; | ||||
| 		this.auditSuccess = auditSuccess; | ||||
| 		this.auditFailure = auditFailure; | ||||
| 	} | ||||
| 	 | ||||
| 	public Acl getAcl() { | ||||
| 		return acl; | ||||
| 	} | ||||
| 	public boolean isGranting() { | ||||
| 		return granting; | ||||
| 	} | ||||
| 	public Serializable getId() { | ||||
| 		return id; | ||||
| 	} | ||||
| 	public Permission getPermission() { | ||||
| 		return permission; | ||||
| 	} | ||||
| 	public Sid getSid() { | ||||
| 		return sid; | ||||
| 	} | ||||
| 	 | ||||
| 	void setPermission(Permission permission) { | ||||
| 		Assert.notNull(permission, "Permission required"); | ||||
| 		this.permission = permission; | ||||
| 		this.aceDirty = true; | ||||
| 	} | ||||
| 	 | ||||
| 	void setId(Serializable id) { | ||||
| 		this.id = id; | ||||
| 	} | ||||
| 	 | ||||
| 	public boolean isAuditFailure() { | ||||
| 		return auditFailure; | ||||
| 	} | ||||
| 
 | ||||
| 	void setAuditFailure(boolean auditFailure) { | ||||
| 		this.auditFailure = auditFailure; | ||||
| 		this.aceDirty = true; | ||||
| 	} | ||||
| 
 | ||||
| 	public boolean isAuditSuccess() { | ||||
| 		return auditSuccess; | ||||
| 	} | ||||
| 
 | ||||
| 	void setAuditSuccess(boolean auditSuccess) { | ||||
| 		this.auditSuccess = auditSuccess; | ||||
| 		this.aceDirty = true; | ||||
| 	} | ||||
| 	 | ||||
| 	public boolean isAceDirty() { | ||||
| 		return aceDirty; | ||||
| 	} | ||||
| 	 | ||||
| 
 | ||||
| 	public String toString() { | ||||
| 		StringBuffer sb = new StringBuffer(); | ||||
| 		sb.append("AccessControlEntryImpl["); | ||||
| 		sb.append("id: ").append(this.id).append("; "); | ||||
| 		sb.append("granting: ").append(this.granting).append("; "); | ||||
| 		sb.append("sid: ").append(this.sid).append("; "); | ||||
| 		sb.append("permission: ").append(this.permission); | ||||
| 		sb.append("]"); | ||||
| 		return sb.toString(); | ||||
| 	}	 | ||||
| } | ||||
							
								
								
									
										500
									
								
								sandbox/src/main/java/org/acegisecurity/acls/domain/AclImpl.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										500
									
								
								sandbox/src/main/java/org/acegisecurity/acls/domain/AclImpl.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,500 @@ | ||||
| /* 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.acls.domain; | ||||
| 
 | ||||
| import java.io.Serializable; | ||||
| import java.util.Iterator; | ||||
| import java.util.List; | ||||
| import java.util.Vector; | ||||
| 
 | ||||
| import org.acegisecurity.AccessDeniedException; | ||||
| import org.acegisecurity.Authentication; | ||||
| import org.acegisecurity.GrantedAuthority; | ||||
| import org.acegisecurity.acls.AccessControlEntry; | ||||
| import org.acegisecurity.acls.Acl; | ||||
| import org.acegisecurity.acls.AuditableAcl; | ||||
| import org.acegisecurity.acls.MutableAcl; | ||||
| import org.acegisecurity.acls.NotFoundException; | ||||
| import org.acegisecurity.acls.OwnershipAcl; | ||||
| import org.acegisecurity.acls.Permission; | ||||
| import org.acegisecurity.acls.UnloadedSidException; | ||||
| import org.acegisecurity.acls.objectidentity.ObjectIdentity; | ||||
| import org.acegisecurity.acls.sid.PrincipalSid; | ||||
| import org.acegisecurity.acls.sid.Sid; | ||||
| import org.acegisecurity.context.SecurityContextHolder; | ||||
| import org.springframework.util.Assert; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Base implementation of <code>Acl</code>. | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id | ||||
|  */ | ||||
| public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl { | ||||
|     //~ Instance fields ======================================================== | ||||
| 	private static final int CHANGE_OWNERSHIP = 0; | ||||
| 	private static final int CHANGE_AUDITING = 1; | ||||
| 	private static final int CHANGE_GENERAL = 2; | ||||
| 	 | ||||
| 	private GrantedAuthority gaTakeOwnership; | ||||
| 	private GrantedAuthority gaModifyAuditing; | ||||
| 	private GrantedAuthority gaGeneralChanges; | ||||
| 	 | ||||
| 	private Acl parentAcl; | ||||
|     private AuditLogger auditLogger = new ConsoleAuditLogger(); // AuditableAcl | ||||
|     private List aces = new Vector(); | ||||
|     private List deletedAces = new Vector(); | ||||
|     private Long id; | ||||
|     private ObjectIdentity objectIdentity; | ||||
|     private Sid owner; // OwnershipAcl | ||||
|     private boolean entriesInheriting = false; | ||||
|     private Sid[] loadedSids = null; // includes all SIDs the WHERE clause covered, even if there was no ACE for a SID | ||||
|     private boolean aclDirty = false; // for snapshot detection | ||||
|     private boolean addedAces = false; // for snapshot detection | ||||
|     private boolean updatedAces = false; // for snapshot detection | ||||
| 
 | ||||
|     //~ Constructors =========================================================== | ||||
| 
 | ||||
|     /** | ||||
|      * Minimal constructor, which should be used {@link | ||||
|      * org.acegisecurity.acls.MutableAclService#createAcl(ObjectIdentity)}. | ||||
|      * | ||||
|      * @param objectIdentity the object identity this ACL relates to (required) | ||||
|      * @param id the primary key assigned to this ACL (required) | ||||
|      * @param auths an array of <code>GrantedAuthority</code>s that have | ||||
|      * special permissions (index 0 is the authority needed to change | ||||
|      * ownership, index 1 is the authority needed to modify auditing details, | ||||
|      * index 2 is the authority needed to change other ACL and ACE details) (required) | ||||
|      */ | ||||
|     public AclImpl(ObjectIdentity objectIdentity, Long id, GrantedAuthority[] auths) { | ||||
|     	Assert.notNull(objectIdentity, "Object Identity required"); | ||||
|         Assert.notNull(id, "Id required"); | ||||
|         this.objectIdentity = objectIdentity; | ||||
|         this.id = id; | ||||
|         this.setAuthorities(auths); | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Change the special adminstrative permissions honoured by this | ||||
|      * object. | ||||
|      *  | ||||
|      * <p> | ||||
|      * Normally a principal must be the owner of the ACL in order to | ||||
|      * make most changes. The authorities passed to this method provide | ||||
|      * a way for non-owners to modify the ACL (and indeed modify audit | ||||
|      * parameters, which are not available to ACL owners). | ||||
|      * | ||||
|      * @param auths an array of <code>GrantedAuthority</code>s that have | ||||
|      * administrative permissions (index 0 is the authority needed to change | ||||
|      * ownership, index 1 is the authority needed to modify auditing details, | ||||
|      * index 2 is the authority needed to change other ACL and ACE details) | ||||
|      */ | ||||
|     private void setAuthorities(GrantedAuthority[] auths) { | ||||
|         Assert.notEmpty(auths, "GrantedAuthority[] with three elements required"); | ||||
|         Assert.isTrue(auths.length == 3, "GrantedAuthority[] with three elements required"); | ||||
|     	this.gaTakeOwnership = auths[0]; | ||||
|     	this.gaModifyAuditing = auths[1]; | ||||
|     	this.gaGeneralChanges = auths[2]; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Full constructor, which should be used by persistence tools that do not | ||||
|      * provide field-level access features. | ||||
|      * | ||||
|      * @param objectIdentity the object identity this ACL relates to (required) | ||||
|      * @param id the primary key assigned to this ACL (required) | ||||
|      * @param auths an array of <code>GrantedAuthority</code>s that have | ||||
|      * special permissions (index 0 is the authority needed to change | ||||
|      * ownership, index 1 is the authority needed to modify auditing details, | ||||
|      * index 2 is the authority needed to change other ACL and ACE details) (required) | ||||
|      * @param parentAcl the parent (may be <code>null</code>) | ||||
|      * @param loadedSids the loaded SIDs if only a subset were loaded (may be | ||||
|      *        <code>null</code>) | ||||
|      * @param entriesInheriting if ACEs from the parent should inherit into | ||||
|      *        this ACL | ||||
|      * @param owner the owner (required) | ||||
|      */ | ||||
|     public AclImpl(ObjectIdentity objectIdentity, Long id, Acl parentAcl, GrantedAuthority[] auths, | ||||
|         Sid[] loadedSids, boolean entriesInheriting, Sid owner) { | ||||
|         Assert.notNull(objectIdentity, "Object Identity required"); | ||||
|         Assert.notNull(id, "Id required"); | ||||
|         Assert.notNull(owner, "Owner required"); | ||||
|         this.objectIdentity = objectIdentity; | ||||
|         this.id = id; | ||||
|         setAuthorities(auths); | ||||
|         this.parentAcl = parentAcl; // may be null | ||||
|         this.loadedSids = loadedSids; // may be null | ||||
|         this.entriesInheriting = entriesInheriting; | ||||
|         this.owner = owner; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Private no-argument constructor for use by reflection-based persistence | ||||
|      * tools along with field-level access. | ||||
|      */ | ||||
|     private AclImpl() {} | ||||
| 
 | ||||
|     //~ Methods ================================================================ | ||||
|      | ||||
|     protected void securityCheck(int changeType) { | ||||
|     	if (SecurityContextHolder.getContext() == null || SecurityContextHolder.getContext().getAuthentication() == null || !SecurityContextHolder.getContext().getAuthentication().isAuthenticated()) { | ||||
|     		throw new AccessDeniedException("Authenticated principal required to operate with ACLs"); | ||||
|     	} | ||||
|     	 | ||||
|     	Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); | ||||
|     	// Check if authorized by virtue of ACL ownership | ||||
|     	Sid currentUser = new PrincipalSid(authentication); | ||||
|     	if (currentUser.equals(this.owner) && (changeType == CHANGE_GENERAL || changeType == CHANGE_OWNERSHIP)) { | ||||
|     		return; | ||||
|     	} | ||||
|     	 | ||||
|     	// Not authorized by ACL ownership; try via adminstrative permissions | ||||
|     	GrantedAuthority requiredAuthority = null; | ||||
|     	if (changeType == CHANGE_AUDITING) { | ||||
|     		requiredAuthority = this.gaModifyAuditing; | ||||
|     	} else if (changeType == CHANGE_GENERAL) { | ||||
|     		requiredAuthority = this.gaGeneralChanges; | ||||
|     	} else if (changeType == CHANGE_OWNERSHIP) { | ||||
|     		requiredAuthority = this.gaTakeOwnership; | ||||
|     	} else { | ||||
|     		throw new IllegalArgumentException("Unknown change type"); | ||||
|     	} | ||||
|     	 | ||||
|     	// Iterate this principal's authorities to determine right | ||||
|     	GrantedAuthority[] auths = authentication.getAuthorities(); | ||||
|     	for (int i = 0; i < auths.length; i++) { | ||||
|     		if (requiredAuthority.equals(auths[i])) { | ||||
|     			return; | ||||
|     		} | ||||
|     	} | ||||
|     	 | ||||
|     	throw new AccessDeniedException("Principal does not have required ACL permissions to perform requested operation"); | ||||
|     } | ||||
| 
 | ||||
|     public void deleteAce(Long aceId) throws NotFoundException { | ||||
|         securityCheck(CHANGE_GENERAL); | ||||
|     	 | ||||
|     	synchronized (aces) { | ||||
|         	int offset = findAceOffset(aceId); | ||||
| 
 | ||||
|             if (offset == 1) { | ||||
|                 throw new NotFoundException("Requested ACE ID not found"); | ||||
|             } | ||||
| 
 | ||||
|             aces.remove(offset); | ||||
|             deletedAces.add(aceId); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private int findAceOffset(Long aceId) { | ||||
|         Assert.notNull(aceId, "ACE ID is required"); | ||||
| 
 | ||||
|         synchronized (aces) { | ||||
|             for (int i = 0; i < aces.size(); i++) { | ||||
|                 AccessControlEntry ace = (AccessControlEntry) aces.get(i); | ||||
| 
 | ||||
|                 if (ace.getId().equals(aceId)) { | ||||
|                     return i; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     public AccessControlEntry[] getEntries() { | ||||
|         // Can safely return AccessControlEntry directly, as they're immutable | ||||
|         return (AccessControlEntry[]) aces.toArray(new AccessControlEntry[] {}); | ||||
|     } | ||||
| 
 | ||||
| 	public void setEntriesInheriting(boolean entriesInheriting) { | ||||
|         securityCheck(CHANGE_GENERAL); | ||||
|         this.entriesInheriting = entriesInheriting; | ||||
|         this.aclDirty = true; | ||||
|     } | ||||
| 
 | ||||
|     public Serializable getId() { | ||||
|         return this.id; | ||||
|     } | ||||
| 
 | ||||
|     public ObjectIdentity getObjectIdentity() { | ||||
|         return objectIdentity; | ||||
|     } | ||||
| 
 | ||||
|     public Sid getOwner() { | ||||
|         return this.owner; | ||||
|     } | ||||
| 
 | ||||
|     public Acl getParentAcl() { | ||||
|         return parentAcl; | ||||
|     } | ||||
| 
 | ||||
|     public void insertAce(Long afterAceId, Permission permission, Sid sid, | ||||
|         boolean granting) throws NotFoundException { | ||||
|         securityCheck(CHANGE_GENERAL); | ||||
|         Assert.notNull(permission, "Permission required"); | ||||
|         Assert.notNull(sid, "Sid required"); | ||||
| 
 | ||||
|         AccessControlEntryImpl ace = new AccessControlEntryImpl(null, this, | ||||
|                 sid, permission, granting, false, false); | ||||
| 
 | ||||
|         synchronized (aces) { | ||||
|             if (afterAceId != null) { | ||||
|                 int offset = findAceOffset(afterAceId); | ||||
| 
 | ||||
|                 if (offset == -1) { | ||||
|                     throw new NotFoundException("Requested ACE ID not found"); | ||||
|                 } | ||||
| 
 | ||||
|                 aces.add(offset + 1, ace); | ||||
|             } else { | ||||
|                 aces.add(ace); | ||||
|             } | ||||
|        	 | ||||
|         } | ||||
| 
 | ||||
|         this.addedAces = true; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isSidLoaded(Sid[] sids) { | ||||
|         // If loadedSides is null, this indicates all SIDs were loaded | ||||
|     	// Also return true if the caller didn't specify a SID to find | ||||
|         if (this.loadedSids == null || sids == null || sids.length == 0) { | ||||
|         	return true; | ||||
|         } | ||||
|          | ||||
|         // This ACL applies to a SID subset. Iterate to check it applies | ||||
|         for (int i = 0; i < sids.length; i++) { | ||||
|         	boolean found = false; | ||||
|         	for (int y = 0; y < this.loadedSids.length; y++) { | ||||
|         		if (sids[i].equals(this.loadedSids[y])) { | ||||
|         			// this SID is OK | ||||
|         			found = true; | ||||
|         			break; // out of loadedSids for loop | ||||
|         		} | ||||
|         	} | ||||
|     		if (!found) { | ||||
|     			return false; | ||||
|     		} | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isEntriesInheriting() { | ||||
|         return entriesInheriting; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Determines authorization.  The order of the <code>permission</code> and | ||||
|      * <code>sid</code> arguments is <em>extremely important</em>! The method | ||||
|      * will iterate through each of the <code>permission</code>s in the order | ||||
|      * specified. For each iteration, all of the <code>sid</code>s will be | ||||
|      * considered, again in the order they are presented. The iteration of | ||||
|      * each <code>permission:sid</code> combination will then inspect the ACEs | ||||
|      * in the order they appear in the ACL. When the <em>first full match</em> | ||||
|      * is found (ie an ACE that has the SID currently being searched for and | ||||
|      * the exact permission bit mask being search for), the grant or deny flag | ||||
|      * for that ACE will prevail. If the ACE specifies to grant access, the | ||||
|      * method will return <code>true</code>. If the ACE specifies to deny | ||||
|      * access, the loop will stop and the next <code>permission</code> | ||||
|      * iteration will be performed. If each permission indicates to deny | ||||
|      * access, the first deny ACE found will be considered the reason for the | ||||
|      * failure (as it was the first match found, and is therefore the one most | ||||
|      * logically requiring changes - although not always). If absolutely no | ||||
|      * matching ACE was found at all for any permission, the parent ACL will | ||||
|      * be tried (provided that there is a parent and {@link | ||||
|      * #isEntriesInheriting()} is <code>true</code>. The parent ACL will also | ||||
|      * scan its parent and so on. If ultimately no matching ACE is found, a | ||||
|      * <code>NotFoundException</code> will be thrown and the caller will need | ||||
|      * to decide how to handle the permission check. Similarly, if any of the | ||||
|      * passed SIDs were not loaded by the ACL, the | ||||
|      * <code>UnloadedSidException</code> will be thrown. | ||||
|      * | ||||
|      * @param permission the exact permissions to scan for (order is important) | ||||
|      * @param sids the exact SIDs to scan for (order is important) | ||||
|      * @param administrativeMode if <code>true</code> denotes the query is for | ||||
|      *        administrative purposes and no auditing will be undertaken | ||||
|      * | ||||
|      * @return <code>true</code> if one of the permissions has been granted, | ||||
|      *         <code>false</code> if one of the permissions has been | ||||
|      *         specifically revoked | ||||
|      * | ||||
|      * @throws NotFoundException if an exact ACE for one of the permission bit | ||||
|      *         masks and SID combination could not be found | ||||
|      * @throws UnloadedSidException if the passed SIDs are unknown to this ACL | ||||
|      *         because the ACL was only loaded for a subset of SIDs | ||||
|      */ | ||||
|     public boolean isGranted(Permission[] permission, Sid[] sids, boolean administrativeMode) | ||||
|         throws NotFoundException, UnloadedSidException { | ||||
|         Assert.notEmpty(permission, "Permissions required"); | ||||
|         Assert.notEmpty(sids, "SIDs required"); | ||||
| 
 | ||||
|         if (!this.isSidLoaded(sids)) { | ||||
|             throw new UnloadedSidException("ACL was not loaded for one or more SID"); | ||||
|         } | ||||
|          | ||||
|         AccessControlEntry firstRejection = null; | ||||
| 
 | ||||
|         for (int i = 0; i < permission.length; i++) { | ||||
|             for (int x = 0; x < sids.length; x++) { | ||||
|                 // Attempt to find exact match for this permission mask and SID | ||||
|                 Iterator acesIterator = aces.iterator(); | ||||
|                 boolean scanNextSid = true; | ||||
| 
 | ||||
|                 while (acesIterator.hasNext()) { | ||||
|                     AccessControlEntry ace = (AccessControlEntry) acesIterator | ||||
|                         .next(); | ||||
| 
 | ||||
|                     if ((ace.getPermission().getMask() == permission[i].getMask()) | ||||
|                         && ace.getSid().equals(sids[x])) { | ||||
|                         // Found a matching ACE, so its authorization decision will prevail | ||||
|                         if (ace.isGranting()) { | ||||
|                             // Success | ||||
|                         	if (!administrativeMode) { | ||||
|                                 auditLogger.logIfNeeded(true, ace); | ||||
|                         	} | ||||
| 
 | ||||
|                             return true; | ||||
|                         } else { | ||||
|                             // Failure for this permission, so stop search | ||||
|                             // We will see if they have a different permission | ||||
|                             // (this permission is 100% rejected for this SID) | ||||
|                             if (firstRejection == null) { | ||||
|                                 // Store first rejection for auditing reasons | ||||
|                                 firstRejection = ace; | ||||
|                             } | ||||
| 
 | ||||
|                             scanNextSid = false; // helps break the loop | ||||
| 
 | ||||
|                             break; // exit "aceIterator" while loop | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (!scanNextSid) { | ||||
|                     break; // exit SID for loop (now try next permission) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (firstRejection != null) { | ||||
|             // We found an ACE to reject the request at this point, as no | ||||
|             // other ACEs were found that granted a different permission | ||||
|              | ||||
|         	if (!administrativeMode) { | ||||
|             	auditLogger.logIfNeeded(false, firstRejection); | ||||
|         	} | ||||
| 
 | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         // No matches have been found so far | ||||
|         if (isEntriesInheriting() && (parentAcl != null)) { | ||||
|             // We have a parent, so let them try to find a matching ACE | ||||
|         	return parentAcl.isGranted(permission, sids, false); | ||||
|         } else { | ||||
|             // We either have no parent, or we're the uppermost parent | ||||
|             throw new NotFoundException( | ||||
|                 "Unable to locate a matching ACE for passed permissions and SIDs"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void setOwner(Sid newOwner) { | ||||
|         securityCheck(CHANGE_OWNERSHIP); | ||||
|         Assert.notNull(newOwner, "Owner required"); | ||||
|         this.owner = newOwner; | ||||
|         this.aclDirty = true; | ||||
|     } | ||||
| 
 | ||||
|     public void setParent(MutableAcl newParent) { | ||||
|         securityCheck(CHANGE_GENERAL); | ||||
|         Assert.notNull(newParent, "New Parent required"); | ||||
|         this.parentAcl = newParent; | ||||
|         this.aclDirty = true; | ||||
|     } | ||||
| 
 | ||||
|     public void updateAce(Long aceId, Permission permission) | ||||
|         throws NotFoundException { | ||||
|         securityCheck(CHANGE_GENERAL); | ||||
|         synchronized (aces) { | ||||
|         	int offset = findAceOffset(aceId); | ||||
| 
 | ||||
|             if (offset == 1) { | ||||
|                 throw new NotFoundException("Requested ACE ID not found"); | ||||
|             } | ||||
| 
 | ||||
|             AccessControlEntryImpl ace = (AccessControlEntryImpl) aces.get(offset); | ||||
|             ace.setPermission(permission); | ||||
|         } | ||||
|          | ||||
|         this.updatedAces = true; | ||||
|     } | ||||
| 
 | ||||
|     public void updateAuditing(Long aceId, boolean auditSuccess, | ||||
|         boolean auditFailure) { | ||||
|         securityCheck(CHANGE_AUDITING); | ||||
|     	 | ||||
|     	synchronized (aces) { | ||||
|             int offset = findAceOffset(aceId); | ||||
| 
 | ||||
|             if (offset == 1) { | ||||
|                 throw new NotFoundException("Requested ACE ID not found"); | ||||
|             } | ||||
| 
 | ||||
|             AccessControlEntryImpl ace = (AccessControlEntryImpl) aces.get(offset); | ||||
|             ace.setAuditSuccess(auditSuccess); | ||||
|             ace.setAuditFailure(auditFailure); | ||||
| 		} | ||||
|         this.updatedAces = true; | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Clears the dirty flags on the <code>Acl</code>, but not any | ||||
|      * associated ACEs. | ||||
|      */ | ||||
|     public void clearDirtyFlags() { | ||||
|         this.aclDirty = false; | ||||
|         this.addedAces = false; | ||||
|         this.updatedAces = false; | ||||
|     } | ||||
| 
 | ||||
| 	public boolean isAclDirty() { | ||||
| 		return aclDirty; | ||||
| 	} | ||||
| 
 | ||||
| 	public String toString() { | ||||
| 		StringBuffer sb = new StringBuffer(); | ||||
| 		sb.append("AclImpl["); | ||||
| 		sb.append("id: ").append(this.id).append("; "); | ||||
| 		sb.append("objectIdentity: ").append(this.objectIdentity).append("; "); | ||||
| 		sb.append("owner: ").append(this.owner).append("; "); | ||||
| 		Iterator iterator = this.aces.iterator(); | ||||
| 		int count = 0; | ||||
| 		while (iterator.hasNext()) { | ||||
| 			count++; | ||||
| 			if (count == 1) { | ||||
| 				sb.append("\r\n"); | ||||
| 			} | ||||
| 			sb.append(iterator.next().toString()).append("\r\n"); | ||||
| 		} | ||||
| 		sb.append("inheriting: ").append(this.entriesInheriting).append("; "); | ||||
| 		sb.append("parent: ").append(this.parentAcl == null ? "Null" : this.parentAcl.getObjectIdentity()); | ||||
| 		sb.append("]"); | ||||
| 		return sb.toString(); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,14 @@ | ||||
| package org.acegisecurity.acls.domain; | ||||
| 
 | ||||
| import org.acegisecurity.acls.AccessControlEntry; | ||||
| 
 | ||||
| /** | ||||
|  * Used by <code>AclImpl</code> to log audit events. | ||||
|  *  | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  * | ||||
|  */ | ||||
| public interface AuditLogger { | ||||
| 	public void logIfNeeded(boolean granted, AccessControlEntry ace); | ||||
| } | ||||
| @ -0,0 +1,66 @@ | ||||
| package org.acegisecurity.acls.domain; | ||||
| 
 | ||||
| import org.acegisecurity.acls.AclFormattingUtils; | ||||
| import org.acegisecurity.acls.Permission; | ||||
| 
 | ||||
| public class BasePermission implements Permission { | ||||
| 	public static final Permission READ = new BasePermission(1<<0, 'R'); // 1 | ||||
| 	public static final Permission WRITE = new BasePermission(1<<1, 'W'); // 2 | ||||
| 	public static final Permission CREATE = new BasePermission(1<<2, 'C'); // 4 | ||||
| 	public static final Permission ADMINISTRATION = new BasePermission(1<<3, 'A'); // 8 | ||||
| 	 | ||||
| 	private int mask; | ||||
| 	private char code; | ||||
| 	 | ||||
| 	private BasePermission(int mask, char code) { | ||||
| 		this.mask = mask; | ||||
| 		this.code = code; | ||||
| 	} | ||||
| 	 | ||||
| 	public boolean equals(Object arg0) { | ||||
| 		if (!(arg0 instanceof BasePermission)) { | ||||
| 			return false; | ||||
| 		} | ||||
| 		BasePermission rhs = (BasePermission) arg0; | ||||
| 		return (this.mask == rhs.getMask()); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Dynamically creates a <code>CumulativePermission</code> | ||||
| 	 * representing the active bits in the passed mask. | ||||
| 	 * NB: Only uses <code>BasePermission</code>! | ||||
| 	 *  | ||||
| 	 * @param mask to review | ||||
| 	 */ | ||||
| 	public static Permission buildFromMask(int mask) { | ||||
| 		CumulativePermission permission = new CumulativePermission(); | ||||
| 		 | ||||
| 		// TODO: Write the rest of it to iterate through the 32 bits and instantiate BasePermissions | ||||
| 		if (mask == 1) { | ||||
| 			permission.set(READ); | ||||
| 		} | ||||
| 		if (mask == 2) { | ||||
| 			permission.set(WRITE); | ||||
| 		} | ||||
| 		if (mask == 4) { | ||||
| 			permission.set(CREATE); | ||||
| 		} | ||||
| 		if (mask == 8) { | ||||
| 			permission.set(ADMINISTRATION); | ||||
| 		} | ||||
| 		return permission; | ||||
| 	} | ||||
| 	 | ||||
| 	public int getMask() { | ||||
| 		return mask; | ||||
| 	} | ||||
| 
 | ||||
| 	public String toString() { | ||||
| 		return "BasePermission[" + getPattern() + "=" + mask + "]"; | ||||
| 	} | ||||
| 
 | ||||
| 	public String getPattern() { | ||||
| 		return AclFormattingUtils.printBinary(mask, code); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,19 @@ | ||||
| package org.acegisecurity.acls.domain; | ||||
| 
 | ||||
| import org.acegisecurity.acls.AccessControlEntry; | ||||
| import org.acegisecurity.acls.AuditableAccessControlEntry; | ||||
| import org.springframework.util.Assert; | ||||
| 
 | ||||
| public class ConsoleAuditLogger implements AuditLogger { | ||||
| 	public void logIfNeeded(boolean granted, AccessControlEntry ace) { | ||||
| 		Assert.notNull(ace, "AccessControlEntry required"); | ||||
| 		if (ace instanceof AuditableAccessControlEntry) { | ||||
| 			AuditableAccessControlEntry auditableAce = (AuditableAccessControlEntry) ace; | ||||
| 			if (granted && auditableAce.isAuditSuccess()) { | ||||
| 				System.out.println("GRANTED due to ACE: " + ace); | ||||
| 			} else if (!granted && auditableAce.isAuditFailure()) { | ||||
| 				System.out.println("DENIED due to ACE: " + ace); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -0,0 +1,84 @@ | ||||
| /* 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.acls.domain; | ||||
| 
 | ||||
| import org.acegisecurity.acls.AclFormattingUtils; | ||||
| import org.acegisecurity.acls.Permission; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Represents a <code>Permission</code> that is constructed at runtime from | ||||
|  * other permissions. | ||||
|  *  | ||||
|  * <p> | ||||
|  * Methods return <code>this</code>, in order to facilitate method chaining. | ||||
|  * </p> | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public class CumulativePermission implements Permission { | ||||
|     //~ Instance fields ======================================================== | ||||
| 
 | ||||
|     private String pattern = THIRTY_TWO_RESERVED_OFF; | ||||
|     private int mask = 0; | ||||
| 
 | ||||
|     //~ Methods ================================================================ | ||||
| 
 | ||||
|     public CumulativePermission clear(Permission permission) { | ||||
|         this.mask &= ~permission.getMask(); | ||||
|         this.pattern = AclFormattingUtils.demergePatterns(this.pattern, | ||||
|                 permission.getPattern()); | ||||
| 
 | ||||
|         return this; | ||||
|     } | ||||
|      | ||||
| 	public boolean equals(Object arg0) { | ||||
| 		if (!(arg0 instanceof CumulativePermission)) { | ||||
| 			return false; | ||||
| 		} | ||||
| 		CumulativePermission rhs = (CumulativePermission) arg0; | ||||
| 		return (this.mask == rhs.getMask()); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
|     public CumulativePermission clear() { | ||||
|         this.mask = 0; | ||||
|         this.pattern = THIRTY_TWO_RESERVED_OFF; | ||||
| 
 | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     public int getMask() { | ||||
|         return this.mask; | ||||
|     } | ||||
| 
 | ||||
|     public String getPattern() { | ||||
|         return this.pattern; | ||||
|     } | ||||
| 
 | ||||
|     public CumulativePermission set(Permission permission) { | ||||
|         this.mask |= permission.getMask(); | ||||
|         this.pattern = AclFormattingUtils.mergePatterns(this.pattern, | ||||
|                 permission.getPattern()); | ||||
| 
 | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     public String toString() { | ||||
|         return "CumulativePermission[" + pattern + "=" + this.mask + "]"; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,18 @@ | ||||
| package org.acegisecurity.acls.jdbc; | ||||
| 
 | ||||
| import org.acegisecurity.acls.domain.AclImpl; | ||||
| import org.acegisecurity.acls.objectidentity.ObjectIdentity; | ||||
| 
 | ||||
| /** | ||||
|  * A caching layer for {@link JdbcAclService}. | ||||
|  *  | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  * | ||||
|  */ | ||||
| public interface AclCache { | ||||
| 	public AclImpl getFromCache(ObjectIdentity objectIdentity); | ||||
| 	public AclImpl getFromCache(Long pk); | ||||
| 	public void putInCache(AclImpl acl); // should walk tree as well! | ||||
| 	public void evictFromCache(Long pk); | ||||
| } | ||||
| @ -0,0 +1,517 @@ | ||||
| /* 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.acls.jdbc; | ||||
| 
 | ||||
| import java.lang.reflect.Field; | ||||
| import java.sql.PreparedStatement; | ||||
| import java.sql.ResultSet; | ||||
| import java.sql.SQLException; | ||||
| import java.util.HashMap; | ||||
| import java.util.HashSet; | ||||
| import java.util.Iterator; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
| 
 | ||||
| import javax.sql.DataSource; | ||||
| 
 | ||||
| import org.acegisecurity.GrantedAuthority; | ||||
| import org.acegisecurity.acls.AccessControlEntry; | ||||
| import org.acegisecurity.acls.Acl; | ||||
| import org.acegisecurity.acls.NotFoundException; | ||||
| import org.acegisecurity.acls.Permission; | ||||
| import org.acegisecurity.acls.UnloadedSidException; | ||||
| import org.acegisecurity.acls.domain.AccessControlEntryImpl; | ||||
| import org.acegisecurity.acls.domain.AclImpl; | ||||
| import org.acegisecurity.acls.domain.BasePermission; | ||||
| import org.acegisecurity.acls.objectidentity.ObjectIdentity; | ||||
| import org.acegisecurity.acls.objectidentity.ObjectIdentityImpl; | ||||
| import org.acegisecurity.acls.sid.GrantedAuthoritySid; | ||||
| import org.acegisecurity.acls.sid.PrincipalSid; | ||||
| import org.acegisecurity.acls.sid.Sid; | ||||
| import org.springframework.dao.DataAccessException; | ||||
| import org.springframework.jdbc.core.JdbcTemplate; | ||||
| import org.springframework.jdbc.core.PreparedStatementSetter; | ||||
| import org.springframework.jdbc.core.ResultSetExtractor; | ||||
| import org.springframework.util.Assert; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Performs lookups in a manner that is compatible with ANSI SQL. | ||||
|  *  | ||||
|  * <p> | ||||
|  * NB: This implementation does attempt to provide reasonably optimised lookups | ||||
|  * - within the constraints of a normalised database and standard ANSI SQL | ||||
|  * features. If you are willing to sacrifice either of these constraints (eg | ||||
|  * use a particular database feature such as hierarchical queries or | ||||
|  * materalized views, or reduce normalisation) you are likely to achieve better | ||||
|  * performance. In such situations you will need to provide your own custom | ||||
|  * <code>LookupStrategy</code>. This class does not support subclassing, as | ||||
|  * it is likely to change in future releases and therefore subclassing is | ||||
|  * unsupported. | ||||
|  * </p> | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public final class BasicLookupStrategy implements LookupStrategy { | ||||
|      | ||||
| 	private int batchSize = 50; | ||||
|     private AclCache aclCache; | ||||
|     private JdbcTemplate jdbcTemplate; | ||||
|     private GrantedAuthority[] auths; | ||||
| 
 | ||||
|     //~ Constructors =========================================================== | ||||
| 
 | ||||
|     /** | ||||
|      * Constructor accepting mandatory arguments | ||||
|      * | ||||
|      * @param dataSource to access the database | ||||
|      * @param aclCache the cache where fully-loaded elements can be stored | ||||
|      * @param auths as per the format defined by {@link | ||||
|      *        AclImpl#setAuthorities(GrantedAuthority[])} for instances | ||||
|      *        created by this implementation | ||||
|      */ | ||||
|     public BasicLookupStrategy(DataSource dataSource, AclCache aclCache, | ||||
|         GrantedAuthority[] auths) { | ||||
|         Assert.notNull(dataSource, "DataSource required"); | ||||
|         Assert.notNull(aclCache, "AclCache required"); | ||||
|         Assert.notEmpty(auths, "GrantedAuthority[] with three elements required"); | ||||
|         Assert.isTrue(auths.length == 3, | ||||
|             "GrantedAuthority[] with three elements required"); | ||||
|         this.jdbcTemplate = new JdbcTemplate(dataSource); | ||||
|         this.aclCache = aclCache; | ||||
|         this.auths = auths; | ||||
|     } | ||||
| 
 | ||||
|     //~ Methods ================================================================ | ||||
| 
 | ||||
|     public void setBatchSize(int batchSize) { | ||||
| 		this.batchSize = batchSize; | ||||
| 	} | ||||
| 
 | ||||
|     /** | ||||
|      * The main method. | ||||
|      *  | ||||
|      * <p> | ||||
|      * WARNING: This implementation completely disregards the "sids" argument! | ||||
|      * Every item in the cache is expected to contain all SIDs. | ||||
|      * | ||||
|      * <p> | ||||
|      * The implementation works in batch sizes specfied by {@link #batchSize}. | ||||
|      * | ||||
|      */ | ||||
|     public Map readAclsById(ObjectIdentity[] objects, Sid[] sids) | ||||
|         throws NotFoundException { | ||||
|         Assert.isTrue(batchSize >= 1, "BatchSize must be >= 1"); | ||||
|     	Assert.notEmpty(objects, "Objects to lookup required"); | ||||
| 
 | ||||
|         Map result = new HashMap(); // contains FULLY loaded Acl objects | ||||
| 
 | ||||
|         Set currentBatchToLoad = new HashSet(); // contains ObjectIdentitys | ||||
| 
 | ||||
|         for (int i = 0; i < objects.length; i++) { | ||||
|             // Check we don't already have this ACL in the results | ||||
|             if (result.containsKey(objects[i])) { | ||||
|                 continue; // already in results, so move to next element | ||||
|             } | ||||
| 
 | ||||
|             // Check cache for the present ACL entry | ||||
|             Acl acl = aclCache.getFromCache(objects[i]); | ||||
| 
 | ||||
|             // Ensure any cached element supports all the requested SIDs | ||||
|             // (they should always, as our base impl doesn't filter on SID) | ||||
|             if (acl != null) { | ||||
|                 if (acl.isSidLoaded(sids)) { | ||||
|                     result.put(acl.getObjectIdentity(), acl); | ||||
|                     continue; // now in results, so move to next element | ||||
|                 } else { | ||||
|                     throw new IllegalStateException( | ||||
|                         "Error: SID-filtered element detected when implementation does not perform SID filtering - have you added something to the cache manually?"); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // To get this far, we have no choice but to retrieve it via JDBC | ||||
|             // (although we don't do it until we get a batch of them to load) | ||||
|             currentBatchToLoad.add(objects[i]); | ||||
| 
 | ||||
|             // Is it time to load from JDBC the currentBatchToLoad? | ||||
|             if ((currentBatchToLoad.size() == this.batchSize) || (i+1 == objects.length)) { | ||||
|                 Map loadedBatch = lookupObjectIdentities((ObjectIdentity[]) currentBatchToLoad | ||||
|                 		.toArray(new ObjectIdentity[] {})); | ||||
| 
 | ||||
|                 // Add loaded batch (all elements 100% initialized) to results | ||||
|                 result.putAll(loadedBatch); | ||||
| 
 | ||||
|                 // Add the loaded batch to the cache | ||||
|                 Iterator loadedAclIterator = loadedBatch.values().iterator(); | ||||
| 
 | ||||
|                 while (loadedAclIterator.hasNext()) { | ||||
|                     aclCache.putInCache((AclImpl) loadedAclIterator.next()); | ||||
|                 } | ||||
|                  | ||||
|                 currentBatchToLoad.clear(); | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         // TODO: Now we're done, check every requested object identity was found (throw NotFoundException if needed) | ||||
| 
 | ||||
|         return result; | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Looks up a batch of <code>ObjectIdentity</code>s directly from the | ||||
|      * database. | ||||
|      *  | ||||
|      * <p> | ||||
|      * The caller is responsible for optimization issues, such as selecting the | ||||
|      * identities to lookup, ensuring the cache doesn't contain them already, | ||||
|      * and adding the returned elements to the cache etc. | ||||
|      * </p> | ||||
|      *  | ||||
|      * <p> | ||||
|      * This subclass is required to return fully valid <code>Acl</code>s, | ||||
|      * including properly-configured parent ACLs. | ||||
|      * </p> | ||||
|      */ | ||||
|     private Map lookupObjectIdentities(final ObjectIdentity[] objectIdentities) { | ||||
|         Assert.notEmpty(objectIdentities, "Must provide identities to lookup"); | ||||
| 
 | ||||
|         final Map acls = new HashMap(); // contains Acls with StubAclParents | ||||
| 
 | ||||
|         // Make the "acls" map contain all requested objectIdentities | ||||
|         // (including markers to each parent in the hierarchy) | ||||
|         String sql = computeRepeatingSql("(ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY = ? and ACL_CLASS.CLASS = ?)", objectIdentities.length); | ||||
|         System.out.println("Executing lookupObjectIdentities; length: " + objectIdentities.length); | ||||
|         jdbcTemplate.query(sql, | ||||
|             new PreparedStatementSetter() { | ||||
|                 public void setValues(PreparedStatement ps) | ||||
|                     throws SQLException { | ||||
|                     for (int i = 0; i < objectIdentities.length; i++) { | ||||
|                         // Determine prepared statement values for this iteration | ||||
|                         String javaType = objectIdentities[i].getJavaType().getName(); | ||||
|                         Assert.isInstanceOf(Long.class, objectIdentities[i].getIdentifier(),"This class requires ObjectIdentity.getIdentifier() to be a Long"); | ||||
|                         long id = ((Long) objectIdentities[i].getIdentifier()).longValue(); | ||||
|                          | ||||
|                         // Inject values | ||||
|                         ps.setLong((2 * i) + 1, id); | ||||
|                         ps.setString((2 * i) + 2, javaType); | ||||
|                     } | ||||
|                 } | ||||
|             }, new ProcessResultSet(acls)); | ||||
| 
 | ||||
|         // Finally, convert our "acls" containing StubAclParents into true Acls | ||||
|         Map resultMap = new HashMap(); | ||||
|         Iterator iter = acls.values().iterator(); | ||||
|         while (iter.hasNext()) { | ||||
|         	Acl inputAcl = (Acl) iter.next(); | ||||
|         	Assert.isInstanceOf(AclImpl.class, inputAcl, "Map should have contained an AclImpl"); | ||||
|         	Assert.isInstanceOf(Long.class, ((AclImpl)inputAcl).getId(), "Acl.getId() must be Long"); | ||||
|         	Acl result = convert(acls, (Long)((AclImpl)inputAcl).getId()); | ||||
|         	resultMap.put(result.getObjectIdentity(), result); | ||||
|         } | ||||
|          | ||||
|         return resultMap; | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Locates the primary key IDs specified in "findNow", adding AclImpl | ||||
|      * instances with StubAclParents to the "acls" Map. | ||||
|      * | ||||
|      * @param acls the AclImpls (with StubAclParents) | ||||
|      * @param findNow Long-based primary keys to retrieve | ||||
|      */ | ||||
|     private void lookupPrimaryKeys(final Map acls, final Set findNow) { | ||||
|         Assert.notNull(acls, "ACLs are required"); | ||||
|         Assert.notEmpty(findNow, "Items to find now required"); | ||||
|     	 | ||||
|         String sql = computeRepeatingSql("(ACL_OBJECT_IDENTITY.ID = ?)",findNow.size()); | ||||
|         System.out.println("Executing lookupPrimaryKeys; length: " + findNow.size()); | ||||
| 
 | ||||
|         jdbcTemplate.query(sql, | ||||
|             new PreparedStatementSetter() { | ||||
|                 public void setValues(PreparedStatement ps) throws SQLException { | ||||
|                     Iterator iter = findNow.iterator(); | ||||
|                     int i = 0; | ||||
|                     while (iter.hasNext()) { | ||||
|                     	i++; | ||||
|                         ps.setLong(i, ((Long)iter.next()).longValue()); | ||||
|                     } | ||||
|                 } | ||||
|             }, new ProcessResultSet(acls)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Accepts the current <code>ResultSet</code> row, and converts it into | ||||
|      * an <code>AclImpl</code> that contains a <code>StubAclParent</code> | ||||
|      *  | ||||
|      * @param acls the Map we should add the converted Acl to | ||||
|      * @param rs the ResultSet focused on a current row | ||||
|      * @throws SQLException if something goes wrong converting values | ||||
|      */ | ||||
|     private void convertCurrentResultIntoObject(Map acls, ResultSet rs) throws SQLException { | ||||
| 	    Long id = new Long(rs.getLong("ACL_ID")); | ||||
| 	 | ||||
| 	    // If we already have an ACL for this ID, just create the ACE | ||||
| 	    AclImpl acl = (AclImpl) acls.get(id); | ||||
| 	 | ||||
| 	    if (acl == null) { | ||||
| 	        // Make an AclImpl and pop it into the Map | ||||
| 	        ObjectIdentity objectIdentity = new ObjectIdentityImpl(rs.getString( | ||||
| 	                    "CLASS"), new Long(rs.getLong("OBJECT_ID_IDENTITY"))); | ||||
| 	 | ||||
| 	        Acl parentAcl = null; | ||||
| 	        long parentAclId = rs.getLong("PARENT_OBJECT"); | ||||
| 	 | ||||
| 	        if (parentAclId != 0) { | ||||
| 	            parentAcl = new StubAclParent(new Long(parentAclId)); | ||||
| 	        } | ||||
| 	 | ||||
| 	        boolean entriesInheriting = rs.getBoolean("ENTRIES_INHERITING"); | ||||
| 	        Sid owner; | ||||
| 	 | ||||
| 	        if (rs.getBoolean("ACL_PRINCIPAL")) { | ||||
| 	            owner = new PrincipalSid(rs.getString("ACL_SID")); | ||||
| 	        } else { | ||||
| 	            owner = new GrantedAuthoritySid(rs.getString("ACL_SID")); | ||||
| 	        } | ||||
| 	 | ||||
| 	        acl = new AclImpl(objectIdentity, id, parentAcl, auths, null, | ||||
| 	                entriesInheriting, owner); | ||||
| 	        acls.put(id, acl); | ||||
| 	    } | ||||
| 	 | ||||
| 	    // Add an extra ACE to the ACL (ORDER BY maintains the ACE list order) | ||||
| 	    Long aceId = new Long(rs.getLong("ACE_ID")); | ||||
| 	    Sid recipient; | ||||
| 	 | ||||
| 	    if (rs.getBoolean("ACE_PRINCIPAL")) { | ||||
| 	        recipient = new PrincipalSid(rs.getString("ACE_SID")); | ||||
| 	    } else { | ||||
| 	        recipient = new GrantedAuthoritySid(rs.getString("ACE_SID")); | ||||
| 	    } | ||||
| 	 | ||||
| 	    Permission permission = BasePermission.buildFromMask(rs.getInt("MASK")); | ||||
| 	    boolean granting = rs.getBoolean("GRANTING"); | ||||
| 	    boolean auditSuccess = rs.getBoolean("AUDIT_SUCCESS"); | ||||
| 	    boolean auditFailure = rs.getBoolean("AUDIT_FAILURE"); | ||||
| 	     | ||||
| 	    AccessControlEntryImpl ace = new AccessControlEntryImpl(aceId, acl, | ||||
| 	            recipient, permission, granting, auditSuccess, auditFailure); | ||||
| 	     | ||||
| 	     | ||||
| 	    Field acesField = getAccessibleField(AclImpl.class, "aces"); | ||||
| 	    List aces; | ||||
| 	 | ||||
| 	    try { | ||||
| 	        aces = (List) acesField.get(acl); | ||||
| 	    } catch (IllegalAccessException ex) { | ||||
| 	        throw new IllegalStateException( | ||||
| 	            "Could not obtain AclImpl.ace field", ex); | ||||
| 	    } | ||||
| 	 | ||||
| 	    // Add the ACE if it doesn't already exist in the ACL.aces field | ||||
| 	    if (!aces.contains(ace)) { | ||||
| 		    aces.add(ace); | ||||
| 	    } | ||||
| 	} | ||||
|      | ||||
|     /** | ||||
|      * The final phase of converting the <code>Map</code> of <code>AclImpl</code> instances | ||||
|      * which contain <code>StubAclParent</code>s into proper, valid <code>AclImpl</code>s with | ||||
|      * correct ACL parents. | ||||
|      *  | ||||
|      * @param inputMap the unconverted <code>AclImpl</code>s | ||||
|      * @param inputAcl the current <code>Acl</code> that we wish to convert (this may be | ||||
|      * @return | ||||
|      */ | ||||
|     private AclImpl convert(Map inputMap, Long currentIdentity) { | ||||
|     	Assert.notEmpty(inputMap, "InputMap required"); | ||||
|     	Assert.notNull(currentIdentity, "CurrentIdentity required"); | ||||
|     	 | ||||
|     	// Retrieve this Acl from the InputMap | ||||
|     	Acl uncastAcl = (Acl) inputMap.get(currentIdentity); | ||||
|     	Assert.isInstanceOf(AclImpl.class, uncastAcl, "The inputMap contained a non-AclImpl"); | ||||
|     	AclImpl inputAcl = (AclImpl) uncastAcl; | ||||
|     	 | ||||
|     	Acl parent = inputAcl.getParentAcl(); | ||||
|     	if (parent != null && parent instanceof StubAclParent) { | ||||
|     		// Lookup the parent | ||||
|     		StubAclParent stubAclParent = (StubAclParent) parent; | ||||
|     		parent = convert(inputMap, stubAclParent.getId()); | ||||
|     	} | ||||
|     	 | ||||
|     	// Now we have the parent (if there is one), create the true AclImpl | ||||
|     	AclImpl result = new AclImpl(inputAcl.getObjectIdentity(), (Long)inputAcl.getId(), parent, auths, null, inputAcl.isEntriesInheriting(), inputAcl.getOwner()); | ||||
|     	 | ||||
|     	// Copy the "aces" from the input to the destination | ||||
|     	Field field = getAccessibleField(AclImpl.class, "aces"); | ||||
|     	try { | ||||
|     		field.set(result, field.get(inputAcl)); | ||||
|     	} catch (IllegalAccessException ex) { | ||||
| 	        throw new IllegalStateException("Could not obtain or set AclImpl.ace field");  | ||||
|     	} | ||||
|     	 | ||||
|     	return result; | ||||
|     } | ||||
| 
 | ||||
| 	private static String computeRepeatingSql(String repeatingSql, int requiredRepetitions) { | ||||
|     	Assert.isTrue(requiredRepetitions >= 1, "Must be => 1"); | ||||
|     	 | ||||
|         String startSql = "select ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY, ACL_ENTRY.ACE_ORDER, " | ||||
|             + "ACL_OBJECT_IDENTITY.ID as ACL_ID, " | ||||
|             + "ACL_OBJECT_IDENTITY.PARENT_OBJECT, " | ||||
|             + "ACL_OBJECT_IDENTITY,ENTRIES_INHERITING, " | ||||
|             + "ACL_ENTRY.ID as ACE_ID, ACL_ENTRY.MASK, ACL_ENTRY.GRANTING, ACL_ENTRY.AUDIT_SUCCESS, ACL_ENTRY.AUDIT_FAILURE, " | ||||
|             + "ACE_SID.PRINCIPAL as ACE_PRINCIPAL, ACE_SID.SID as ACE_SID, " | ||||
|             + "ACL_SID.PRINCIPAL as ACL_PRINCIPAL, ACL_SID.SID as ACL_SID, " | ||||
|             + "ACL_CLASS.CLASS " | ||||
|             + "from ACL_OBJECT_IDENTITY, ACL_ENTRY, ACL_SID ACE_SID, ACL_SID ACL_SID, ACL_CLASS " | ||||
|             + "where ACL_ENTRY.ACL_OBJECT_IDENTITY = ACL_OBJECT_IDENTITY.ID " | ||||
|             + "and ACE_SID.ID = ACL_ENTRY.SID " | ||||
|             + "and ACL_SID.ID = ACL_OBJECT_IDENTITY.OWNER_SID " | ||||
|             + "and ACL_CLASS.ID = ACL_OBJECT_IDENTITY.OBJECT_ID_CLASS " | ||||
|             + "and ( "; | ||||
| 
 | ||||
|         String endSql = ") order by ACL_ENTRY.ACL_OBJECT_IDENTITY asc, ACL_ENTRY.ACE_ORDER asc"; | ||||
| 
 | ||||
|         StringBuffer sqlStringBuffer = new StringBuffer(); | ||||
|         sqlStringBuffer.append(startSql); | ||||
| 
 | ||||
|         for (int i = 1; i <= requiredRepetitions; i++) { | ||||
|             sqlStringBuffer.append(repeatingSql); | ||||
| 
 | ||||
|             if (i != requiredRepetitions) { | ||||
|                 sqlStringBuffer.append(" or "); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         sqlStringBuffer.append(endSql); | ||||
| 
 | ||||
|         return sqlStringBuffer.toString(); | ||||
|     } | ||||
| 
 | ||||
|     private static Field getAccessibleField(Class clazz, String protectedField) { | ||||
|         Field field = null; | ||||
| 
 | ||||
|         try { | ||||
|             field = clazz.getDeclaredField(protectedField); | ||||
|         } catch (NoSuchFieldException nsf) {} | ||||
| 
 | ||||
|         if (field == null) { | ||||
|             // Unable to locate, so try the superclass (if there is one) | ||||
|             if (clazz.getSuperclass() != null) { | ||||
|                 getAccessibleField(clazz.getSuperclass(), protectedField); | ||||
|             } else { | ||||
|                 throw new IllegalArgumentException("Couldn't find '" | ||||
|                     + protectedField + "' field"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // We have a field, so process | ||||
|         field.setAccessible(true); | ||||
| 
 | ||||
|         return field; | ||||
|     } | ||||
| 	 | ||||
|     //~ Inner Classes ========================================================== | ||||
| 
 | ||||
|     private class StubAclParent implements Acl { | ||||
|         private Long id; | ||||
| 
 | ||||
|         public StubAclParent(Long id) { | ||||
|             this.id = id; | ||||
|         } | ||||
| 
 | ||||
|         public AccessControlEntry[] getEntries() { | ||||
|             throw new UnsupportedOperationException("Stub only"); | ||||
|         } | ||||
| 
 | ||||
|         public Long getId() { | ||||
|             return id; | ||||
|         } | ||||
| 
 | ||||
|         public ObjectIdentity getObjectIdentity() { | ||||
|             throw new UnsupportedOperationException("Stub only"); | ||||
|         } | ||||
| 
 | ||||
|         public Acl getParentAcl() { | ||||
|             throw new UnsupportedOperationException("Stub only"); | ||||
|         } | ||||
| 
 | ||||
|         public boolean isEntriesInheriting() { | ||||
|             throw new UnsupportedOperationException("Stub only"); | ||||
|         } | ||||
| 
 | ||||
|         public boolean isGranted(Permission[] permission, Sid[] sids, | ||||
|             boolean administrativeMode) | ||||
|             throws NotFoundException, UnloadedSidException { | ||||
|             throw new UnsupportedOperationException("Stub only"); | ||||
|         } | ||||
| 
 | ||||
|         public boolean isSidLoaded(Sid[] sids) { | ||||
|             throw new UnsupportedOperationException("Stub only"); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     private class ProcessResultSet implements ResultSetExtractor { | ||||
|     	private Map acls; | ||||
|     	 | ||||
|     	public ProcessResultSet(Map acls) { | ||||
|     		Assert.notNull(acls, "ACLs cannot be null"); | ||||
|     		this.acls = acls; | ||||
|     	} | ||||
|     	 | ||||
|     	public Object extractData(ResultSet rs) throws SQLException, DataAccessException { | ||||
| 	        Set parentIdsToLookup = new HashSet(); // Set of parent_id Longs | ||||
| 	 | ||||
| 	        while (rs.next()) { | ||||
| 	            // Convert current row into an Acl (albeit with a StubAclParent) | ||||
| 	            convertCurrentResultIntoObject(acls, rs); | ||||
| 	 | ||||
| 	            // Figure out if this row means we need to lookup another parent | ||||
| 	            long parentId = rs.getLong("PARENT_OBJECT"); | ||||
| 	 | ||||
| 	            if (parentId != 0) { | ||||
| 	                // See if its already in the "acls" | ||||
| 	            	if (acls.containsKey(new Long(parentId))) { | ||||
| 	            		continue; // skip this while element | ||||
| 	            	} | ||||
| 	            	 | ||||
| 	            	// Now try to find it in the cache | ||||
| 	            	Acl cached = aclCache.getFromCache(new Long(parentId)); | ||||
| 	 | ||||
| 	                if (cached == null) { | ||||
| 	                    parentIdsToLookup.add(new Long(parentId)); | ||||
| 	                } else { | ||||
| 	                	// Pop into the acls map, so our convert method doesn't | ||||
| 	                	// need to deal with an unsynchronized AclCache | ||||
| 	                	Assert.isInstanceOf(AclImpl.class, cached, "Cached ACL must be an AclImpl"); | ||||
| 	                	acls.put(((AclImpl)cached).getId(), cached); | ||||
| 	                } | ||||
| 	            } | ||||
| 	        } | ||||
| 	 | ||||
| 	        // Lookup parents, adding Acls (with StubAclParents) to "acl" map | ||||
| 	        if (parentIdsToLookup.size() > 0) { | ||||
| 		        lookupPrimaryKeys(acls, parentIdsToLookup); | ||||
| 	        } | ||||
| 	 | ||||
| 	        // Return null to meet ResultSetExtractor method contract | ||||
| 	        return null; | ||||
| 	    } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,58 @@ | ||||
| package org.acegisecurity.acls.jdbc; | ||||
| 
 | ||||
| import net.sf.ehcache.Cache; | ||||
| import net.sf.ehcache.CacheException; | ||||
| import net.sf.ehcache.Element; | ||||
| 
 | ||||
| import org.acegisecurity.acls.domain.AclImpl; | ||||
| import org.acegisecurity.acls.objectidentity.ObjectIdentity; | ||||
| import org.springframework.util.Assert; | ||||
| 
 | ||||
| public class EhCacheBasedAclCache implements AclCache { | ||||
| 
 | ||||
| 	private Cache cache; | ||||
| 	 | ||||
| 	public EhCacheBasedAclCache(Cache cache) { | ||||
| 		Assert.notNull(cache, "Cache required"); | ||||
| 		this.cache = cache; | ||||
| 	} | ||||
| 	 | ||||
| 	public AclImpl getFromCache(ObjectIdentity objectIdentity) { | ||||
| 		Element element = null; | ||||
| 		try { | ||||
| 			element = cache.get(objectIdentity); | ||||
| 		} catch (CacheException ignored) {} | ||||
| 		if (element == null) { | ||||
| 			return null; | ||||
| 		} | ||||
| 		return (AclImpl) element.getValue(); | ||||
| 	} | ||||
| 
 | ||||
| 	public AclImpl getFromCache(Long pk) { | ||||
| 		Element element = null; | ||||
| 		try { | ||||
| 			element = cache.get(pk); | ||||
| 		} catch (CacheException ignored) {} | ||||
| 		if (element == null) { | ||||
| 			return null; | ||||
| 		} | ||||
| 		return (AclImpl) element.getValue(); | ||||
| 	} | ||||
| 
 | ||||
| 	public void putInCache(AclImpl acl) { | ||||
| 		if (acl.getParentAcl() != null && acl.getParentAcl() instanceof AclImpl) { | ||||
| 			putInCache((AclImpl)acl.getParentAcl()); | ||||
| 		} | ||||
| 		cache.put(new Element(acl.getObjectIdentity(), acl)); | ||||
| 		cache.put(new Element(acl.getId(), acl)); | ||||
| 	} | ||||
| 
 | ||||
| 	public void evictFromCache(Long pk) { | ||||
| 		AclImpl acl = getFromCache(pk); | ||||
| 		if (acl != null) { | ||||
| 			cache.remove(pk); | ||||
| 			cache.remove(acl.getObjectIdentity()); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,51 @@ | ||||
| package org.acegisecurity.acls.jdbc; | ||||
| 
 | ||||
| import java.util.Map; | ||||
| 
 | ||||
| import javax.sql.DataSource; | ||||
| 
 | ||||
| import org.acegisecurity.acls.AclService; | ||||
| import org.acegisecurity.acls.NotFoundException; | ||||
| import org.acegisecurity.acls.objectidentity.ObjectIdentity; | ||||
| import org.acegisecurity.acls.sid.Sid; | ||||
| import org.springframework.jdbc.core.JdbcTemplate; | ||||
| import org.springframework.util.Assert; | ||||
| 
 | ||||
| /** | ||||
|  * Simple JDBC-based implementation of <code>AclService</code>. | ||||
|  *  | ||||
|  * <p> | ||||
|  * Requires the "dirty" flags in {@link org.acegisecurity.acls.domain.AclImpl} and {@link org.acegisecurity.acls.domain.AccessControlEntryImpl} | ||||
|  * to be set, so that the implementation can detect changed parameters easily. | ||||
|  *  | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public class JdbcAclService implements AclService/*, MutableAclService */ { | ||||
| 
 | ||||
| 	private AclCache aclCache; | ||||
| 	private JdbcTemplate template; | ||||
| 	private LookupStrategy lookupStrategy; | ||||
| 
 | ||||
| 	public JdbcAclService(DataSource dataSource, AclCache aclCache, LookupStrategy lookupStrategy) { | ||||
|         Assert.notNull(dataSource, "DataSource required"); | ||||
|         Assert.notNull(aclCache, "AclCache required"); | ||||
| 		Assert.notNull(lookupStrategy, "LookupStrategy required"); | ||||
| 		this.template = new JdbcTemplate(dataSource); | ||||
| 		this.aclCache = aclCache; | ||||
| 		this.lookupStrategy = lookupStrategy; | ||||
| 	} | ||||
| 	 | ||||
| 	public Map readAclsById(ObjectIdentity[] objects) { | ||||
| 		return readAclsById(objects, null); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Method required by interface. | ||||
| 	 */ | ||||
| 	public Map readAclsById(ObjectIdentity[] objects, Sid[] sids) throws NotFoundException { | ||||
| 		return lookupStrategy.readAclsById(objects, sids); | ||||
| 	} | ||||
| 	 | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,47 @@ | ||||
| /* 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.acls.jdbc; | ||||
| 
 | ||||
| import org.acegisecurity.acls.objectidentity.ObjectIdentity; | ||||
| import org.acegisecurity.acls.sid.Sid; | ||||
| 
 | ||||
| import java.util.Map; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Performs optimised lookups for {@link JdbcAclService}. | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public interface LookupStrategy { | ||||
|     //~ Methods ================================================================ | ||||
| 
 | ||||
|     /** | ||||
|      * Perform database-specific optimized lookup. | ||||
|      * | ||||
|      * @param objects the identities to lookup (required) | ||||
|      * @param sids the SIDs for which identities are required (may be | ||||
|      *        <code>null</code> - implementations may elect not to provide SID | ||||
|      *        optimisations) | ||||
|      * | ||||
|      * @return the <code>Map</code> pursuant to the interface contract for | ||||
|      *         {@link | ||||
|      *         org.acegisecurity.acls.AclService#readAclsById(ObjectIdentity[], | ||||
|      *         Sid[])} | ||||
|      */ | ||||
|     public Map readAclsById(ObjectIdentity[] objects, Sid[] sids); | ||||
| } | ||||
| @ -0,0 +1,78 @@ | ||||
| /* 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.acls.objectidentity; | ||||
| 
 | ||||
| import java.io.Serializable; | ||||
| 
 | ||||
| /** | ||||
|  * Interface representing the identity of an individual domain object instance. | ||||
|  *  | ||||
|  * <P> | ||||
|  * As implementations are used as the key for caching and lookup, it is | ||||
|  * essential that implementations provide methods so that object-equality | ||||
|  * rather than reference-equality can be relied upon by caches. In other | ||||
|  * words, a cache can consider two <code>ObjectIdentity</code>s equal if | ||||
|  * <code>identity1.equals(identity2)</code>, rather than reference-equality of | ||||
|  * <code>identity1==identity2</code>. | ||||
|  * </p> | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public interface ObjectIdentity extends Serializable { | ||||
|     //~ Methods ================================================================ | ||||
| 
 | ||||
|     /** | ||||
|      * Refer to the <code>java.lang.Object</code> documentation for the | ||||
|      * interface contract. | ||||
|      * | ||||
|      * @param obj to be compared | ||||
|      * | ||||
|      * @return <code>true</code> if the objects are equal, <code>false</code> | ||||
|      *         otherwise | ||||
|      */ | ||||
|     public boolean equals(Object obj); | ||||
| 
 | ||||
|     /** | ||||
|      * Obtains the actual identifier. This identifier must not be reused to | ||||
|      * represent other domain objects with the same <code>javaType</code>. | ||||
|      *  | ||||
|      * <p> | ||||
|      * Because ACLs are largely immutable, it is strongly recommended to use a | ||||
|      * synthetic identifier (such as a database sequence number for the | ||||
|      * primary key). Do not use an identifier with business meaning, as that | ||||
|      * business meaning may change. | ||||
|      * </p> | ||||
|      * | ||||
|      * @return the identifier (unique within this <code>javaType</code> | ||||
|      */ | ||||
|     public Serializable getIdentifier(); | ||||
| 
 | ||||
|     /** | ||||
|      * Obtains the Java type represented by the domain object. | ||||
|      * | ||||
|      * @return the Java type of the domain object | ||||
|      */ | ||||
|     public Class getJavaType(); | ||||
| 
 | ||||
|     /** | ||||
|      * Refer to the <code>java.lang.Object</code> documentation for the | ||||
|      * interface contract. | ||||
|      * | ||||
|      * @return a hash code representation of this object | ||||
|      */ | ||||
|     public int hashCode(); | ||||
| } | ||||
| @ -0,0 +1,157 @@ | ||||
| /* 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.acls.objectidentity; | ||||
| 
 | ||||
| import org.acegisecurity.acl.basic.AclObjectIdentity; | ||||
| 
 | ||||
| import org.acegisecurity.acls.IdentityUnavailableException; | ||||
| 
 | ||||
| import org.springframework.util.Assert; | ||||
| import org.springframework.util.ReflectionUtils; | ||||
| 
 | ||||
| import java.io.Serializable; | ||||
| 
 | ||||
| import java.lang.reflect.Method; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Simple implementation of {@link AclObjectIdentity}. | ||||
|  *  | ||||
|  * <P> | ||||
|  * Uses <code>String</code>s to store the identity of the domain object | ||||
|  * instance. Also offers a constructor that uses reflection to build the | ||||
|  * identity information. | ||||
|  * </p> | ||||
|  */ | ||||
| public class ObjectIdentityImpl implements ObjectIdentity { | ||||
|     //~ Instance fields ======================================================== | ||||
| 
 | ||||
|     private Class javaType; | ||||
|     private Serializable identifier; | ||||
| 
 | ||||
|     //~ Constructors =========================================================== | ||||
| 
 | ||||
|     public ObjectIdentityImpl(String javaType, Serializable identifier) { | ||||
|         Assert.hasText(javaType, "Java Type required"); | ||||
|         Assert.notNull(identifier, "identifier required"); | ||||
|     	try { | ||||
|     		this.javaType = Class.forName(javaType); | ||||
|     	} catch (Exception ex) { | ||||
|     		ReflectionUtils.handleReflectionException(ex); | ||||
|     	} | ||||
|     	this.identifier = identifier; | ||||
|     } | ||||
|      | ||||
|     public ObjectIdentityImpl(Class javaType, Serializable identifier) { | ||||
|         Assert.notNull(javaType, "Java Type required"); | ||||
|         Assert.notNull(identifier, "identifier required"); | ||||
|         this.javaType = javaType; | ||||
|         this.identifier = identifier; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Creates the <code>NamedEntityObjectIdentity</code> based on the passed | ||||
|      * object instance. The passed object must provide a <code>getId()</code> | ||||
|      * method, otherwise an exception will be thrown. | ||||
|      * | ||||
|      * @param object the domain object instance to create an identity for | ||||
|      * | ||||
|      * @throws IdentityUnavailableException if identity could not be extracted | ||||
|      */ | ||||
|     public ObjectIdentityImpl(Object object) | ||||
|         throws IdentityUnavailableException { | ||||
|         Assert.notNull(object, "object cannot be null"); | ||||
| 
 | ||||
|         this.javaType = object.getClass(); | ||||
| 
 | ||||
|         Object result; | ||||
| 
 | ||||
|         try { | ||||
|             Method method = this.javaType.getMethod("getId", new Class[] {}); | ||||
|             result = method.invoke(object, new Object[] {}); | ||||
|         } catch (Exception e) { | ||||
|             throw new IdentityUnavailableException( | ||||
|                 "Could not extract identity from object " + object, e); | ||||
|         } | ||||
| 
 | ||||
|         Assert.isInstanceOf(Serializable.class, result, | ||||
|             "Getter must provide a return value of type Serializable"); | ||||
|         this.identifier = (Serializable) result; | ||||
|     } | ||||
| 
 | ||||
|     //~ Methods ================================================================ | ||||
| 
 | ||||
|     /** | ||||
|      * Important so caching operates properly. | ||||
|      *  | ||||
|      * <P> | ||||
|      * Considers an object of the same class equal if it has the same | ||||
|      * <code>classname</code> and <code>id</code> properties. | ||||
|      * </p> | ||||
|      * | ||||
|      * @param arg0 object to compare | ||||
|      * | ||||
|      * @return <code>true</code> if the presented object matches this object | ||||
|      */ | ||||
|     public boolean equals(Object arg0) { | ||||
|         if (arg0 == null) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         if (!(arg0 instanceof ObjectIdentityImpl)) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         ObjectIdentityImpl other = (ObjectIdentityImpl) arg0; | ||||
| 
 | ||||
|         if (this.getIdentifier().equals(other.getIdentifier()) | ||||
|             && this.getJavaType().equals(other.getJavaType())) { | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     public Serializable getIdentifier() { | ||||
|         return identifier; | ||||
|     } | ||||
| 
 | ||||
|     public Class getJavaType() { | ||||
|         return javaType; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Important so caching operates properly. | ||||
|      * | ||||
|      * @return the hash | ||||
|      */ | ||||
|     public int hashCode() { | ||||
|         int code = 31; | ||||
|         code ^= this.javaType.hashCode(); | ||||
|         code ^= this.identifier.hashCode(); | ||||
| 
 | ||||
|         return code; | ||||
|     } | ||||
| 
 | ||||
|     public String toString() { | ||||
|         StringBuffer sb = new StringBuffer(); | ||||
|         sb.append(this.getClass().getName()).append("["); | ||||
|         sb.append("Java Type: ").append(this.javaType); | ||||
|         sb.append("; Identifier: ").append(this.identifier).append("]"); | ||||
| 
 | ||||
|         return sb.toString(); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,5 @@ | ||||
| <html> | ||||
| <body> | ||||
| Enables retrieval of access control lists (ACLs) for domain object instances. | ||||
| </body> | ||||
| </html> | ||||
| @ -0,0 +1,74 @@ | ||||
| /* 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.acls.sid; | ||||
| 
 | ||||
| import org.acegisecurity.GrantedAuthority; | ||||
| 
 | ||||
| import org.springframework.util.Assert; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Represents a <code>GrantedAuthority</code> as a <code>Sid</code>. | ||||
|  *  | ||||
|  * <p> | ||||
|  * This is a basic implementation that simply uses the | ||||
|  * <code>String</code>-based principal for <code>Sid</code> comparison. More | ||||
|  * complex principal objects may wish to provide an alternative | ||||
|  * <code>Sid</code> implementation that uses some other identifier. | ||||
|  * </p> | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public class GrantedAuthoritySid implements Sid { | ||||
|     //~ Instance fields ======================================================== | ||||
| 
 | ||||
|     private String grantedAuthority; | ||||
| 
 | ||||
|     //~ Constructors =========================================================== | ||||
| 
 | ||||
|     public GrantedAuthoritySid(String grantedAuthority) { | ||||
|     	Assert.hasText(grantedAuthority, "GrantedAuthority required"); | ||||
|     	this.grantedAuthority = grantedAuthority; | ||||
|     } | ||||
|      | ||||
|     public GrantedAuthoritySid(GrantedAuthority grantedAuthority) { | ||||
|         Assert.notNull(grantedAuthority, "GrantedAuthority required"); | ||||
|         Assert.notNull(grantedAuthority.getAuthority(), | ||||
|             "This Sid is only compatible with GrantedAuthoritys that provide a non-null getAuthority()"); | ||||
|         this.grantedAuthority = grantedAuthority.getAuthority(); | ||||
|     } | ||||
| 
 | ||||
|     //~ Methods ================================================================ | ||||
| 
 | ||||
|     public boolean equals(Object object) { | ||||
|         if ((object == null) || !(object instanceof GrantedAuthoritySid)) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         // Delegate to getGrantedAuthority() to perform actual comparison (both should be identical)  | ||||
|         return ((GrantedAuthoritySid) object).getGrantedAuthority() | ||||
|                 .equals(this.getGrantedAuthority()); | ||||
|     } | ||||
| 
 | ||||
|     public String getGrantedAuthority() { | ||||
|         return grantedAuthority; | ||||
|     } | ||||
| 
 | ||||
|     public String toString() { | ||||
|         return "GrantedAuthoritySid[" + this.grantedAuthority + "]"; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,81 @@ | ||||
| /* 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.acls.sid; | ||||
| 
 | ||||
| import org.acegisecurity.Authentication; | ||||
| 
 | ||||
| import org.acegisecurity.userdetails.UserDetails; | ||||
| 
 | ||||
| import org.springframework.util.Assert; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Represents an <code>Authentication.getPrincipal()</code> as a | ||||
|  * <code>Sid</code>. | ||||
|  *  | ||||
|  * <p> | ||||
|  * This is a basic implementation that simply uses the | ||||
|  * <code>String</code>-based principal for <code>Sid</code> comparison. More | ||||
|  * complex principal objects may wish to provide an alternative | ||||
|  * <code>Sid</code> implementation that uses some other identifier. | ||||
|  * </p> | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public class PrincipalSid implements Sid { | ||||
|     //~ Instance fields ======================================================== | ||||
| 
 | ||||
|     private String principal; | ||||
| 
 | ||||
|     //~ Constructors =========================================================== | ||||
| 
 | ||||
|     public PrincipalSid(String principal) { | ||||
|     	Assert.hasText(principal, "Principal required"); | ||||
|     	this.principal = principal; | ||||
|     } | ||||
|      | ||||
|     public PrincipalSid(Authentication authentication) { | ||||
|         Assert.notNull(authentication, "Authentication required"); | ||||
|         Assert.notNull(authentication.getPrincipal(), "Principal required"); | ||||
|         this.principal = authentication.getPrincipal().toString(); | ||||
| 
 | ||||
|         if (authentication.getPrincipal() instanceof UserDetails) { | ||||
|             this.principal = ((UserDetails) authentication.getPrincipal()) | ||||
|                 .getUsername(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     //~ Methods ================================================================ | ||||
| 
 | ||||
|     public boolean equals(Object object) { | ||||
|         if ((object == null) || !(object instanceof PrincipalSid)) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         // Delegate to getPrincipal() to perform actual comparison (both should be identical)  | ||||
|         return ((PrincipalSid) object).getPrincipal() | ||||
|                 .equals(this.getPrincipal()); | ||||
|     } | ||||
| 
 | ||||
|     public String getPrincipal() { | ||||
|         return principal; | ||||
|     } | ||||
| 
 | ||||
|     public String toString() { | ||||
|         return "PrincipalSid[" + this.principal + "]"; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										54
									
								
								sandbox/src/main/java/org/acegisecurity/acls/sid/Sid.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								sandbox/src/main/java/org/acegisecurity/acls/sid/Sid.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | ||||
| /* 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.acls.sid; | ||||
| 
 | ||||
| /** | ||||
|  * A security identity recognised by the ACL system. | ||||
|  *  | ||||
|  * <p> | ||||
|  * This interface provides indirection between actual security objects (eg | ||||
|  * principals, roles, groups etc) and what is stored inside an | ||||
|  * <code>Acl</code>. This is because an <code>Acl</code> will not store an | ||||
|  * entire security object, but only an abstraction of it. This interface | ||||
|  * therefore provides a simple way to compare these abstracted security | ||||
|  * identities with other security identities and actual security objects. | ||||
|  * </p> | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public interface Sid { | ||||
|     //~ Methods ================================================================ | ||||
| 
 | ||||
|     /** | ||||
|      * Refer to the <code>java.lang.Object</code> documentation for the | ||||
|      * interface contract. | ||||
|      * | ||||
|      * @param obj to be compared | ||||
|      * | ||||
|      * @return <code>true</code> if the objects are equal, <code>false</code> | ||||
|      *         otherwise | ||||
|      */ | ||||
|     public boolean equals(Object obj); | ||||
| 
 | ||||
|     /** | ||||
|      * Refer to the <code>java.lang.Object</code> documentation for the | ||||
|      * interface contract. | ||||
|      * | ||||
|      * @return a hash code representation of this object | ||||
|      */ | ||||
|     public int hashCode(); | ||||
| } | ||||
| @ -0,0 +1,41 @@ | ||||
| package org.acegisecurity.acls.domain; | ||||
| 
 | ||||
| import junit.framework.TestCase; | ||||
| 
 | ||||
| /** | ||||
|  * Tests BasePermission and CumulativePermission. | ||||
|  *  | ||||
|  * @author Ben Alex | ||||
|  * @version $Id${date} | ||||
|  * | ||||
|  */ | ||||
| public class PermissionTests extends TestCase { | ||||
| 	public void testStringConversion() { | ||||
| 		System.out.println("R =  " + BasePermission.READ.toString()); | ||||
| 		assertEquals("BasePermission[...............................R=1]", BasePermission.READ.toString()); | ||||
| 		 | ||||
| 		System.out.println("A =  " + BasePermission.ADMINISTRATION.toString()); | ||||
| 		assertEquals("BasePermission[............................A...=8]", BasePermission.ADMINISTRATION.toString()); | ||||
| 		 | ||||
| 		System.out.println("R =  " + new CumulativePermission().set(BasePermission.READ).toString()); | ||||
| 		assertEquals("CumulativePermission[...............................R=1]", new CumulativePermission().set(BasePermission.READ).toString()); | ||||
| 		 | ||||
| 		System.out.println("A =  " + new CumulativePermission().set(BasePermission.ADMINISTRATION).toString()); | ||||
| 		assertEquals("CumulativePermission[............................A...=8]", new CumulativePermission().set(BasePermission.ADMINISTRATION).toString()); | ||||
| 		 | ||||
| 		System.out.println("RA = " + new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ).toString()); | ||||
| 		assertEquals("CumulativePermission[............................A..R=9]", new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ).toString()); | ||||
| 		 | ||||
| 		System.out.println("R =  " + new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ).clear(BasePermission.ADMINISTRATION).toString()); | ||||
| 		assertEquals("CumulativePermission[...............................R=1]", new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ).clear(BasePermission.ADMINISTRATION).toString()); | ||||
| 		 | ||||
| 		System.out.println("0 =  " + new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ).clear(BasePermission.ADMINISTRATION).clear(BasePermission.READ).toString()); | ||||
| 		assertEquals("CumulativePermission[................................=0]", new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ).clear(BasePermission.ADMINISTRATION).clear(BasePermission.READ).toString()); | ||||
| 	} | ||||
| 	 | ||||
| 	public void testExpectedIntegerValues() { | ||||
| 		assertEquals(1, BasePermission.READ.getMask()); | ||||
| 		assertEquals(8, BasePermission.ADMINISTRATION.getMask()); | ||||
| 		assertEquals(9, new CumulativePermission().set(BasePermission.READ).set(BasePermission.ADMINISTRATION).getMask()); | ||||
| 	} | ||||
| } | ||||
| @ -0,0 +1,23 @@ | ||||
| package org.acegisecurity.acls.jdbc; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| import javax.sql.DataSource; | ||||
| 
 | ||||
| import org.springframework.core.io.Resource; | ||||
| import org.springframework.jdbc.core.JdbcTemplate; | ||||
| import org.springframework.util.Assert; | ||||
| import org.springframework.util.FileCopyUtils; | ||||
| 
 | ||||
| public class DatabaseSeeder { | ||||
| 	 | ||||
| 	public DatabaseSeeder(DataSource dataSource, Resource resource) throws IOException { | ||||
| 		Assert.notNull(dataSource, "dataSource required"); | ||||
| 		Assert.notNull(resource, "resource required"); | ||||
| 		 | ||||
| 		JdbcTemplate template = new JdbcTemplate(dataSource); | ||||
| 		String sql = new String(FileCopyUtils.copyToByteArray(resource.getInputStream())); | ||||
| 		template.execute(sql); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,40 @@ | ||||
| package org.acegisecurity.acls.jdbc; | ||||
| 
 | ||||
| import java.util.Iterator; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| import org.acegisecurity.acls.Acl; | ||||
| import org.acegisecurity.acls.objectidentity.ObjectIdentity; | ||||
| import org.acegisecurity.acls.objectidentity.ObjectIdentityImpl; | ||||
| import org.springframework.test.AbstractDependencyInjectionSpringContextTests; | ||||
| 
 | ||||
| public class JdbcAclServiceTests extends AbstractDependencyInjectionSpringContextTests { | ||||
| 
 | ||||
| 	protected String[] getConfigLocations() { | ||||
| 		return new String[] {"classpath:org/acegisecurity/acls/jdbc/applicationContext-test.xml"}; | ||||
| 	} | ||||
| 	 | ||||
| 	private JdbcAclService jdbcAclService; | ||||
| 	 | ||||
| 	public void testStub() { | ||||
| 		ObjectIdentity id1 = new ObjectIdentityImpl("sample.contact.Contact", new Long(1)); | ||||
| 		ObjectIdentity id2 = new ObjectIdentityImpl("sample.contact.Contact", new Long(2)); | ||||
| 		ObjectIdentity id3 = new ObjectIdentityImpl("sample.contact.Contact", new Long(3)); | ||||
| 		ObjectIdentity id4 = new ObjectIdentityImpl("sample.contact.Contact", new Long(4)); | ||||
| 		ObjectIdentity id5 = new ObjectIdentityImpl("sample.contact.Contact", new Long(5)); | ||||
| 		ObjectIdentity id6 = new ObjectIdentityImpl("sample.contact.Contact", new Long(6)); | ||||
| 		Map map = jdbcAclService.readAclsById(new ObjectIdentity[] {id1, id2, id3, id4, id5, id6}); | ||||
| 		Iterator iterator = map.keySet().iterator(); | ||||
| 		while (iterator.hasNext()) { | ||||
| 			ObjectIdentity identity = (ObjectIdentity) iterator.next(); | ||||
| 			assertEquals(identity, ((Acl)map.get(identity)).getObjectIdentity()); | ||||
| 			System.out.println(map.get(identity)); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public void setJdbcAclService(JdbcAclService jdbcAclService) { | ||||
| 		this.jdbcAclService = jdbcAclService; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,71 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> | ||||
| 
 | ||||
| <!-- | ||||
|   - Application context containing business beans. | ||||
|   - | ||||
|   - Used by all artifacts. | ||||
|   - | ||||
|   - $Id$ | ||||
|   --> | ||||
| 
 | ||||
| <beans> | ||||
| 
 | ||||
| 	<bean id="databaseSeeder" class="org.acegisecurity.acls.jdbc.DatabaseSeeder"> | ||||
| 		<constructor-arg ref="dataSource"/> | ||||
| 		<constructor-arg value="classpath:org/acegisecurity/acls/jdbc/testData.sql"/> | ||||
| 	</bean> | ||||
| 	 | ||||
| 	<bean id="aclCache" class="org.acegisecurity.acls.jdbc.EhCacheBasedAclCache"> | ||||
| 		<constructor-arg> | ||||
| 		   <bean class="org.springframework.cache.ehcache.EhCacheFactoryBean"> | ||||
| 		      <property name="cacheManager"> | ||||
| 				<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/> | ||||
| 		      </property> | ||||
| 		      <property name="cacheName"> | ||||
| 		         <value>aclCache</value> | ||||
| 		      </property> | ||||
| 		   </bean> | ||||
| 		</constructor-arg> | ||||
| 	</bean> | ||||
|      | ||||
| 	<bean id="lookupStrategy" class="org.acegisecurity.acls.jdbc.BasicLookupStrategy"> | ||||
| 		<constructor-arg ref="dataSource"/> | ||||
| 		<constructor-arg ref="aclCache"/> | ||||
| 		<constructor-arg> | ||||
| 			<list> | ||||
| 				<bean class="org.acegisecurity.GrantedAuthorityImpl"> | ||||
| 					<constructor-arg value="ROLE_ADMINISTRATOR"/> | ||||
| 				</bean> | ||||
| 				<bean class="org.acegisecurity.GrantedAuthorityImpl"> | ||||
| 					<constructor-arg value="ROLE_ADMINISTRATOR"/> | ||||
| 				</bean> | ||||
| 				<bean class="org.acegisecurity.GrantedAuthorityImpl"> | ||||
| 					<constructor-arg value="ROLE_ADMINISTRATOR"/> | ||||
| 				</bean> | ||||
| 			</list> | ||||
| 		</constructor-arg> | ||||
| 	</bean> | ||||
| 	 | ||||
| 	<bean id="aclService" class="org.acegisecurity.acls.jdbc.JdbcAclService"> | ||||
| 		<constructor-arg ref="dataSource"/> | ||||
| 		<constructor-arg ref="aclCache"/> | ||||
| 		<constructor-arg ref="lookupStrategy"/> | ||||
| 	</bean> | ||||
| 
 | ||||
|     <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> | ||||
|         <property name="driverClassName"> | ||||
|             <value>org.hsqldb.jdbcDriver</value> | ||||
|         </property> | ||||
|         <property name="url"> | ||||
|             <value>jdbc:hsqldb:mem:test</value> | ||||
|         </property> | ||||
|         <property name="username"> | ||||
|             <value>sa</value> | ||||
|         </property> | ||||
|         <property name="password"> | ||||
|             <value></value> | ||||
|         </property> | ||||
|     </bean> | ||||
| 	 | ||||
| </beans> | ||||
							
								
								
									
										23
									
								
								sandbox/src/test/java/org/acegisecurity/acls/jdbc/select.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								sandbox/src/test/java/org/acegisecurity/acls/jdbc/select.sql
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| -- Not required. Just shows the sort of queries being sent to DB. | ||||
| 
 | ||||
| select ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY, ACL_ENTRY.ACE_ORDER,  | ||||
| ACL_OBJECT_IDENTITY.ID as ACL_ID, | ||||
| ACL_OBJECT_IDENTITY.PARENT_OBJECT, | ||||
| ACL_OBJECT_IDENTITY,ENTRIES_INHERITING, | ||||
| ACL_ENTRY.ID as ACE_ID, ACL_ENTRY.MASK, ACL_ENTRY.GRANTING, ACL_ENTRY.AUDIT_SUCCESS, ACL_ENTRY.AUDIT_FAILURE, | ||||
| ACE_SID.PRINCIPAL as ACE_PRINCIPAL, ACE_SID.SID as ACE_SID, | ||||
| ACL_SID.PRINCIPAL as ACL_PRINCIPAL, ACL_SID.SID as ACL_SID, | ||||
| ACL_CLASS.CLASS | ||||
| from ACL_OBJECT_IDENTITY, ACL_ENTRY, ACL_SID ACE_SID, ACL_SID ACL_SID, ACL_CLASS | ||||
| where ACL_ENTRY.ACL_OBJECT_IDENTITY = ACL_OBJECT_IDENTITY.ID | ||||
| 
 | ||||
| and ACE_SID.ID = ACL_ENTRY.SID | ||||
| and ACL_SID.ID = ACL_OBJECT_IDENTITY.OWNER_SID | ||||
| and ACL_CLASS.ID = ACL_OBJECT_IDENTITY.OBJECT_ID_CLASS | ||||
| and ( | ||||
| (ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY = 1  | ||||
| and ACL_CLASS.CLASS = 'sample.contact.Contact') | ||||
| or  | ||||
| (ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY = 2 | ||||
| and ACL_CLASS.CLASS = 'sample.contact.Contact') | ||||
| ) order by ACL_ENTRY.ACL_OBJECT_IDENTITY asc, ACL_ENTRY.ACE_ORDER asc | ||||
| @ -0,0 +1,70 @@ | ||||
| CREATE TABLE ACL_SID( | ||||
| ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY, | ||||
| PRINCIPAL BOOLEAN NOT NULL, | ||||
| SID VARCHAR_IGNORECASE(100) NOT NULL, | ||||
| CONSTRAINT UNIQUE_UK_1 UNIQUE(SID,PRINCIPAL)); | ||||
| 
 | ||||
| INSERT INTO ACL_SID VALUES (1, TRUE, 'MARISSA'); | ||||
| INSERT INTO ACL_SID VALUES (2, TRUE, 'DIANNE'); | ||||
| INSERT INTO ACL_SID VALUES (3, TRUE, 'SCOTT'); | ||||
| INSERT INTO ACL_SID VALUES (4, TRUE, 'PETER'); | ||||
| 
 | ||||
| CREATE TABLE ACL_CLASS( | ||||
| ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY, | ||||
| CLASS VARCHAR_IGNORECASE(100) NOT NULL, | ||||
| CONSTRAINT UNIQUE_UK_2 UNIQUE(CLASS)); | ||||
| 
 | ||||
| INSERT INTO ACL_CLASS VALUES (1, 'sample.contact.Contact'); | ||||
| 
 | ||||
| CREATE TABLE ACL_OBJECT_IDENTITY( | ||||
| ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY, | ||||
| OBJECT_ID_CLASS BIGINT NOT NULL, | ||||
| OBJECT_ID_IDENTITY BIGINT NOT NULL, | ||||
| PARENT_OBJECT BIGINT, | ||||
| OWNER_SID BIGINT, | ||||
| ENTRIES_INHERITING BOOLEAN NOT NULL, | ||||
| CONSTRAINT UNIQUE_UK_3 UNIQUE(OBJECT_ID_CLASS,OBJECT_ID_IDENTITY), | ||||
| CONSTRAINT FOREIGN_FK_1 FOREIGN KEY(PARENT_OBJECT)REFERENCES ACL_OBJECT_IDENTITY(ID), | ||||
| CONSTRAINT FOREIGN_FK_2 FOREIGN KEY(OBJECT_ID_CLASS)REFERENCES ACL_CLASS(ID), | ||||
| CONSTRAINT FOREIGN_FK_3 FOREIGN KEY(OWNER_SID)REFERENCES ACL_SID(ID)); | ||||
| 
 | ||||
| INSERT INTO ACL_OBJECT_IDENTITY VALUES (1, 1, 1, NULL, 1, TRUE); | ||||
| INSERT INTO ACL_OBJECT_IDENTITY VALUES (2, 1, 2, 1, 2, TRUE); | ||||
| INSERT INTO ACL_OBJECT_IDENTITY VALUES (3, 1, 3, 1, 1, FALSE); | ||||
| INSERT INTO ACL_OBJECT_IDENTITY VALUES (4, 1, 4, 1, 2, TRUE); | ||||
| INSERT INTO ACL_OBJECT_IDENTITY VALUES (5, 1, 5, 1, 2, FALSE); | ||||
| INSERT INTO ACL_OBJECT_IDENTITY VALUES (6, 1, 6, NULL, 1, TRUE); | ||||
| 
 | ||||
| CREATE TABLE ACL_ENTRY( | ||||
| ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY, | ||||
| ACL_OBJECT_IDENTITY BIGINT NOT NULL, | ||||
| ACE_ORDER INT NOT NULL, | ||||
| SID BIGINT NOT NULL, | ||||
| MASK INTEGER NOT NULL, | ||||
| GRANTING BOOLEAN NOT NULL, | ||||
| AUDIT_SUCCESS BOOLEAN NOT NULL, | ||||
| AUDIT_FAILURE BOOLEAN NOT NULL, | ||||
| CONSTRAINT UNIQUE_UK_4 UNIQUE(ACL_OBJECT_IDENTITY,ACE_ORDER), | ||||
| CONSTRAINT FOREIGN_FK_4 FOREIGN KEY(ACL_OBJECT_IDENTITY) REFERENCES ACL_OBJECT_IDENTITY(ID), | ||||
| CONSTRAINT FOREIGN_FK_5 FOREIGN KEY(SID) REFERENCES ACL_SID(ID)); | ||||
| 
 | ||||
| INSERT INTO ACL_ENTRY VALUES (1, 1, 1, 2, 8, TRUE, FALSE, FALSE); | ||||
| INSERT INTO ACL_ENTRY VALUES (2, 1, 2, 1, 2, TRUE, FALSE, FALSE); | ||||
| INSERT INTO ACL_ENTRY VALUES (3, 1, 3, 3, 8, TRUE, FALSE, FALSE); | ||||
| INSERT INTO ACL_ENTRY VALUES (4, 2, 1, 3, 4, TRUE, FALSE, FALSE); | ||||
| INSERT INTO ACL_ENTRY VALUES (5, 2, 2, 4, 8, TRUE, FALSE, FALSE); | ||||
| INSERT INTO ACL_ENTRY VALUES (6, 3, 1, 3, 8, TRUE, FALSE, FALSE); | ||||
| INSERT INTO ACL_ENTRY VALUES (7, 3, 2, 4, 8, TRUE, FALSE, FALSE); | ||||
| INSERT INTO ACL_ENTRY VALUES (8, 3, 3, 1, 8, FALSE, FALSE, FALSE); | ||||
| INSERT INTO ACL_ENTRY VALUES (9, 4, 1, 4, 8, TRUE, FALSE, FALSE); | ||||
| INSERT INTO ACL_ENTRY VALUES (10, 5, 1, 2, 8, TRUE, FALSE, FALSE); | ||||
| INSERT INTO ACL_ENTRY VALUES (11, 5, 2, 3, 8, FALSE, TRUE, TRUE); | ||||
| INSERT INTO ACL_ENTRY VALUES (12, 5, 3, 1, 8, TRUE, FALSE, FALSE); | ||||
| INSERT INTO ACL_ENTRY VALUES (13, 5, 4, 4, 8, TRUE, FALSE, FALSE); | ||||
| INSERT INTO ACL_ENTRY VALUES (14, 6, 1, 2, 1, TRUE, FALSE, FALSE); | ||||
| INSERT INTO ACL_ENTRY VALUES (15, 6, 2, 1, 2, TRUE, FALSE, FALSE); | ||||
| INSERT INTO ACL_ENTRY VALUES (16, 6, 3, 2, 4, TRUE, FALSE, FALSE); | ||||
| INSERT INTO ACL_ENTRY VALUES (17, 6, 4, 3, 2, TRUE, FALSE, FALSE); | ||||
| INSERT INTO ACL_ENTRY VALUES (18, 6, 5, 3, 1, TRUE, FALSE, FALSE); | ||||
| INSERT INTO ACL_ENTRY VALUES (19, 6, 6, 4, 4, TRUE, FALSE, FALSE); | ||||
| INSERT INTO ACL_ENTRY VALUES (20, 6, 7, 4, 2, TRUE, FALSE, FALSE); | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user