SEC-239: New ACL module.

This commit is contained in:
Ben Alex 2006-11-17 02:01:21 +00:00
parent 2984913051
commit 9f512c384e
94 changed files with 5759 additions and 3676 deletions

View File

@ -5,6 +5,7 @@
<classpathentry kind="src" path="core/src/test/java"/>
<classpathentry kind="src" path="core/src/test/resources"/>
<classpathentry kind="src" path="sandbox/other/src/main/java"/>
<classpathentry kind="src" path="sandbox/other/src/test/java"/>
<classpathentry kind="src" path="samples/contacts/src/main/java"/>
<classpathentry kind="src" path="samples/contacts/src/main/resources"/>
<classpathentry kind="src" path="samples/contacts/src/test/java"/>
@ -40,7 +41,7 @@
<classpathentry kind="var" path="MAVEN_REPO/commons-codec/jars/commons-codec-1.3.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/commons-collections/jars/commons-collections-3.1.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/commons-logging/jars/commons-logging-1.0.4.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/hsqldb/jars/hsqldb-1.7.3.0.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/hsqldb/jars/hsqldb-1.8.0.4.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/oro/jars/oro-2.0.8.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/javax.servlet/jars/servlet-api-2.4.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/tomcat/jars/catalina-4.1.9.jar"/>

View File

@ -93,7 +93,7 @@
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.7.3.0</version>
<version>1.8.0.4</version>
<scope>test</scope>
</dependency>
<dependency>

View File

@ -1,25 +1,24 @@
/* 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;
import java.io.Serializable;
/* 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;
import java.io.Serializable;
/**
* Represents an individual permission assignment within an {@link Acl}.
*
@ -30,28 +29,28 @@ import java.io.Serializable;
* @author Ben Alex
* @version $Id$
*
*/
public interface AccessControlEntry {
//~ Methods ========================================================================================================
public Acl getAcl();
/**
* Obtains an identifier that represents this ACE.
*
* @return the identifier, or <code>null</code> if unsaved
*/
public Serializable getId();
public Permission getPermission();
public Sid getSid();
/**
* Indicates the a Permission is being granted to the relevant Sid. If false,
* indicates the permission is being revoked/blocked.
*
* @return true if being granted, false otherwise
*/
public boolean isGranting();
}
*/
public interface AccessControlEntry {
//~ Methods ========================================================================================================
public Acl getAcl();
/**
* Obtains an identifier that represents this ACE.
*
* @return the identifier, or <code>null</code> if unsaved
*/
public Serializable getId();
public Permission getPermission();
public Sid getSid();
/**
* Indicates the a Permission is being granted to the relevant Sid. If false, indicates the permission is
* being revoked/blocked.
*
* @return true if being granted, false otherwise
*/
public boolean isGranting();
}

View File

@ -1,26 +1,25 @@
/* 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.io.Serializable;
/* 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.io.Serializable;
/**
* Represents an access control list (ACL) for a domain object.
*
@ -40,105 +39,114 @@ import java.io.Serializable;
*
* @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);
}
*/
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();
/**
* Determines the owner of the <code>Acl</code>. The meaning of ownership varies by implementation and is
* unspecified.
*
* @return the owner (may be null if the implementation does not use ownership concepts)
*/
public Sid getOwner();
/**
* 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.</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 logging
* or auditing (if supported by the implementation) should be undertaken
*
* @return <code>true</code> is authorization is granted
*
* @throws NotFoundException MUST be thrown if an implementation cannot make an authoritative authorization
* decision, usually because there is no ACL information for this particular permission and/or SID
* @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 one or more security identities the caller is interest in knowing whether this <code>Sid</code>
* supports
*
* @return <code>true</code> if every passed <code>Sid</code> is represented by this <code>Acl</code> instance
*/
public boolean isSidLoaded(Sid[] sids);
}

View File

@ -1,106 +1,105 @@
/* 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);
}
}
/* 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);
}
}

View File

@ -1,66 +1,100 @@
/* 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;
/* 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>)
*
* @throws NotFoundException DOCUMENT ME!
*/
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>)
*
* @throws NotFoundException DOCUMENT ME!
*/
public Map readAclsById(ObjectIdentity[] objects, Sid[] sids)
throws NotFoundException;
}
*/
public interface AclService {
//~ Methods ========================================================================================================
/**
* Locates all object identities that use the specified parent. This is useful for administration tools.
*
* @param parentIdentity to locate children of
*
* @return the children (or <code>null</code> if none were found)
*/
public ObjectIdentity[] findChildren(ObjectIdentity parentIdentity);
/**
* Same as {@link #readAclsById(ObjectIdentity[])} except it returns only a single Acl.<p>This method
* should not be called as it does not leverage the underlaying implementation's potential ability to filter
* <code>Acl</code> entries based on a {@link Sid} parameter.</p>
*
* @param object DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws NotFoundException DOCUMENT ME!
*/
public Acl readAclById(ObjectIdentity object) throws NotFoundException;
/**
* Same as {@link #readAclsById(ObjectIdentity[], Sid[])} except it returns only a single Acl.
*
* @param object DOCUMENT ME!
* @param sids DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws NotFoundException DOCUMENT ME!
*/
public Acl readAclById(ObjectIdentity object, Sid[] sids)
throws NotFoundException;
/**
* 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>)
*
* @throws NotFoundException DOCUMENT ME!
*/
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>)
*
* @throws NotFoundException DOCUMENT ME!
*/
public Map readAclsById(ObjectIdentity[] objects, Sid[] sids)
throws NotFoundException;
}

View File

@ -1,49 +1,48 @@
/* 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 ===================================================================================================
/* 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);
}
*/
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);
}
}
*/
public AlreadyExistsException(String msg, Throwable t) {
super(msg, t);
}
}

View File

@ -1,31 +1,30 @@
/* 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;
/* 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;
/**
* Represents an ACE that provides auditing information.
*
* @author Ben Alex
* @version $Id$
*
*/
public interface AuditableAccessControlEntry extends AccessControlEntry {
//~ Methods ========================================================================================================
public boolean isAuditFailure();
public boolean isAuditSuccess();
}
*/
public interface AuditableAccessControlEntry extends AccessControlEntry {
//~ Methods ========================================================================================================
public boolean isAuditFailure();
public boolean isAuditSuccess();
}

View File

@ -1,29 +1,31 @@
/* 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;
/* 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;
/**
* A mutable ACL that provides audit capabilities.
*
* @author Ben Alex
* @version $Id$
*
*/
public interface AuditableAcl extends MutableAcl {
//~ Methods ========================================================================================================
public void updateAuditing(Long aceId, boolean auditSuccess, boolean auditFailure);
}
*/
public interface AuditableAcl extends MutableAcl {
//~ Methods ========================================================================================================
public void updateAuditing(Serializable aceId, boolean auditSuccess, boolean auditFailure);
}

View File

@ -1,50 +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 {@link Acl} cannot be deleted because children <code>Acl</code>s exist.
*
* @author Ben Alex
* @version $Id$
*/
public class ChildrenExistException extends AcegiSecurityException {
//~ Constructors ===================================================================================================
/* 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);
}
*/
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);
}
}
*/
public ChildrenExistException(String msg, Throwable t) {
super(msg, t);
}
}

View File

@ -1,49 +1,48 @@
/* 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 ===================================================================================================
/* 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);
}
*/
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);
}
}
*/
public IdentityUnavailableException(String msg, Throwable t) {
super(msg, t);
}
}

View File

@ -1,25 +1,24 @@
/* 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;
import java.io.Serializable;
/* 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;
import java.io.Serializable;
/**
* A mutable <code>Acl</code>.
*
@ -30,31 +29,47 @@ import java.io.Serializable;
*
* @author Ben Alex
* @version $Id$
*/
public interface MutableAcl extends Acl {
//~ Methods ========================================================================================================
public void deleteAce(Long aceId) throws NotFoundException;
/**
* Obtains an identifier that represents this <code>MutableAcl</code>.
*
* @return the identifier, or <code>null</code> if unsaved
*/
public Serializable getId();
public void insertAce(Long afterAceId, Permission permission, Sid sid, boolean granting)
throws NotFoundException;
public void setEntriesInheriting(boolean entriesInheriting);
/**
* 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 interface MutableAcl extends Acl {
//~ Methods ========================================================================================================
public void deleteAce(Serializable aceId) throws NotFoundException;
/**
* Retrieves all of the non-deleted {@link AccessControlEntry} instances currently stored by the
* <code>MutableAcl</code>. The returned objects should be immutable outside the package, and therefore it is safe
* to return them to the caller for informational purposes. The <code>AccessControlEntry</code> information is
* needed so that invocations of update and delete methods on the <code>MutableAcl</code> can refer to a valid
* {@link AccessControlEntry#getId()}.
*
* @return DOCUMENT ME!
*/
public AccessControlEntry[] getEntries();
/**
* Obtains an identifier that represents this <code>MutableAcl</code>.
*
* @return the identifier, or <code>null</code> if unsaved
*/
public Serializable getId();
public void insertAce(Serializable afterAceId, Permission permission, Sid sid, boolean granting)
throws NotFoundException;
/**
* Change the value returned by {@link Acl#isEntriesInheriting()}.
*
* @param entriesInheriting the new value
*/
public void setEntriesInheriting(boolean entriesInheriting);
/**
* Changes the parent of this ACL.
*
* @param newParent the new parent
*/
public void setParent(MutableAcl newParent);
public void updateAce(Serializable aceId, Permission permission)
throws NotFoundException;
}

View File

@ -1,74 +1,65 @@
/* 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;
/* 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;
}
*/
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 objectIdentity 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 objectIdentity)
throws AlreadyExistsException;
/**
* Removes the specified entry from the database.
*
* @param objectIdentity 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 objectIdentity, boolean deleteChildren)
throws ChildrenExistException;
/**
* Changes an existing <code>Acl</code> in the database.
*
* @param acl to modify
*
* @return DOCUMENT ME!
*
* @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 MutableAcl updateAcl(MutableAcl acl) throws NotFoundException;
}

View File

@ -1,49 +1,48 @@
/* 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 ===================================================================================================
/* 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);
}
*/
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);
}
}
*/
public NotFoundException(String msg, Throwable t) {
super(msg, t);
}
}

View File

@ -1,23 +1,22 @@
/* 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;
/* 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.
*
@ -28,11 +27,9 @@ import org.acegisecurity.acls.sid.Sid;
*
* @author Ben Alex
* @version $Id$
*/
public interface OwnershipAcl extends MutableAcl {
//~ Methods ========================================================================================================
public Sid getOwner();
public void setOwner(Sid newOwner);
}
*/
public interface OwnershipAcl extends MutableAcl {
//~ Methods ========================================================================================================
public void setOwner(Sid newOwner);
}

View File

@ -1,57 +1,56 @@
/* 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;
/* 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();
}
*/
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();
}

View File

@ -1,50 +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 {@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 ===================================================================================================
/* 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);
}
*/
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);
}
}
*/
public UnloadedSidException(String msg, Throwable t) {
super(msg, t);
}
}

View File

@ -1,149 +1,133 @@
/* 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.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;
import java.io.Serializable;
/**
* An immutable default implementation of <code>AccessControlEntry</code>.
*
* @author Ben Alex
* @version $Id$
*/
public class AccessControlEntryImpl implements AccessControlEntry, AuditableAccessControlEntry {
//~ Instance fields ================================================================================================
private Acl acl;
private Permission permission;
private Serializable id;
private Sid sid;
private boolean aceDirty = false;
private boolean auditFailure = false;
private boolean auditSuccess = false;
private boolean granting;
//~ Constructors ===================================================================================================
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;
}
//~ Methods ========================================================================================================
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 Acl getAcl() {
return acl;
}
public Serializable getId() {
return id;
}
public Permission getPermission() {
return permission;
}
public Sid getSid() {
return sid;
}
public boolean isAceDirty() {
return aceDirty;
}
public boolean isAuditFailure() {
return auditFailure;
}
public boolean isAuditSuccess() {
return auditSuccess;
}
public boolean isGranting() {
return granting;
}
void setAuditFailure(boolean auditFailure) {
this.auditFailure = auditFailure;
this.aceDirty = true;
}
void setAuditSuccess(boolean auditSuccess) {
this.auditSuccess = auditSuccess;
this.aceDirty = true;
}
void setId(Serializable id) {
this.id = id;
}
void setPermission(Permission permission) {
Assert.notNull(permission, "Permission required");
this.permission = permission;
this.aceDirty = true;
}
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();
}
}
/* 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.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;
import java.io.Serializable;
/**
* An immutable default implementation of <code>AccessControlEntry</code>.
*
* @author Ben Alex
* @version $Id$
*/
public class AccessControlEntryImpl implements AccessControlEntry, AuditableAccessControlEntry {
//~ Instance fields ================================================================================================
private Acl acl;
private Permission permission;
private Serializable id;
private Sid sid;
private boolean auditFailure = false;
private boolean auditSuccess = false;
private boolean granting;
//~ Constructors ===================================================================================================
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;
}
//~ Methods ========================================================================================================
public boolean equals(Object arg0) {
if (!(arg0 instanceof AccessControlEntryImpl)) {
return false;
}
AccessControlEntryImpl rhs = (AccessControlEntryImpl) arg0;
if ((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 Acl getAcl() {
return acl;
}
public Serializable getId() {
return id;
}
public Permission getPermission() {
return permission;
}
public Sid getSid() {
return sid;
}
public boolean isAuditFailure() {
return auditFailure;
}
public boolean isAuditSuccess() {
return auditSuccess;
}
public boolean isGranting() {
return granting;
}
void setAuditFailure(boolean auditFailure) {
this.auditFailure = auditFailure;
}
void setAuditSuccess(boolean auditSuccess) {
this.auditSuccess = auditSuccess;
}
void setPermission(Permission permission) {
Assert.notNull(permission, "Permission required");
this.permission = permission;
}
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).append("; ");
sb.append("auditSuccess: ").append(this.auditSuccess).append("; ");
sb.append("auditFailure: ").append(this.auditFailure);
sb.append("]");
return sb.toString();
}
}

View File

@ -0,0 +1,38 @@
/* 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.Acl;
/**
* Strategy used by {@link AclImpl} to determine whether a principal is permitted to call
* adminstrative methods on the <code>AclImpl</code>.
*
* @author Ben Alex
* @version $Id$
*/
public interface AclAuthorizationStrategy {
//~ Static fields/initializers =====================================================================================
public static final int CHANGE_OWNERSHIP = 0;
public static final int CHANGE_AUDITING = 1;
public static final int CHANGE_GENERAL = 2;
//~ Methods ========================================================================================================
public void securityCheck(Acl acl, int changeType);
}

View File

@ -0,0 +1,125 @@
/* 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.AccessDeniedException;
import org.acegisecurity.Authentication;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.acls.Acl;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.sid.PrincipalSid;
import org.acegisecurity.acls.sid.Sid;
import org.acegisecurity.acls.sid.SidRetrievalStrategy;
import org.acegisecurity.acls.sid.SidRetrievalStrategyImpl;
import org.acegisecurity.context.SecurityContextHolder;
import org.springframework.util.Assert;
/**
* Default implementation of {@link AclAuthorizationStrategy}.<p>Permission will be granted provided the current
* principal is either the owner (as defined by the ACL), has {@link BasePermission#ADMINISTRATION} (as defined by the
* ACL and via a {@link Sid} retrieved for the current principal via {@link #sidRetrievalStrategy}), or if the current
* principal holds the relevant system-wide {@link GrantedAuthority} and injected into the constructor.</p>
*
* @author Ben Alex
* @version $Id$
*/
public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
//~ Instance fields ================================================================================================
private GrantedAuthority gaGeneralChanges;
private GrantedAuthority gaModifyAuditing;
private GrantedAuthority gaTakeOwnership;
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
//~ Constructors ===================================================================================================
/**
* Constructor. The only mandatory parameter relates to the system-wide {@link GrantedAuthority} instances that
* can be held to always permit ACL changes.
*
* @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 AclAuthorizationStrategyImpl(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];
}
//~ Methods ========================================================================================================
public void securityCheck(Acl acl, 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(acl.getOwner()) && ((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;
}
}
// Try to get permission via ACEs within the ACL
Sid[] sids = sidRetrievalStrategy.getSids(authentication);
if (acl.isGranted(new Permission[] {BasePermission.ADMINISTRATION}, sids, false)) {
return;
}
throw new AccessDeniedException(
"Principal does not have required ACL permissions to perform requested operation");
}
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
this.sidRetrievalStrategy = sidRetrievalStrategy;
}
}

View File

@ -12,13 +12,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.domain;
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;
@ -28,11 +23,8 @@ 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;
import java.io.Serializable;
@ -49,29 +41,17 @@ import java.util.Vector;
* @version $Id
*/
public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
//~ Static fields/initializers =====================================================================================
private static final int CHANGE_OWNERSHIP = 0;
private static final int CHANGE_AUDITING = 1;
private static final int CHANGE_GENERAL = 2;
//~ Instance fields ================================================================================================
private Acl parentAcl;
private AuditLogger auditLogger = new ConsoleAuditLogger(); // AuditableAcl
private GrantedAuthority gaGeneralChanges;
private GrantedAuthority gaModifyAuditing;
private GrantedAuthority gaTakeOwnership;
private AclAuthorizationStrategy aclAuthorizationStrategy;
private AuditLogger auditLogger;
private List aces = new Vector();
private List deletedAces = new Vector();
private Long id;
private ObjectIdentity objectIdentity;
private Serializable id;
private Sid owner; // OwnershipAcl
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 entriesInheriting = false;
private boolean updatedAces = false; // for snapshot detection
private boolean entriesInheriting = true;
//~ Constructors ===================================================================================================
@ -81,17 +61,19 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
*
* @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 aclAuthorizationStrategy authorization strategy (required)
* @param auditLogger audit logger (required)
*/
public AclImpl(ObjectIdentity objectIdentity, Long id, GrantedAuthority[] auths) {
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
AuditLogger auditLogger) {
Assert.notNull(objectIdentity, "Object Identity required");
Assert.notNull(id, "Id required");
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
Assert.notNull(auditLogger, "AuditLogger required");
this.objectIdentity = objectIdentity;
this.id = id;
this.setAuthorities(auths);
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
this.auditLogger = auditLogger;
}
/**
@ -100,10 +82,8 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
*
* @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 aclAuthorizationStrategy authorization strategy (required)
* @param auditLogger audit logger (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>)
@ -111,14 +91,17 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
* this ACL
* @param owner the owner (required)
*/
public AclImpl(ObjectIdentity objectIdentity, Long id, Acl parentAcl, GrantedAuthority[] auths, Sid[] loadedSids,
boolean entriesInheriting, Sid owner) {
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
AuditLogger auditLogger, Acl parentAcl, Sid[] loadedSids, boolean entriesInheriting, Sid owner) {
Assert.notNull(objectIdentity, "Object Identity required");
Assert.notNull(id, "Id required");
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
Assert.notNull(owner, "Owner required");
Assert.notNull(auditLogger, "AuditLogger required");
this.objectIdentity = objectIdentity;
this.id = id;
setAuthorities(auths);
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
this.auditLogger = auditLogger;
this.parentAcl = parentAcl; // may be null
this.loadedSids = loadedSids; // may be null
this.entriesInheriting = entriesInheriting;
@ -133,17 +116,8 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
//~ Methods ========================================================================================================
/**
* 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 void deleteAce(Long aceId) throws NotFoundException {
securityCheck(CHANGE_GENERAL);
public void deleteAce(Serializable aceId) throws NotFoundException {
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
synchronized (aces) {
int offset = findAceOffset(aceId);
@ -152,12 +126,11 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
throw new NotFoundException("Requested ACE ID not found");
}
aces.remove(offset);
deletedAces.add(aceId);
this.aces.remove(offset);
}
}
private int findAceOffset(Long aceId) {
private int findAceOffset(Serializable aceId) {
Assert.notNull(aceId, "ACE ID is required");
synchronized (aces) {
@ -174,7 +147,7 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
}
public AccessControlEntry[] getEntries() {
// Can safely return AccessControlEntry directly, as they're immutable
// Can safely return AccessControlEntry directly, as they're immutable outside the ACL package
return (AccessControlEntry[]) aces.toArray(new AccessControlEntry[] {});
}
@ -194,9 +167,9 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
return parentAcl;
}
public void insertAce(Long afterAceId, Permission permission, Sid sid, boolean granting)
public void insertAce(Serializable afterAceId, Permission permission, Sid sid, boolean granting)
throws NotFoundException {
securityCheck(CHANGE_GENERAL);
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
Assert.notNull(permission, "Permission required");
Assert.notNull(sid, "Sid required");
@ -210,17 +183,11 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
throw new NotFoundException("Requested ACE ID not found");
}
aces.add(offset + 1, ace);
this.aces.add(offset + 1, ace);
} else {
aces.add(ace);
this.aces.add(ace);
}
}
this.addedAces = true;
}
public boolean isAclDirty() {
return aclDirty;
}
public boolean isEntriesInheriting() {
@ -231,18 +198,19 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
* 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.
* presented. A search will then be performed for the first {@link AccessControlEntry} object that directly
* matches that <code>permission:sid</code> combination. 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 SID arguments presented to the method were not loaded by the ACL,
* <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)
@ -335,7 +303,7 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
return true;
}
// This ACL applies to a SID subset. Iterate to check it applies
// This ACL applies to a SID subset only. Iterate to check it applies.
for (int i = 0; i < sids.length; i++) {
boolean found = false;
@ -356,83 +324,22 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
return true;
}
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");
}
/**
* 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).</p>
*
* @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];
}
public void setEntriesInheriting(boolean entriesInheriting) {
securityCheck(CHANGE_GENERAL);
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
this.entriesInheriting = entriesInheriting;
this.aclDirty = true;
}
public void setOwner(Sid newOwner) {
securityCheck(CHANGE_OWNERSHIP);
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
Assert.notNull(newOwner, "Owner required");
this.owner = newOwner;
this.aclDirty = true;
}
public void setParent(MutableAcl newParent) {
securityCheck(CHANGE_GENERAL);
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
Assert.notNull(newParent, "New Parent required");
Assert.isTrue(!newParent.equals(this), "Cannot be the parent of yourself");
this.parentAcl = newParent;
this.aclDirty = true;
}
public String toString() {
@ -455,6 +362,10 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
sb.append(iterator.next().toString()).append("\r\n");
}
if (count == 0) {
sb.append("no ACEs; ");
}
sb.append("inheriting: ").append(this.entriesInheriting).append("; ");
sb.append("parent: ").append((this.parentAcl == null) ? "Null" : this.parentAcl.getObjectIdentity().toString());
sb.append("]");
@ -462,9 +373,9 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
return sb.toString();
}
public void updateAce(Long aceId, Permission permission)
public void updateAce(Serializable aceId, Permission permission)
throws NotFoundException {
securityCheck(CHANGE_GENERAL);
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
synchronized (aces) {
int offset = findAceOffset(aceId);
@ -476,12 +387,10 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
AccessControlEntryImpl ace = (AccessControlEntryImpl) aces.get(offset);
ace.setPermission(permission);
}
this.updatedAces = true;
}
public void updateAuditing(Long aceId, boolean auditSuccess, boolean auditFailure) {
securityCheck(CHANGE_AUDITING);
public void updateAuditing(Serializable aceId, boolean auditSuccess, boolean auditFailure) {
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_AUDITING);
synchronized (aces) {
int offset = findAceOffset(aceId);
@ -494,7 +403,5 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
ace.setAuditSuccess(auditSuccess);
ace.setAuditFailure(auditFailure);
}
this.updatedAces = true;
}
}

View File

@ -1,32 +1,31 @@
/* 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.AccessControlEntry;
/* 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.AccessControlEntry;
/**
* Used by <code>AclImpl</code> to log audit events.
*
* @author Ben Alex
* @version $Id$
*
*/
public interface AuditLogger {
//~ Methods ========================================================================================================
public void logIfNeeded(boolean granted, AccessControlEntry ace);
}
*/
public interface AuditLogger {
//~ Methods ========================================================================================================
public void logIfNeeded(boolean granted, AccessControlEntry ace);
}

View File

@ -0,0 +1,164 @@
/* 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;
import org.springframework.util.Assert;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
/**
* A set of standard permissions.
*
* @author Ben Alex
* @version $Id$
*/
public class BasePermission implements Permission {
//~ Static fields/initializers =====================================================================================
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 DELETE = new BasePermission(1 << 3, 'D'); // 8
public static final Permission ADMINISTRATION = new BasePermission(1 << 4, 'A'); // 16
private static Map locallyDeclaredPermissionsByInteger = new HashMap();
private static Map locallyDeclaredPermissionsByName = new HashMap();
static {
Field[] fields = BasePermission.class.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
try {
Object fieldValue = fields[i].get(null);
if (BasePermission.class.isAssignableFrom(fieldValue.getClass())) {
// Found a BasePermission static field
BasePermission perm = (BasePermission) fieldValue;
locallyDeclaredPermissionsByInteger.put(new Integer(perm.getMask()), perm);
locallyDeclaredPermissionsByName.put(fields[i].getName(), perm);
}
} catch (Exception ignore) {}
}
}
//~ Instance fields ================================================================================================
private char code;
private int mask;
//~ Constructors ===================================================================================================
private BasePermission(int mask, char code) {
this.mask = mask;
this.code = code;
}
//~ Methods ========================================================================================================
/**
* Dynamically creates a <code>CumulativePermission</code> or <code>BasePermission</code> representing the
* active bits in the passed mask.
*
* @param mask to build
*
* @return a Permission representing the requested object
*/
public static Permission buildFromMask(int mask) {
if (locallyDeclaredPermissionsByInteger.containsKey(new Integer(mask))) {
// The requested mask has an exactly match against a statically-defined BasePermission, so return it
return (Permission) locallyDeclaredPermissionsByInteger.get(new Integer(mask));
}
// To get this far, we have to use a CumulativePermission
CumulativePermission permission = new CumulativePermission();
for (int i = 0; i < 32; i++) {
int permissionToCheck = 1 << i;
if ((mask & permissionToCheck) == permissionToCheck) {
Permission p = (Permission) locallyDeclaredPermissionsByInteger.get(new Integer(permissionToCheck));
Assert.state(p != null,
"Mask " + permissionToCheck + " does not have a corresponding static BasePermission");
permission.set(p);
}
}
return permission;
}
public static Permission[] buildFromMask(int[] masks) {
if ((masks == null) || (masks.length == 0)) {
return new Permission[] {};
}
List list = new Vector();
for (int i = 0; i < masks.length; i++) {
list.add(BasePermission.buildFromMask(masks[i]));
}
return (Permission[]) list.toArray(new Permission[] {});
}
public static Permission buildFromName(String name) {
Assert.isTrue(locallyDeclaredPermissionsByName.containsKey(name), "Unknown permission '" + name + "'");
return (Permission) locallyDeclaredPermissionsByName.get(name);
}
public static Permission[] buildFromName(String[] names) {
if ((names == null) || (names.length == 0)) {
return new Permission[] {};
}
List list = new Vector();
for (int i = 0; i < names.length; i++) {
list.add(BasePermission.buildFromName(names[i]));
}
return (Permission[]) list.toArray(new Permission[] {});
}
public boolean equals(Object arg0) {
if (!(arg0 instanceof BasePermission)) {
return false;
}
BasePermission rhs = (BasePermission) arg0;
return (this.mask == rhs.getMask());
}
public int getMask() {
return mask;
}
public String getPattern() {
return AclFormattingUtils.printBinary(mask, code);
}
public String toString() {
return "BasePermission[" + getPattern() + "=" + mask + "]";
}
}

View File

@ -1,46 +1,45 @@
/* 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.AccessControlEntry;
import org.acegisecurity.acls.AuditableAccessControlEntry;
import org.springframework.util.Assert;
/**
* DOCUMENT ME!
*
* @author $author$
* @version $Revision$
*/
public class ConsoleAuditLogger implements AuditLogger {
//~ Methods ========================================================================================================
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);
}
}
}
}
/* 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.AccessControlEntry;
import org.acegisecurity.acls.AuditableAccessControlEntry;
import org.springframework.util.Assert;
/**
* A bsaic implementation of {@link AuditLogger}.
*
* @author Ben Alex
* @version $Id$
*/
public class ConsoleAuditLogger implements AuditLogger {
//~ Methods ========================================================================================================
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);
}
}
}
}

View File

@ -1,79 +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.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 CumulativePermission clear() {
this.mask = 0;
this.pattern = THIRTY_TWO_RESERVED_OFF;
return this;
}
public boolean equals(Object arg0) {
if (!(arg0 instanceof CumulativePermission)) {
return false;
}
CumulativePermission rhs = (CumulativePermission) arg0;
return (this.mask == rhs.getMask());
}
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 + "]";
}
}
/* 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 CumulativePermission clear() {
this.mask = 0;
this.pattern = THIRTY_TWO_RESERVED_OFF;
return this;
}
public boolean equals(Object arg0) {
if (!(arg0 instanceof CumulativePermission)) {
return false;
}
CumulativePermission rhs = (CumulativePermission) arg0;
return (this.mask == rhs.getMask());
}
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 + "]";
}
}

View File

@ -0,0 +1,5 @@
<html>
<body>
Basic implementation of access control lists (ACLs) interfaces.
</body>
</html>

View File

@ -1,39 +1,42 @@
/* 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.domain.AclImpl;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
/* 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.MutableAcl;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import java.io.Serializable;
/**
* A caching layer for {@link JdbcAclService}.
*
* @author Ben Alex
* @version $Id$
*
*/
public interface AclCache {
//~ Methods ========================================================================================================
public void evictFromCache(Long pk);
public AclImpl getFromCache(ObjectIdentity objectIdentity);
public AclImpl getFromCache(Long pk);
public void putInCache(AclImpl acl); // should walk tree as well!
}
*/
public interface AclCache {
//~ Methods ========================================================================================================
public void evictFromCache(Serializable pk);
public void evictFromCache(ObjectIdentity objectIdentity);
public MutableAcl getFromCache(ObjectIdentity objectIdentity);
public MutableAcl getFromCache(Serializable pk);
public void putInCache(MutableAcl acl);
}

View File

@ -1,93 +1,115 @@
/* 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 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;
/**
* DOCUMENT ME!
*
* @author $author$
* @version $Revision$
*/
public class EhCacheBasedAclCache implements AclCache {
//~ Instance fields ================================================================================================
private Cache cache;
//~ Constructors ===================================================================================================
public EhCacheBasedAclCache(Cache cache) {
Assert.notNull(cache, "Cache required");
this.cache = cache;
}
//~ Methods ========================================================================================================
public void evictFromCache(Long pk) {
AclImpl acl = getFromCache(pk);
if (acl != null) {
cache.remove(pk);
cache.remove(acl.getObjectIdentity());
}
}
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));
}
}
/* 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 net.sf.ehcache.Cache;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.Element;
import org.acegisecurity.acls.MutableAcl;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.springframework.util.Assert;
import java.io.Serializable;
/**
* Simple implementation of {@link AclCache} that delegates to EH-CACHE.
*
* @author Ben Alex
* @version $Id$
*/
public class EhCacheBasedAclCache implements AclCache {
//~ Instance fields ================================================================================================
private Cache cache;
//~ Constructors ===================================================================================================
public EhCacheBasedAclCache(Cache cache) {
Assert.notNull(cache, "Cache required");
this.cache = cache;
}
//~ Methods ========================================================================================================
public void evictFromCache(Serializable pk) {
Assert.notNull(pk, "Primary key (identifier) required");
MutableAcl acl = getFromCache(pk);
if (acl != null) {
cache.remove(acl.getId());
cache.remove(acl.getObjectIdentity());
}
}
public void evictFromCache(ObjectIdentity objectIdentity) {
Assert.notNull(objectIdentity, "ObjectIdentity required");
MutableAcl acl = getFromCache(objectIdentity);
if (acl != null) {
cache.remove(acl.getId());
cache.remove(acl.getObjectIdentity());
}
}
public MutableAcl getFromCache(ObjectIdentity objectIdentity) {
Assert.notNull(objectIdentity, "ObjectIdentity required");
Element element = null;
try {
element = cache.get(objectIdentity);
} catch (CacheException ignored) {}
if (element == null) {
return null;
}
return (MutableAcl) element.getValue();
}
public MutableAcl getFromCache(Serializable pk) {
Assert.notNull(pk, "Primary key (identifier) required");
Element element = null;
try {
element = cache.get(pk);
} catch (CacheException ignored) {}
if (element == null) {
return null;
}
return (MutableAcl) element.getValue();
}
public void putInCache(MutableAcl acl) {
Assert.notNull(acl, "Acl required");
Assert.notNull(acl.getObjectIdentity(), "ObjectIdentity required");
Assert.notNull(acl.getId(), "ID required");
if ((acl.getParentAcl() != null) && (acl.getParentAcl() instanceof MutableAcl)) {
putInCache((MutableAcl) acl.getParentAcl());
}
cache.put(new Element(acl.getObjectIdentity(), acl));
cache.put(new Element(acl.getId(), acl));
}
}

View File

@ -0,0 +1,114 @@
/* 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.Acl;
import org.acegisecurity.acls.AclService;
import org.acegisecurity.acls.NotFoundException;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.objectidentity.ObjectIdentityImpl;
import org.acegisecurity.acls.sid.Sid;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.util.Assert;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
/**
* 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.</p>
*
* @author Ben Alex
* @version $Id$
*/
public class JdbcAclService implements AclService {
//~ Static fields/initializers =====================================================================================
protected static final Log log = LogFactory.getLog(JdbcAclService.class);
private static final String selectAclObjectWithParent = "SELECT obj.object_id_identity obj_id, class.class class "
+ "FROM acl_object_identity obj, acl_object_identity parent, acl_class class "
+ "WHERE obj.parent_object = parent.id AND obj.object_id_class = class.id "
+ "AND parent.object_id_identity = ? AND parent.object_id_class = ("
+ "SELECT id FROM acl_class WHERE acl_class.class = ?)";
//~ Instance fields ================================================================================================
protected JdbcTemplate jdbcTemplate;
private LookupStrategy lookupStrategy;
//~ Constructors ===================================================================================================
public JdbcAclService(DataSource dataSource, LookupStrategy lookupStrategy) {
Assert.notNull(dataSource, "DataSource required");
Assert.notNull(lookupStrategy, "LookupStrategy required");
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.lookupStrategy = lookupStrategy;
}
//~ Methods ========================================================================================================
public ObjectIdentity[] findChildren(ObjectIdentity parentIdentity) {
Object[] args = {parentIdentity.getIdentifier(), parentIdentity.getJavaType().getName()};
List objects = jdbcTemplate.query(selectAclObjectWithParent, args,
new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum)
throws SQLException {
String javaType = rs.getString("class");
String identifier = rs.getString("obj_id");
return new ObjectIdentityImpl(javaType, identifier);
}
});
return (ObjectIdentityImpl[]) objects.toArray(new ObjectIdentityImpl[] {});
}
public Acl readAclById(ObjectIdentity object, Sid[] sids)
throws NotFoundException {
Map map = readAclsById(new ObjectIdentity[] {object}, sids);
if (map.size() == 0) {
throw new NotFoundException("Could not find ACL");
} else {
return (Acl) map.get(object);
}
}
public Acl readAclById(ObjectIdentity object) throws NotFoundException {
return readAclById(object, null);
}
public Map readAclsById(ObjectIdentity[] objects) {
return readAclsById(objects, null);
}
public Map readAclsById(ObjectIdentity[] objects, Sid[] sids)
throws NotFoundException {
return lookupStrategy.readAclsById(objects, sids);
}
}

View File

@ -0,0 +1,368 @@
/* 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.Authentication;
import org.acegisecurity.acls.AccessControlEntry;
import org.acegisecurity.acls.Acl;
import org.acegisecurity.acls.AlreadyExistsException;
import org.acegisecurity.acls.ChildrenExistException;
import org.acegisecurity.acls.MutableAcl;
import org.acegisecurity.acls.MutableAclService;
import org.acegisecurity.acls.NotFoundException;
import org.acegisecurity.acls.domain.AccessControlEntryImpl;
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.acegisecurity.context.SecurityContextHolder;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
import java.lang.reflect.Array;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
import javax.sql.DataSource;
/**
* Provides a base implementation of {@link MutableAclService}.
*
* @author Ben Alex
* @author Johannes Zlattinger
* @version $Id$
*/
public class JdbcMutableAclService extends JdbcAclService implements MutableAclService {
//~ Instance fields ================================================================================================
private AclCache aclCache;
private String deleteClassByClassNameString = "DELETE FROM acl_class WHERE class=?";
private String deleteEntryByObjectIdentityForeignKey = "DELETE FROM acl_entry WHERE acl_object_identity=?";
private String deleteObjectIdentityByPrimaryKey = "DELETE FROM acl_object_identity WHERE id=?";
private String identityQuery = "call identity()";
private String insertClass = "INSERT INTO acl_class (id, class) VALUES (null, ?)";
private String insertEntry = "INSERT INTO acl_entry "
+ "(id, acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure)"
+ "VALUES (null, ?, ?, ?, ?, ?, ?, ?)";
private String insertObjectIdentity = "INSERT INTO acl_object_identity "
+ "(id, object_id_class, object_id_identity, owner_sid, entries_inheriting) " + "VALUES (null, ?, ?, ?, ?)";
private String insertSid = "INSERT INTO acl_sid (id, principal, sid) VALUES (null, ?, ?)";
private String selectClassPrimaryKey = "SELECT id FROM acl_class WHERE class=?";
private String selectCountObjectIdentityRowsForParticularClassNameString = "SELECT COUNT(acl_object_identity.id) "
+ "FROM acl_object_identity, acl_class WHERE acl_class.id = acl_object_identity.object_id_class and class=?";
private String selectObjectIdentityPrimaryKey = "SELECT acl_object_identity.id FROM acl_object_identity, acl_class "
+ "WHERE acl_object_identity.object_id_class = acl_class.id and acl_class.class=? "
+ "and acl_object_identity.object_id_identity = ?";
private String selectSidPrimaryKey = "SELECT id FROM acl_sid WHERE principal=? AND sid=?";
private String updateObjectIdentity = "UPDATE acl_object_identity SET "
+ "parent_object = ?, owner_sid = ?, entries_inheriting = ?" + "where id = ?";
//~ Constructors ===================================================================================================
public JdbcMutableAclService(DataSource dataSource, LookupStrategy lookupStrategy, AclCache aclCache) {
super(dataSource, lookupStrategy);
Assert.notNull(aclCache, "AclCache required");
this.aclCache = aclCache;
}
//~ Methods ========================================================================================================
public MutableAcl createAcl(ObjectIdentity objectIdentity)
throws AlreadyExistsException {
Assert.notNull(objectIdentity, "Object Identity required");
// Check this object identity hasn't already been persisted
if (retrieveObjectIdentityPrimaryKey(objectIdentity) != null) {
throw new AlreadyExistsException("Object identity '" + objectIdentity + "' already exists");
}
// Need to retrieve the current principal, in order to know who "owns" this ACL (can be changed later on)
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
PrincipalSid sid = new PrincipalSid(auth);
// Create the acl_object_identity row
createObjectIdentity(objectIdentity, sid);
// Retrieve the ACL via superclass (ensures cache registration, proper retrieval etc)
Acl acl = readAclById(objectIdentity);
Assert.isInstanceOf(MutableAcl.class, acl, "MutableAcl should be been returned");
return (MutableAcl) acl;
}
/**
* Creates a new row in acl_entry for every ACE defined in the passed MutableAcl object.
*
* @param acl containing the ACEs to insert
*/
protected void createEntries(final MutableAcl acl) {
jdbcTemplate.batchUpdate(insertEntry,
new BatchPreparedStatementSetter() {
public int getBatchSize() {
return acl.getEntries().length;
}
public void setValues(PreparedStatement stmt, int i)
throws SQLException {
AccessControlEntry entry_ = (AccessControlEntry) Array.get(acl.getEntries(), i);
Assert.isTrue(entry_ instanceof AccessControlEntryImpl, "Unknown ACE class");
AccessControlEntryImpl entry = (AccessControlEntryImpl) entry_;
stmt.setLong(1, ((Long) acl.getId()).longValue());
stmt.setInt(2, i);
stmt.setLong(3, createOrRetrieveSidPrimaryKey(entry.getSid(), true).longValue());
stmt.setInt(4, entry.getPermission().getMask());
stmt.setBoolean(5, entry.isGranting());
stmt.setBoolean(6, entry.isAuditSuccess());
stmt.setBoolean(7, entry.isAuditFailure());
}
});
}
/**
* Creates an entry in the acl_object_identity table for the passed ObjectIdentity. The Sid is also
* necessary, as acl_object_identity has defined the sid column as non-null.
*
* @param object to represent an acl_object_identity for
* @param owner for the SID column (will be created if there is no acl_sid entry for this particular Sid already)
*/
protected void createObjectIdentity(ObjectIdentity object, Sid owner) {
Long sidId = createOrRetrieveSidPrimaryKey(owner, true);
Long classId = createOrRetrieveClassPrimaryKey(object.getJavaType(), true);
jdbcTemplate.update(insertObjectIdentity,
new Object[] {classId, object.getIdentifier().toString(), sidId, new Boolean(true)});
}
/**
* Retrieves the primary key from acl_class, creating a new row if needed and the allowCreate property is
* true.
*
* @param clazz to find or create an entry for (this implementation uses the fully-qualified class name String)
* @param allowCreate true if creation is permitted if not found
*
* @return the primary key or null if not found
*/
protected Long createOrRetrieveClassPrimaryKey(Class clazz, boolean allowCreate) {
List classIds = jdbcTemplate.queryForList(selectClassPrimaryKey, new Object[] {clazz.getName()}, Long.class);
Long classId = null;
if (classIds.isEmpty()) {
if (allowCreate) {
classId = null;
jdbcTemplate.update(insertClass, new Object[] {clazz.getName()});
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
classId = new Long(jdbcTemplate.queryForLong(identityQuery));
}
} else {
classId = (Long) classIds.iterator().next();
}
return classId;
}
/**
* Retrieves the primary key from acl_sid, creating a new row if needed and the allowCreate property is
* true.
*
* @param sid to find or create
* @param allowCreate true if creation is permitted if not found
*
* @return the primary key or null if not found
*
* @throws IllegalArgumentException DOCUMENT ME!
*/
protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
Assert.notNull(sid, "Sid required");
String sidName = null;
boolean principal = true;
if (sid instanceof PrincipalSid) {
sidName = ((PrincipalSid) sid).getPrincipal();
} else if (sid instanceof GrantedAuthoritySid) {
sidName = ((GrantedAuthoritySid) sid).getGrantedAuthority();
principal = false;
} else {
throw new IllegalArgumentException("Unsupported implementation of Sid");
}
List sidIds = jdbcTemplate.queryForList(selectSidPrimaryKey, new Object[] {new Boolean(principal), sidName},
Long.class);
Long sidId = null;
if (sidIds.isEmpty()) {
if (allowCreate) {
sidId = null;
jdbcTemplate.update(insertSid, new Object[] {new Boolean(principal), sidName});
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
sidId = new Long(jdbcTemplate.queryForLong(identityQuery));
}
} else {
sidId = (Long) sidIds.iterator().next();
}
return sidId;
}
public void deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren)
throws ChildrenExistException {
Assert.notNull(objectIdentity, "Object Identity required");
Assert.notNull(objectIdentity.getIdentifier(), "Object Identity doesn't provide an identifier");
// Recursively call this method for children, or handle children if they don't want automatic recursion
ObjectIdentity[] children = findChildren(objectIdentity);
if (deleteChildren) {
for (int i = 0; i < children.length; i++) {
deleteAcl(children[i], true);
}
} else if (children.length > 0) {
throw new ChildrenExistException("Cannot delete '" + objectIdentity + "' (has " + children.length
+ " children)");
}
// Delete this ACL's ACEs in the acl_entry table
deleteEntries(objectIdentity);
// Delete this ACL's acl_object_identity row
deleteObjectIdentityAndOptionallyClass(objectIdentity);
// Clear the cache
aclCache.evictFromCache(objectIdentity);
}
/**
* Deletes all ACEs defined in the acl_entry table belonging to the presented ObjectIdentity
*
* @param oid the rows in acl_entry to delete
*/
protected void deleteEntries(ObjectIdentity oid) {
jdbcTemplate.update(deleteEntryByObjectIdentityForeignKey, new Object[] {retrieveObjectIdentityPrimaryKey(oid)});
}
/**
* Deletes a single row from acl_object_identity that is associated with the presented ObjectIdentity. In
* addition, deletes the corresponding row from acl_class if there are no more entries in acl_object_identity that
* use that particular acl_class. This keeps the acl_class table reasonably small.
*
* @param oid to delete the acl_object_identity (and clean up acl_class for that class name if appropriate)
*/
protected void deleteObjectIdentityAndOptionallyClass(ObjectIdentity oid) {
// Delete the acl_object_identity row
jdbcTemplate.update(deleteObjectIdentityByPrimaryKey, new Object[] {retrieveObjectIdentityPrimaryKey(oid)});
// Delete the acl_class row, assuming there are no other references to it in acl_object_identity
Object[] className = {oid.getJavaType().getName()};
long numObjectIdentities = jdbcTemplate.queryForLong(selectCountObjectIdentityRowsForParticularClassNameString,
className);
if (numObjectIdentities == 0) {
// No more rows
jdbcTemplate.update(deleteClassByClassNameString, className);
}
}
/**
* Retrieves the primary key from the acl_object_identity table for the passed ObjectIdentity. Unlike some
* other methods in this implementation, this method will NOT create a row (use {@link
* #createObjectIdentity(ObjectIdentity, Sid)} instead).
*
* @param oid to find
*
* @return the object identity or null if not found
*/
protected Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
try {
return new Long(jdbcTemplate.queryForLong(selectObjectIdentityPrimaryKey,
new Object[] {oid.getJavaType().getName(), oid.getIdentifier()}));
} catch (DataAccessException notFound) {
return null;
}
}
/**
* This implementation will simply delete all ACEs in the database and recreate them on each invocation of
* this method. A more comprehensive implementation might use dirty state checking, or more likely use ORM
* capabilities for create, update and delete operations of {@link MutableAcl}.
*
* @param acl DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws NotFoundException DOCUMENT ME!
*/
public MutableAcl updateAcl(MutableAcl acl) throws NotFoundException {
Assert.notNull(acl.getId(), "Object Identity doesn't provide an identifier");
// Delete this ACL's ACEs in the acl_entry table
deleteEntries(acl.getObjectIdentity());
// Create this ACL's ACEs in the acl_entry table
createEntries(acl);
// Change the mutable columns in acl_object_identity
updateObjectIdentity(acl);
// Clear the cache
aclCache.evictFromCache(acl.getObjectIdentity());
// Retrieve the ACL via superclass (ensures cache registration, proper retrieval etc)
return (MutableAcl) super.readAclById(acl.getObjectIdentity());
}
/**
* Updates an existing acl_object_identity row, with new information presented in the passed MutableAcl
* object. Also will create an acl_sid entry if needed for the Sid that owns the MutableAcl.
*
* @param acl to modify (a row must already exist in acl_object_identity)
*
* @throws NotFoundException DOCUMENT ME!
*/
protected void updateObjectIdentity(MutableAcl acl) {
Long parentId = null;
if (acl.getParentAcl() != null) {
Assert.isInstanceOf(ObjectIdentityImpl.class, acl.getParentAcl().getObjectIdentity(),
"Implementation only supports ObjectIdentityImpl");
ObjectIdentityImpl oii = (ObjectIdentityImpl) acl.getParentAcl().getObjectIdentity();
parentId = retrieveObjectIdentityPrimaryKey(oii);
}
Assert.notNull(acl.getOwner(), "Owner is required in this implementation");
Long ownerSid = createOrRetrieveSidPrimaryKey(acl.getOwner(), true);
int count = jdbcTemplate.update(updateObjectIdentity,
new Object[] {parentId, ownerSid, new Boolean(acl.isEntriesInheriting()), acl.getId()});
if (count != 1) {
throw new NotFoundException("Unable to locate ACL to update");
}
}
}

View File

@ -1,44 +1,43 @@
/* 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;
/* 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);
}
*/
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);
}

View File

@ -0,0 +1,5 @@
<html>
<body>
JDBC-based persistence of ACL information.
</body>
</html>

View File

@ -1,23 +1,22 @@
/* 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;
/* 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.
*
@ -32,40 +31,40 @@ import java.io.Serializable;
*
* @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();
}
*/
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();
}

View File

@ -1,146 +1,147 @@
/* 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;
/* 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;
}
/**
* 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
* Creates the <code>ObjectIdentityImpl</code> based on the passed
* object instance. The passed object must provide a <code>getId()</code>
* method, otherwise an exception will be thrown.
* method, otherwise an exception will be thrown. The object passed will
* be considered the {@link #javaType}, so if more control is required,
* an alternate constructor should be used instead.
*
* @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();
}
}
*/
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();
}
}

View File

@ -0,0 +1,30 @@
/* 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;
/**
* Strategy interface that provides the ability to determine which {@link ObjectIdentity}
* will be returned for a particular domain object
*
* @author Ben Alex
* @version $Id$
*
*/
public interface ObjectIdentityRetrievalStrategy {
//~ Methods ========================================================================================================
public ObjectIdentity getObjectIdentity(Object domainObject);
}

View File

@ -0,0 +1,31 @@
/* 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;
/**
* Basic implementation of {@link ObjectIdentityRetrievalStrategy} that uses the constructor of {@link
* ObjectIdentityImpl} to create the {@link ObjectIdentity}.
*
* @author Ben Alex
* @version $Id$
*/
public class ObjectIdentityRetrievalStrategyImpl implements ObjectIdentityRetrievalStrategy {
//~ Methods ========================================================================================================
public ObjectIdentity getObjectIdentity(Object domainObject) {
return new ObjectIdentityImpl(domainObject);
}
}

View File

@ -0,0 +1,5 @@
<html>
<body>
Provides indirection between ACL packages and domain objects.
</body>
</html>

View File

@ -0,0 +1,5 @@
<html>
<body>
Interfaces and shared classes to manage access control lists (ACLs) for domain object instances.
</body>
</html>

View File

@ -1,68 +1,67 @@
/* 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 + "]";
}
}
/* 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 + "]";
}
}

View File

@ -1,73 +1,72 @@
/* 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 + "]";
}
}
/* 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 + "]";
}
}

View File

@ -1,20 +1,19 @@
/* 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;
/* 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.
*
@ -29,23 +28,23 @@ package org.acegisecurity.acls.sid;
*
* @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();
}
*/
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();
}

View File

@ -0,0 +1,32 @@
/* 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;
/**
* Strategy interface that provides an ability to determine the {@link Sid} instances applicable
* for an {@link Authentication}.
*
* @author Ben Alex
* @version $Id$
*/
public interface SidRetrievalStrategy {
//~ Methods ========================================================================================================
public Sid[] getSids(Authentication authentication);
}

View File

@ -0,0 +1,48 @@
/* 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.GrantedAuthority;
import java.util.List;
import java.util.Vector;
/**
* Basic implementation of {@link SidRetrievalStrategy} that creates a {@link Sid} for the principal, as well as
* every granted authority the principal holds.<p>The returned array will always contain the {@link PrincipalSid}
* before any {@link GrantedAuthoritySid} elements.</p>
*
* @author Ben Alex
* @version $Id$
*/
public class SidRetrievalStrategyImpl implements SidRetrievalStrategy {
//~ Methods ========================================================================================================
public Sid[] getSids(Authentication authentication) {
List list = new Vector();
list.add(new PrincipalSid(authentication));
GrantedAuthority[] authorities = authentication.getAuthorities();
for (int i = 0; i < authorities.length; i++) {
list.add(new GrantedAuthoritySid(authorities[i]));
}
return (Sid[]) list.toArray(new Sid[] {});
}
}

View File

@ -0,0 +1,5 @@
<html>
<body>
Provides indirection between ACL packages and security identities, such as principals and GrantedAuthority[]s.
</body>
</html>

View File

@ -0,0 +1,130 @@
/* 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.afterinvocation;
import org.acegisecurity.Authentication;
import org.acegisecurity.ConfigAttribute;
import org.acegisecurity.acls.Acl;
import org.acegisecurity.acls.AclService;
import org.acegisecurity.acls.NotFoundException;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.domain.BasePermission;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.objectidentity.ObjectIdentityRetrievalStrategy;
import org.acegisecurity.acls.objectidentity.ObjectIdentityRetrievalStrategyImpl;
import org.acegisecurity.acls.sid.Sid;
import org.acegisecurity.acls.sid.SidRetrievalStrategy;
import org.acegisecurity.acls.sid.SidRetrievalStrategyImpl;
import org.springframework.util.Assert;
/**
* DOCUMENT ME!
*
* @author $author$
* @version $Revision$
*/
public abstract class AbstractAclProvider implements AfterInvocationProvider {
//~ Instance fields ================================================================================================
private AclService aclService;
private Class processDomainObjectClass = Object.class;
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
private String processConfigAttribute;
private Permission[] requirePermission = {BasePermission.READ};
//~ Constructors ===================================================================================================
public AbstractAclProvider(AclService aclService, String processConfigAttribute, Permission[] requirePermission) {
Assert.hasText(processConfigAttribute, "A processConfigAttribute is mandatory");
Assert.notNull(aclService, "An AclService is mandatory");
if ((requirePermission == null) || (requirePermission.length == 0)) {
throw new IllegalArgumentException("One or more requirePermission entries is mandatory");
}
this.aclService = aclService;
this.processConfigAttribute = processConfigAttribute;
this.requirePermission = requirePermission;
}
//~ Methods ========================================================================================================
protected Class getProcessDomainObjectClass() {
return processDomainObjectClass;
}
protected boolean hasPermission(Authentication authentication, Object domainObject) {
// Obtain the OID applicable to the domain object
ObjectIdentity objectIdentity = objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
// Obtain the SIDs applicable to the principal
Sid[] sids = sidRetrievalStrategy.getSids(authentication);
Acl acl = null;
try {
// Lookup only ACLs for SIDs we're interested in
acl = aclService.readAclById(objectIdentity, sids);
return acl.isGranted(requirePermission, sids, false);
} catch (NotFoundException ignore) {
return false;
}
}
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
Assert.notNull(objectIdentityRetrievalStrategy, "ObjectIdentityRetrievalStrategy required");
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
}
protected void setProcessConfigAttribute(String processConfigAttribute) {
Assert.hasText(processConfigAttribute, "A processConfigAttribute is mandatory");
this.processConfigAttribute = processConfigAttribute;
}
public void setProcessDomainObjectClass(Class processDomainObjectClass) {
Assert.notNull(processDomainObjectClass, "processDomainObjectClass cannot be set to null");
this.processDomainObjectClass = processDomainObjectClass;
}
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
this.sidRetrievalStrategy = sidRetrievalStrategy;
}
public boolean supports(ConfigAttribute attribute) {
if ((attribute.getAttribute() != null) && attribute.getAttribute().equals(this.processConfigAttribute)) {
return true;
} else {
return false;
}
}
/**
* This implementation supports any type of class, because it does not query the presented secure object.
*
* @param clazz the secure object
*
* @return always <code>true</code>
*/
public boolean supports(Class clazz) {
return true;
}
}

View File

@ -0,0 +1,133 @@
/* 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.afterinvocation;
import org.acegisecurity.AccessDeniedException;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthorizationServiceException;
import org.acegisecurity.ConfigAttribute;
import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.acls.Acl;
import org.acegisecurity.acls.AclService;
import org.acegisecurity.acls.Permission;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.Collection;
import java.util.Iterator;
/**
* <p>Given a <code>Collection</code> of domain object instances returned from a secure object invocation, remove
* any <code>Collection</code> elements the principal does not have appropriate permission to access as defined by the
* {@link AclService}.</p>
* <p>The <code>AclService</code> is used to retrieve the access control list (ACL) permissions associated with
* each <code>Collection</code> domain object instance element for the current <code>Authentication</code> object.</p>
* <p>This after invocation provider will fire if any {@link ConfigAttribute#getAttribute()} matches the {@link
* #processConfigAttribute}. The provider will then lookup the ACLs from the <code>AclService</code> and ensure the
* principal is {@link Acl#isGranted(org.acegisecurity.acls.Permission[], org.acegisecurity.acls.sid.Sid[], boolean)}
* when presenting the {@link #requirePermission} array to that method.</p>
* <p>If the principal does not have permission, that element will not be included in the returned
* <code>Collection</code>.</p>
* <p>Often users will setup a <code>BasicAclEntryAfterInvocationProvider</code> with a {@link
* #processConfigAttribute} of <code>AFTER_ACL_COLLECTION_READ</code> and a {@link #requirePermission} of
* <code>BasePermission.READ</code>. These are also the defaults.</p>
* <p>If the provided <code>returnObject</code> is <code>null</code>, a <code>null</code><code>Collection</code>
* will be returned. If the provided <code>returnObject</code> is not a <code>Collection</code>, an {@link
* AuthorizationServiceException} will be thrown.</p>
* <p>All comparisons and prefixes are case sensitive.</p>
*
* @author Ben Alex
* @author Paulo Neves
* @version $Id$
*/
public class AclEntryAfterInvocationCollectionFilteringProvider extends AbstractAclProvider {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationCollectionFilteringProvider.class);
//~ Constructors ===================================================================================================
public AclEntryAfterInvocationCollectionFilteringProvider(AclService aclService, Permission[] requirePermission) {
super(aclService, "AFTER_ACL_COLLECTION_READ", requirePermission);
}
//~ Methods ========================================================================================================
public Object decide(Authentication authentication, Object object, ConfigAttributeDefinition config,
Object returnedObject) throws AccessDeniedException {
Iterator iter = config.getConfigAttributes();
while (iter.hasNext()) {
ConfigAttribute attr = (ConfigAttribute) iter.next();
if (this.supports(attr)) {
// Need to process the Collection for this invocation
if (returnedObject == null) {
if (logger.isDebugEnabled()) {
logger.debug("Return object is null, skipping");
}
return null;
}
Filterer filterer = null;
if (returnedObject instanceof Collection) {
Collection collection = (Collection) returnedObject;
filterer = new CollectionFilterer(collection);
} else if (returnedObject.getClass().isArray()) {
Object[] array = (Object[]) returnedObject;
filterer = new ArrayFilterer(array);
} else {
throw new AuthorizationServiceException(
"A Collection or an array (or null) was required as the returnedObject, but the returnedObject was: "
+ returnedObject);
}
// Locate unauthorised Collection elements
Iterator collectionIter = filterer.iterator();
while (collectionIter.hasNext()) {
Object domainObject = collectionIter.next();
boolean hasPermission = false;
if (domainObject == null) {
hasPermission = true;
} else if (!getProcessDomainObjectClass().isAssignableFrom(domainObject.getClass())) {
hasPermission = true;
} else {
hasPermission = hasPermission(authentication, domainObject);
if (!hasPermission) {
filterer.remove(domainObject);
if (logger.isDebugEnabled()) {
logger.debug("Principal is NOT authorised for element: " + domainObject);
}
}
}
}
return filterer.getFilteredObject();
}
}
return returnedObject;
}
}

View File

@ -0,0 +1,119 @@
/* 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.afterinvocation;
import org.acegisecurity.AccessDeniedException;
import org.acegisecurity.AcegiMessageSource;
import org.acegisecurity.Authentication;
import org.acegisecurity.ConfigAttribute;
import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.acls.Acl;
import org.acegisecurity.acls.AclService;
import org.acegisecurity.acls.Permission;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor;
import java.util.Iterator;
/**
* <p>Given a domain object instance returned from a secure object invocation, ensures the principal has
* appropriate permission as defined by the {@link AclService}.</p>
* <p>The <code>AclService</code> is used to retrieve the access control list (ACL) permissions associated with a
* domain object instance for the current <code>Authentication</code> object.</p>
* <p>This after invocation provider will fire if any {@link ConfigAttribute#getAttribute()} matches the {@link
* #processConfigAttribute}. The provider will then lookup the ACLs from the <code>AclService</code> and ensure the
* principal is {@link Acl#isGranted(org.acegisecurity.acls.Permission[], org.acegisecurity.acls.sid.Sid[], boolean)}
* when presenting the {@link #requirePermission} array to that method.</p>
* <p>Often users will setup an <code>AclEntryAfterInvocationProvider</code> with a {@link
* #processConfigAttribute} of <code>AFTER_ACL_READ</code> and a {@link #requirePermission} of
* <code>BasePermission.READ</code>. These are also the defaults.</p>
* <p>If the principal does not have sufficient permissions, an <code>AccessDeniedException</code> will be thrown.</p>
* <p>If the provided <code>returnObject</code> is <code>null</code>, permission will always be granted and
* <code>null</code> will be returned.</p>
* <p>All comparisons and prefixes are case sensitive.</p>
*/
public class AclEntryAfterInvocationProvider extends AbstractAclProvider implements MessageSourceAware {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationProvider.class);
//~ Instance fields ================================================================================================
protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
//~ Constructors ===================================================================================================
public AclEntryAfterInvocationProvider(AclService aclService, Permission[] requirePermission) {
super(aclService, "AFTER_ACL_READ", requirePermission);
}
//~ Methods ========================================================================================================
public Object decide(Authentication authentication, Object object, ConfigAttributeDefinition config,
Object returnedObject) throws AccessDeniedException {
Iterator iter = config.getConfigAttributes();
while (iter.hasNext()) {
ConfigAttribute attr = (ConfigAttribute) iter.next();
if (this.supports(attr)) {
// Need to make an access decision on this invocation
if (returnedObject == null) {
// AclManager interface contract prohibits nulls
// As they have permission to null/nothing, grant access
if (logger.isDebugEnabled()) {
logger.debug("Return object is null, skipping");
}
return null;
}
if (!getProcessDomainObjectClass().isAssignableFrom(returnedObject.getClass())) {
if (logger.isDebugEnabled()) {
logger.debug("Return object is not applicable for this provider, skipping");
}
return null;
}
if (hasPermission(authentication, returnedObject)) {
return returnedObject;
} else {
if (logger.isDebugEnabled()) {
logger.debug("Denying access");
}
throw new AccessDeniedException(messages.getMessage(
"BasicAclEntryAfterInvocationProvider.noPermission",
new Object[] {authentication.getName(), returnedObject},
"Authentication {0} has NO permissions to the domain object {1}"));
}
}
}
return returnedObject;
}
public void setMessageSource(MessageSource messages) {
this.messages = new MessageSourceAccessor(messages);
}
}

View File

@ -0,0 +1,101 @@
/* 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.afterinvocation;
import org.apache.commons.collections.iterators.ArrayIterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.lang.reflect.Array;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* A filter used to filter arrays.
*
* @author Ben Alex
* @author Paulo Neves
* @version $Id$
*/
class ArrayFilterer implements Filterer {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(BasicAclEntryAfterInvocationCollectionFilteringProvider.class);
//~ Instance fields ================================================================================================
private Set removeList;
private Object[] list;
//~ Constructors ===================================================================================================
ArrayFilterer(Object[] list) {
this.list = list;
// Collect the removed objects to a HashSet so that
// it is fast to lookup them when a filtered array
// is constructed.
removeList = new HashSet();
}
//~ Methods ========================================================================================================
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#getFilteredObject()
*/
public Object getFilteredObject() {
// Recreate an array of same type and filter the removed objects.
int originalSize = list.length;
int sizeOfResultingList = originalSize - removeList.size();
Object[] filtered = (Object[]) Array.newInstance(list.getClass().getComponentType(), sizeOfResultingList);
for (int i = 0, j = 0; i < list.length; i++) {
Object object = list[i];
if (!removeList.contains(object)) {
filtered[j] = object;
j++;
}
}
if (logger.isDebugEnabled()) {
logger.debug("Original array contained " + originalSize + " elements; now contains " + sizeOfResultingList
+ " elements");
}
return filtered;
}
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#iterator()
*/
public Iterator iterator() {
return new ArrayIterator(list);
}
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#remove(java.lang.Object)
*/
public void remove(Object object) {
removeList.add(object);
}
}

View File

@ -12,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.afterinvocation;
import org.acegisecurity.AccessDeniedException;
@ -26,7 +25,6 @@ import org.acegisecurity.acl.AclManager;
import org.acegisecurity.acl.basic.BasicAclEntry;
import org.acegisecurity.acl.basic.SimpleAclEntry;
import org.apache.commons.collections.iterators.ArrayIterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@ -34,12 +32,8 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
@ -135,42 +129,40 @@ public class BasicAclEntryAfterInvocationCollectionFilteringProvider implements
boolean hasPermission = false;
AclEntry[] acls = null;
if (domainObject == null) {
hasPermission = true;
} else if (!processDomainObjectClass.isAssignableFrom(domainObject.getClass())) {
hasPermission = true;
} else {
acls = aclManager.getAcls(domainObject, authentication);
}
AclEntry[] acls = aclManager.getAcls(domainObject, authentication);
if ((acls != null) && (acls.length != 0)) {
for (int i = 0; i < acls.length; i++) {
// Locate processable AclEntrys
if (acls[i] instanceof BasicAclEntry) {
BasicAclEntry processableAcl = (BasicAclEntry) acls[i];
if ((acls != null) && (acls.length != 0)) {
for (int i = 0; i < acls.length; i++) {
// Locate processable AclEntrys
if (acls[i] instanceof BasicAclEntry) {
BasicAclEntry processableAcl = (BasicAclEntry) acls[i];
// See if principal has any of the required permissions
for (int y = 0; y < requirePermission.length; y++) {
if (processableAcl.isPermitted(requirePermission[y])) {
hasPermission = true;
// See if principal has any of the required permissions
for (int y = 0; y < requirePermission.length; y++) {
if (processableAcl.isPermitted(requirePermission[y])) {
hasPermission = true;
if (logger.isDebugEnabled()) {
logger.debug("Principal is authorised for element: " + domainObject
+ " due to ACL: " + processableAcl.toString());
if (logger.isDebugEnabled()) {
logger.debug("Principal is authorised for element: " + domainObject
+ " due to ACL: " + processableAcl.toString());
}
}
}
}
}
}
}
if (!hasPermission) {
filterer.remove(domainObject);
if (!hasPermission) {
filterer.remove(domainObject);
if (logger.isDebugEnabled()) {
logger.debug("Principal is NOT authorised for element: " + domainObject);
if (logger.isDebugEnabled()) {
logger.debug("Principal is NOT authorised for element: " + domainObject);
}
}
}
}
@ -212,9 +204,11 @@ public class BasicAclEntryAfterInvocationCollectionFilteringProvider implements
}
/**
* Allow setting permissions with String literals instead of integers as {@link #setRequirePermission(int[])}
*
* Allow setting permissions with String literals instead of integers as {@link
* #setRequirePermission(int[])}
*
* @param requirePermission permission literals
*
* @see SimpleAclEntry#parsePermissions(String[]) for valid values
*/
public void setRequirePermissionFromString(String[] requirePermission) {
@ -240,179 +234,3 @@ public class BasicAclEntryAfterInvocationCollectionFilteringProvider implements
return true;
}
}
/**
* Filter strategy interface.
*/
interface Filterer {
//~ Methods ========================================================================================================
/**
* Gets the filtered collection or array.
*
* @return the filtered collection or array
*/
public Object getFilteredObject();
/**
* Returns an iterator over the filtered collection or array.
*
* @return an Iterator
*/
public Iterator iterator();
/**
* Removes the the given object from the resulting list.
*
* @param object the object to be removed
*/
public void remove(Object object);
}
/**
* A filter used to filter Collections.
*/
class CollectionFilterer implements Filterer {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(BasicAclEntryAfterInvocationCollectionFilteringProvider.class);
//~ Instance fields ================================================================================================
private Collection collection;
// collectionIter offers significant performance optimisations (as
// per acegisecurity-developer mailing list conversation 19/5/05)
private Iterator collectionIter;
private Set removeList;
//~ Constructors ===================================================================================================
CollectionFilterer(Collection collection) {
this.collection = collection;
// We create a Set of objects to be removed from the Collection,
// as ConcurrentModificationException prevents removal during
// iteration, and making a new Collection to be returned is
// problematic as the original Collection implementation passed
// to the method may not necessarily be re-constructable (as
// the Collection(collection) constructor is not guaranteed and
// manually adding may lose sort order or other capabilities)
removeList = new HashSet();
}
//~ Methods ========================================================================================================
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#getFilteredObject()
*/
public Object getFilteredObject() {
// Now the Iterator has ended, remove Objects from Collection
Iterator removeIter = removeList.iterator();
int originalSize = collection.size();
while (removeIter.hasNext()) {
collection.remove(removeIter.next());
}
if (logger.isDebugEnabled()) {
logger.debug("Original collection contained " + originalSize + " elements; now contains "
+ collection.size() + " elements");
}
return collection;
}
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#iterator()
*/
public Iterator iterator() {
collectionIter = collection.iterator();
return collectionIter;
}
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#remove(java.lang.Object)
*/
public void remove(Object object) {
removeList.add(object);
}
}
/**
* A filter used to filter arrays.
*/
class ArrayFilterer implements Filterer {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(BasicAclEntryAfterInvocationCollectionFilteringProvider.class);
//~ Instance fields ================================================================================================
private Set removeList;
private Object[] list;
//~ Constructors ===================================================================================================
ArrayFilterer(Object[] list) {
this.list = list;
// Collect the removed objects to a HashSet so that
// it is fast to lookup them when a filtered array
// is constructed.
removeList = new HashSet();
}
//~ Methods ========================================================================================================
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#getFilteredObject()
*/
public Object getFilteredObject() {
// Recreate an array of same type and filter the removed objects.
int originalSize = list.length;
int sizeOfResultingList = originalSize - removeList.size();
Object[] filtered = (Object[]) Array.newInstance(list.getClass().getComponentType(), sizeOfResultingList);
for (int i = 0, j = 0; i < list.length; i++) {
Object object = list[i];
if (!removeList.contains(object)) {
filtered[j] = object;
j++;
}
}
if (logger.isDebugEnabled()) {
logger.debug("Original array contained " + originalSize + " elements; now contains " + sizeOfResultingList
+ " elements");
}
return filtered;
}
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#iterator()
*/
public Iterator iterator() {
return new ArrayIterator(list);
}
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#remove(java.lang.Object)
*/
public void remove(Object object) {
removeList.add(object);
}
}

View File

@ -0,0 +1,104 @@
/* 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.afterinvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* A filter used to filter Collections.
*
* @author Ben Alex
* @author Paulo Neves
* @version $Id$
*/
class CollectionFilterer implements Filterer {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(BasicAclEntryAfterInvocationCollectionFilteringProvider.class);
//~ Instance fields ================================================================================================
private Collection collection;
// collectionIter offers significant performance optimisations (as
// per acegisecurity-developer mailing list conversation 19/5/05)
private Iterator collectionIter;
private Set removeList;
//~ Constructors ===================================================================================================
CollectionFilterer(Collection collection) {
this.collection = collection;
// We create a Set of objects to be removed from the Collection,
// as ConcurrentModificationException prevents removal during
// iteration, and making a new Collection to be returned is
// problematic as the original Collection implementation passed
// to the method may not necessarily be re-constructable (as
// the Collection(collection) constructor is not guaranteed and
// manually adding may lose sort order or other capabilities)
removeList = new HashSet();
}
//~ Methods ========================================================================================================
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#getFilteredObject()
*/
public Object getFilteredObject() {
// Now the Iterator has ended, remove Objects from Collection
Iterator removeIter = removeList.iterator();
int originalSize = collection.size();
while (removeIter.hasNext()) {
collection.remove(removeIter.next());
}
if (logger.isDebugEnabled()) {
logger.debug("Original collection contained " + originalSize + " elements; now contains "
+ collection.size() + " elements");
}
return collection;
}
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#iterator()
*/
public Iterator iterator() {
collectionIter = collection.iterator();
return collectionIter;
}
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#remove(java.lang.Object)
*/
public void remove(Object object) {
removeList.add(object);
}
}

View File

@ -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.afterinvocation;
import java.util.Iterator;
/**
* Filter strategy interface.
*
* @author Ben Alex
* @author Paulo Neves
* @version $Id$
*/
interface Filterer {
//~ Methods ========================================================================================================
/**
* Gets the filtered collection or array.
*
* @return the filtered collection or array
*/
public Object getFilteredObject();
/**
* Returns an iterator over the filtered collection or array.
*
* @return an Iterator
*/
public Iterator iterator();
/**
* Removes the the given object from the resulting list.
*
* @param object the object to be removed
*/
public void remove(Object object);
}

View File

@ -0,0 +1,223 @@
/* 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.taglibs.authz;
import org.acegisecurity.acls.Acl;
import org.acegisecurity.acls.AclService;
import org.acegisecurity.acls.NotFoundException;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.domain.BasePermission;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.objectidentity.ObjectIdentityRetrievalStrategy;
import org.acegisecurity.acls.objectidentity.ObjectIdentityRetrievalStrategyImpl;
import org.acegisecurity.acls.sid.Sid;
import org.acegisecurity.acls.sid.SidRetrievalStrategy;
import org.acegisecurity.acls.sid.SidRetrievalStrategyImpl;
import org.acegisecurity.context.SecurityContextHolder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.util.ExpressionEvaluationUtils;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import javax.servlet.ServletContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;
/**
* An implementation of {@link javax.servlet.jsp.tagext.Tag} that allows its body through if some authorizations
* are granted to the request's principal.<p>One or more comma separate numeric are specified via the
* <code>hasPermission</code> attribute. Those permissions are then converted into {@link Permission} instances. These
* instances are then presented as an array to the {@link Acl#isGranted(Permission[],
* org.acegisecurity.acls.sid.Sid[], boolean)} method. The {@link Sid} presented is determined by the {@link
* SidRetrievalStrategy}.</p>
* <p>For this class to operate it must be able to access the application context via the
* <code>WebApplicationContextUtils</code> and locate an {@link AclService} and {@link SidRetrievalStrategy}.
* Application contexts must provide one and only one of these Java types.</p>
*
* @author Ben Alex
* @version $Id$
*/
public class AccessControlListTag extends TagSupport {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(AccessControlListTag.class);
//~ Instance fields ================================================================================================
private AclService aclService;
private ApplicationContext applicationContext;
private Object domainObject;
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy;
private SidRetrievalStrategy sidRetrievalStrategy;
private String hasPermission = "";
//~ Methods ========================================================================================================
public int doStartTag() throws JspException {
initializeIfRequired();
if ((null == hasPermission) || "".equals(hasPermission)) {
return Tag.SKIP_BODY;
}
final String evaledPermissionsString = ExpressionEvaluationUtils.evaluateString("hasPermission", hasPermission,
pageContext);
Permission[] requiredPermissions = null;
try {
requiredPermissions = parsePermissionsString(evaledPermissionsString);
} catch (NumberFormatException nfe) {
throw new JspException(nfe);
}
Object resolvedDomainObject = null;
if (domainObject instanceof String) {
resolvedDomainObject = ExpressionEvaluationUtils.evaluate("domainObject", (String) domainObject,
Object.class, pageContext);
} else {
resolvedDomainObject = domainObject;
}
if (resolvedDomainObject == null) {
if (logger.isDebugEnabled()) {
logger.debug("domainObject resolved to null, so including tag body");
}
// Of course they have access to a null object!
return Tag.EVAL_BODY_INCLUDE;
}
if (SecurityContextHolder.getContext().getAuthentication() == null) {
if (logger.isDebugEnabled()) {
logger.debug(
"SecurityContextHolder did not return a non-null Authentication object, so skipping tag body");
}
return Tag.SKIP_BODY;
}
Sid[] sids = sidRetrievalStrategy.getSids(SecurityContextHolder.getContext().getAuthentication());
ObjectIdentity oid = objectIdentityRetrievalStrategy.getObjectIdentity(resolvedDomainObject);
// Obtain aclEntrys applying to the current Authentication object
try {
Acl acl = aclService.readAclById(oid, sids);
if (acl.isGranted(requiredPermissions, sids, false)) {
return Tag.EVAL_BODY_INCLUDE;
} else {
return Tag.SKIP_BODY;
}
} catch (NotFoundException nfe) {
return Tag.SKIP_BODY;
}
}
/**
* Allows test cases to override where application context obtained from.
*
* @param pageContext so the <code>ServletContext</code> can be accessed as required by Spring's
* <code>WebApplicationContextUtils</code>
*
* @return the Spring application context (never <code>null</code>)
*/
protected ApplicationContext getContext(PageContext pageContext) {
ServletContext servletContext = pageContext.getServletContext();
return WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
}
public Object getDomainObject() {
return domainObject;
}
public String getHasPermission() {
return hasPermission;
}
private void initializeIfRequired() throws JspException {
if (applicationContext == null) {
this.applicationContext = getContext(pageContext);
Map map = applicationContext.getBeansOfType(AclService.class);
if (map.size() != 1) {
throw new JspException(
"Found incorrect number of AclService instances in application context - you must have only have one!");
}
aclService = (AclService) map.values().iterator().next();
map = applicationContext.getBeansOfType(SidRetrievalStrategy.class);
if (map.size() == 0) {
sidRetrievalStrategy = new SidRetrievalStrategyImpl();
} else if (map.size() == 1) {
sidRetrievalStrategy = (SidRetrievalStrategy) map.values().iterator().next();
} else {
throw new JspException(
"Found incorrect number of SidRetrievalStrategy instances in application context - you must have only have one!");
}
map = applicationContext.getBeansOfType(ObjectIdentityRetrievalStrategy.class);
if (map.size() == 0) {
objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
} else if (map.size() == 1) {
objectIdentityRetrievalStrategy = (ObjectIdentityRetrievalStrategy) map.values().iterator().next();
} else {
throw new JspException(
"Found incorrect number of ObjectIdentityRetrievalStrategy instances in application context - you must have only have one!");
}
}
}
private Permission[] parsePermissionsString(String integersString)
throws NumberFormatException {
final Set permissions = new HashSet();
final StringTokenizer tokenizer;
tokenizer = new StringTokenizer(integersString, ",", false);
while (tokenizer.hasMoreTokens()) {
String integer = tokenizer.nextToken();
permissions.add(BasePermission.buildFromMask(new Integer(integer).intValue()));
}
return (Permission[]) permissions.toArray(new Permission[] {});
}
public void setDomainObject(Object domainObject) {
this.domainObject = domainObject;
}
public void setHasPermission(String hasPermission) {
this.hasPermission = hasPermission;
}
}

View File

@ -12,13 +12,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.vote;
import org.acegisecurity.AuthorizationServiceException;
import org.acegisecurity.acl.AclManager;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.JoinPoint;
@ -28,8 +25,7 @@ import org.springframework.util.Assert;
/**
* <p>Given a domain object instance passed as a method argument, ensures the principal has appropriate permission
* as defined by the {@link AclManager}.</p>
* <p>Provides helper methods for writing domain object ACL voters. Is not bound to any particular ACL system.</p>
*
* @author Ben Alex
* @version $Id$

View File

@ -0,0 +1,251 @@
/* 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.vote;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthorizationServiceException;
import org.acegisecurity.ConfigAttribute;
import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.acls.Acl;
import org.acegisecurity.acls.AclService;
import org.acegisecurity.acls.NotFoundException;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.objectidentity.ObjectIdentityRetrievalStrategy;
import org.acegisecurity.acls.objectidentity.ObjectIdentityRetrievalStrategyImpl;
import org.acegisecurity.acls.sid.Sid;
import org.acegisecurity.acls.sid.SidRetrievalStrategy;
import org.acegisecurity.acls.sid.SidRetrievalStrategyImpl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
/**
* <p>Given a domain object instance passed as a method argument, ensures the principal has appropriate permission
* as indicated by the {@link AclService}.</p>
* <p>The <code>AclService</code> is used to retrieve the access control list (ACL) permissions associated with a
* domain object instance for the current <code>Authentication</code> object.</p>
* <p>The voter will vote if any {@link ConfigAttribute#getAttribute()} matches the {@link
* #processConfigAttribute}. The provider will then locate the first method argument of type {@link
* #processDomainObjectClass}. Assuming that method argument is non-null, the provider will then lookup the ACLs from
* the <code>AclManager</code> and ensure the principal is {@link Acl#isGranted(org.acegisecurity.acls.Permission[],
* org.acegisecurity.acls.sid.Sid[], boolean)} when presenting the {@link #requirePermission} array to that method.</p>
* <p>If the method argument is <code>null</code>, the voter will abstain from voting. If the method argument
* could not be found, an {@link org.acegisecurity.AuthorizationServiceException} will be thrown.</p>
* <p>In practical terms users will typically setup a number of <code>AclEntryVoter</code>s. Each will have a
* different {@link #processDomainObjectClass}, {@link #processConfigAttribute} and {@link #requirePermission}
* combination. For example, a small application might employ the following instances of <code>AclEntryVoter</code>:
* <ul>
* <li>Process domain object class <code>BankAccount</code>, configuration attribute
* <code>VOTE_ACL_BANK_ACCONT_READ</code>, require permission <code>BasePermission.READ</code></li>
* <li>Process domain object class <code>BankAccount</code>, configuration attribute
* <code>VOTE_ACL_BANK_ACCOUNT_WRITE</code>, require permission list <code>BasePermission.WRITE</code> and
* <code>BasePermission.CREATE</code> (allowing the principal to have <b>either</b> of these two permissions</li>
* <li>Process domain object class <code>Customer</code>, configuration attribute
* <code>VOTE_ACL_CUSTOMER_READ</code>, require permission <code>BasePermission.READ</code></li>
* <li>Process domain object class <code>Customer</code>, configuration attribute
* <code>VOTE_ACL_CUSTOMER_WRITE</code>, require permission list <code>BasePermission.WRITE</code> and
* <code>BasePermission.CREATE</code></li>
* </ul>
* Alternatively, you could have used a common superclass or interface for the {@link #processDomainObjectClass}
* if both <code>BankAccount</code> and <code>Customer</code> had common parents.</p>
* <p>If the principal does not have sufficient permissions, the voter will vote to deny access.</p>
* <p>All comparisons and prefixes are case sensitive.</p>
*
* @author Ben Alex
* @version $Id$
*/
public class AclEntryVoter extends AbstractAclVoter {
//~ Static fields/initializers =====================================================================================
private static final Log logger = LogFactory.getLog(AclEntryVoter.class);
//~ Instance fields ================================================================================================
private AclService aclService;
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
private String internalMethod;
private String processConfigAttribute;
private Permission[] requirePermission;
//~ Constructors ===================================================================================================
public AclEntryVoter(AclService aclService, String processConfigAttribute, Permission[] requirePermission) {
Assert.notNull(processConfigAttribute, "A processConfigAttribute is mandatory");
Assert.notNull(aclService, "An AclService is mandatory");
if ((requirePermission == null) || (requirePermission.length == 0)) {
throw new IllegalArgumentException("One or more requirePermission entries is mandatory");
}
this.aclService = aclService;
this.processConfigAttribute = processConfigAttribute;
this.requirePermission = requirePermission;
}
//~ Methods ========================================================================================================
/**
* Optionally specifies a method of the domain object that will be used to obtain a contained domain
* object. That contained domain object will be used for the ACL evaluation. This is useful if a domain object
* contains a parent that an ACL evaluation should be targeted for, instead of the child domain object (which
* perhaps is being created and as such does not yet have any ACL permissions)
*
* @return <code>null</code> to use the domain object, or the name of a method (that requires no arguments) that
* should be invoked to obtain an <code>Object</code> which will be the domain object used for ACL
* evaluation
*/
public String getInternalMethod() {
return internalMethod;
}
public String getProcessConfigAttribute() {
return processConfigAttribute;
}
public void setInternalMethod(String internalMethod) {
this.internalMethod = internalMethod;
}
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
Assert.notNull(objectIdentityRetrievalStrategy, "ObjectIdentityRetrievalStrategy required");
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
}
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
this.sidRetrievalStrategy = sidRetrievalStrategy;
}
public boolean supports(ConfigAttribute attribute) {
if ((attribute.getAttribute() != null) && attribute.getAttribute().startsWith(getProcessConfigAttribute())) {
return true;
} else {
return false;
}
}
public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {
Iterator iter = config.getConfigAttributes();
while (iter.hasNext()) {
ConfigAttribute attr = (ConfigAttribute) iter.next();
if (this.supports(attr)) {
// Need to make an access decision on this invocation
// Attempt to locate the domain object instance to process
Object domainObject = getDomainObjectInstance(object);
// If domain object is null, vote to abstain
if (domainObject == null) {
if (logger.isDebugEnabled()) {
logger.debug("Voting to abstain - domainObject is null");
}
return AccessDecisionVoter.ACCESS_ABSTAIN;
}
// Evaluate if we are required to use an inner domain object
if ((internalMethod != null) && !"".equals(internalMethod)) {
try {
Class clazz = domainObject.getClass();
Method method = clazz.getMethod(internalMethod, new Class[] {});
domainObject = method.invoke(domainObject, new Object[] {});
} catch (NoSuchMethodException nsme) {
throw new AuthorizationServiceException("Object of class '" + domainObject.getClass()
+ "' does not provide the requested internalMethod: " + internalMethod);
} catch (IllegalAccessException iae) {
if (logger.isDebugEnabled()) {
logger.debug("IllegalAccessException", iae);
if (iae.getCause() != null) {
logger.debug("Cause: " + iae.getCause().getMessage(), iae.getCause());
}
}
throw new AuthorizationServiceException("Problem invoking internalMethod: " + internalMethod
+ " for object: " + domainObject);
} catch (InvocationTargetException ite) {
if (logger.isDebugEnabled()) {
logger.debug("InvocationTargetException", ite);
if (ite.getCause() != null) {
logger.debug("Cause: " + ite.getCause().getMessage(), ite.getCause());
}
}
throw new AuthorizationServiceException("Problem invoking internalMethod: " + internalMethod
+ " for object: " + domainObject);
}
}
// Obtain the OID applicable to the domain object
ObjectIdentity objectIdentity = objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
// Obtain the SIDs applicable to the principal
Sid[] sids = sidRetrievalStrategy.getSids(authentication);
Acl acl;
try {
// Lookup only ACLs for SIDs we're interested in
acl = aclService.readAclById(objectIdentity, sids);
} catch (NotFoundException nfe) {
if (logger.isDebugEnabled()) {
logger.debug("Voting to deny access - no ACLs apply for this principal");
}
return AccessDecisionVoter.ACCESS_DENIED;
}
try {
if (acl.isGranted(requirePermission, sids, false)) {
if (logger.isDebugEnabled()) {
logger.debug("Voting to grant access");
}
return AccessDecisionVoter.ACCESS_GRANTED;
} else {
if (logger.isDebugEnabled()) {
logger.debug(
"Voting to deny access - ACLs returned, but insufficient permissions for this principal");
}
return AccessDecisionVoter.ACCESS_DENIED;
}
} catch (NotFoundException nfe) {
if (logger.isDebugEnabled()) {
logger.debug("Voting to deny access - no ACLs apply for this principal");
}
return AccessDecisionVoter.ACCESS_DENIED;
}
}
}
// No configuration attribute matched, so abstain
return AccessDecisionVoter.ACCESS_ABSTAIN;
}
}

View File

@ -113,4 +113,34 @@
</attribute>
</tag>
<tag>
<name>accesscontrollist</name>
<tag-class>org.acegisecurity.taglibs.authz.AccessControlListTag</tag-class>
<description>
Allows inclusion of a tag body if the current Authentication
has one of the specified permissions to the presented
domain object instance.
</description>
<attribute>
<name>hasPermission</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>
A comma separated list of integers, each representing a
required bit mask permission from a subclass of
org.acegisecurity.acl.basic.AbstractBasicAclEntry.
</description>
</attribute>
<attribute>
<name>domainObject</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>
The actual domain object instance for which permissions
are being evaluated.
</description>
</attribute>
</tag>
</taglib>

View File

@ -12,11 +12,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.domain;
import junit.framework.TestCase;
import org.acegisecurity.acls.Permission;
/**
* Tests BasePermission and CumulativePermission.
@ -30,7 +31,18 @@ public class PermissionTests extends TestCase {
public void testExpectedIntegerValues() {
assertEquals(1, BasePermission.READ.getMask());
assertEquals(16, BasePermission.ADMINISTRATION.getMask());
assertEquals(17, new CumulativePermission().set(BasePermission.READ).set(BasePermission.ADMINISTRATION).getMask());
assertEquals(7,
new CumulativePermission().set(BasePermission.READ).set(BasePermission.WRITE).set(BasePermission.CREATE)
.getMask());
assertEquals(17,
new CumulativePermission().set(BasePermission.READ).set(BasePermission.ADMINISTRATION).getMask());
}
public void testFromInteger() {
Permission permission = BasePermission.buildFromMask(7);
System.out.println("7 = " + permission.toString());
permission = BasePermission.buildFromMask(4);
System.out.println("4 = " + permission.toString());
}
public void testStringConversion() {

View File

@ -1,48 +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.springframework.core.io.Resource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import java.io.IOException;
import javax.sql.DataSource;
/**
* DOCUMENT ME!
*
* @author $author$
* @version $Revision$
*/
public class DatabaseSeeder {
//~ Constructors ===================================================================================================
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);
}
}
/* 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.springframework.core.io.Resource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import java.io.IOException;
import javax.sql.DataSource;
/**
* Seeds the database for {@link JdbcAclServiceTests}.
*
* @author Ben Alex
* @version $Id$
*/
public class DatabaseSeeder {
//~ Constructors ===================================================================================================
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);
}
}

View File

@ -0,0 +1,222 @@
/* 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.Authentication;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.acls.AccessControlEntry;
import org.acegisecurity.acls.MutableAcl;
import org.acegisecurity.acls.NotFoundException;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.domain.BasePermission;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.objectidentity.ObjectIdentityImpl;
import org.acegisecurity.acls.sid.PrincipalSid;
import org.acegisecurity.acls.sid.Sid;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.TestingAuthenticationToken;
import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;
import java.util.Map;
/**
* Integration tests the ACL system using an in-memory database.
*
* @author Ben Alex
* @version $Id$
*/
public class JdbcAclServiceTests extends AbstractTransactionalDataSourceSpringContextTests {
//~ Instance fields ================================================================================================
private JdbcMutableAclService jdbcMutableAclService;
//~ Methods ========================================================================================================
protected String[] getConfigLocations() {
return new String[] {"classpath:org/acegisecurity/acls/jdbc/applicationContext-test.xml"};
}
public void setJdbcMutableAclService(JdbcMutableAclService jdbcAclService) {
this.jdbcMutableAclService = jdbcAclService;
}
public void testLifecycle() {
setComplete();
Authentication auth = new TestingAuthenticationToken("ben", "ignored",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ADMINISTRATOR")});
auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth);
ObjectIdentity topParentOid = new ObjectIdentityImpl("sample.contact.Contact", new Long(100));
ObjectIdentity middleParentOid = new ObjectIdentityImpl("sample.contact.Contact", new Long(101));
ObjectIdentity childOid = new ObjectIdentityImpl("sample.contact.Contact", new Long(102));
MutableAcl topParent = jdbcMutableAclService.createAcl(topParentOid);
MutableAcl middleParent = jdbcMutableAclService.createAcl(middleParentOid);
MutableAcl child = jdbcMutableAclService.createAcl(childOid);
// Specify the inheritence hierarchy
middleParent.setParent(topParent);
child.setParent(middleParent);
// Now let's add a couple of permissions
topParent.insertAce(null, BasePermission.READ, new PrincipalSid(auth), true);
topParent.insertAce(null, BasePermission.WRITE, new PrincipalSid(auth), false);
middleParent.insertAce(null, BasePermission.DELETE, new PrincipalSid(auth), true);
child.insertAce(null, BasePermission.DELETE, new PrincipalSid(auth), false);
// Explictly save the changed ACL
jdbcMutableAclService.updateAcl(topParent);
jdbcMutableAclService.updateAcl(middleParent);
jdbcMutableAclService.updateAcl(child);
// Let's check if we can read them back correctly
Map map = jdbcMutableAclService.readAclsById(new ObjectIdentity[] {topParentOid, middleParentOid, childOid});
assertEquals(3, map.size());
// Replace our current objects with their retrieved versions
topParent = (MutableAcl) map.get(topParentOid);
middleParent = (MutableAcl) map.get(middleParentOid);
child = (MutableAcl) map.get(childOid);
// Check the retrieved versions has IDs
assertNotNull(topParent.getId());
assertNotNull(middleParent.getId());
assertNotNull(child.getId());
// Check their parents were correctly persisted
assertNull(topParent.getParentAcl());
assertEquals(topParentOid, middleParent.getParentAcl().getObjectIdentity());
assertEquals(middleParentOid, child.getParentAcl().getObjectIdentity());
// Check their ACEs were correctly persisted
assertEquals(2, topParent.getEntries().length);
assertEquals(1, middleParent.getEntries().length);
assertEquals(1, child.getEntries().length);
// Check the retrieved rights are correct
assertTrue(topParent.isGranted(new Permission[] {BasePermission.READ}, new Sid[] {new PrincipalSid(auth)}, false));
assertFalse(topParent.isGranted(new Permission[] {BasePermission.WRITE}, new Sid[] {new PrincipalSid(auth)},
false));
assertTrue(middleParent.isGranted(new Permission[] {BasePermission.DELETE}, new Sid[] {new PrincipalSid(auth)},
false));
assertFalse(child.isGranted(new Permission[] {BasePermission.DELETE}, new Sid[] {new PrincipalSid(auth)}, false));
try {
child.isGranted(new Permission[] {BasePermission.ADMINISTRATION}, new Sid[] {new PrincipalSid(auth)}, false);
fail("Should have thrown NotFoundException");
} catch (NotFoundException expected) {
assertTrue(true);
}
// Now check the inherited rights (when not explicitly overridden) also look OK
assertTrue(child.isGranted(new Permission[] {BasePermission.READ}, new Sid[] {new PrincipalSid(auth)}, false));
assertFalse(child.isGranted(new Permission[] {BasePermission.WRITE}, new Sid[] {new PrincipalSid(auth)}, false));
assertFalse(child.isGranted(new Permission[] {BasePermission.DELETE}, new Sid[] {new PrincipalSid(auth)}, false));
// Next change the child so it doesn't inherit permissions from above
child.setEntriesInheriting(false);
jdbcMutableAclService.updateAcl(child);
child = (MutableAcl) jdbcMutableAclService.readAclById(childOid);
assertFalse(child.isEntriesInheriting());
// Check the child permissions no longer inherit
assertFalse(child.isGranted(new Permission[] {BasePermission.DELETE}, new Sid[] {new PrincipalSid(auth)}, true));
try {
child.isGranted(new Permission[] {BasePermission.READ}, new Sid[] {new PrincipalSid(auth)}, true);
fail("Should have thrown NotFoundException");
} catch (NotFoundException expected) {
assertTrue(true);
}
try {
child.isGranted(new Permission[] {BasePermission.WRITE}, new Sid[] {new PrincipalSid(auth)}, true);
fail("Should have thrown NotFoundException");
} catch (NotFoundException expected) {
assertTrue(true);
}
// Let's add an identical permission to the child, but it'll appear AFTER the current permission, so has no impact
child.insertAce(null, BasePermission.DELETE, new PrincipalSid(auth), true);
// Let's also add another permission to the child
child.insertAce(null, BasePermission.CREATE, new PrincipalSid(auth), true);
// Save the changed child
jdbcMutableAclService.updateAcl(child);
child = (MutableAcl) jdbcMutableAclService.readAclById(childOid);
assertEquals(3, child.getEntries().length);
// Output permissions
for (int i = 0; i < child.getEntries().length; i++) {
System.out.println(child.getEntries()[i]);
}
// Check the permissions are as they should be
assertFalse(child.isGranted(new Permission[] {BasePermission.DELETE}, new Sid[] {new PrincipalSid(auth)}, true)); // as earlier permission overrode
assertTrue(child.isGranted(new Permission[] {BasePermission.CREATE}, new Sid[] {new PrincipalSid(auth)}, true));
// Now check the first ACE (index 0) really is DELETE for our Sid and is non-granting
AccessControlEntry entry = child.getEntries()[0];
assertEquals(BasePermission.DELETE.getMask(), entry.getPermission().getMask());
assertEquals(new PrincipalSid(auth), entry.getSid());
assertFalse(entry.isGranting());
assertNotNull(entry.getId());
// Now delete that first ACE
child.deleteAce(entry.getId());
// Save and check it worked
child = jdbcMutableAclService.updateAcl(child);
assertEquals(2, child.getEntries().length);
assertTrue(child.isGranted(new Permission[] {BasePermission.DELETE}, new Sid[] {new PrincipalSid(auth)}, false));
SecurityContextHolder.clearContext();
}
/* public void testCumulativePermissions() {
setComplete();
Authentication auth = new TestingAuthenticationToken("ben", "ignored", new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ADMINISTRATOR")});
auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth);
ObjectIdentity topParentOid = new ObjectIdentityImpl("sample.contact.Contact", new Long(110));
MutableAcl topParent = jdbcMutableAclService.createAcl(topParentOid);
// Add an ACE permission entry
CumulativePermission cm = new CumulativePermission().set(BasePermission.READ).set(BasePermission.ADMINISTRATION);
assertEquals(17, cm.getMask());
topParent.insertAce(null, cm, new PrincipalSid(auth), true);
assertEquals(1, topParent.getEntries().length);
// Explictly save the changed ACL
topParent = jdbcMutableAclService.updateAcl(topParent);
// Check the mask was retrieved correctly
assertEquals(17, topParent.getEntries()[0].getPermission().getMask());
assertTrue(topParent.isGranted(new Permission[] {cm}, new Sid[] {new PrincipalSid(auth)}, true));
SecurityContextHolder.clearContext();
}
*/
}

View File

@ -15,6 +15,10 @@
<constructor-arg ref="dataSource"/>
<constructor-arg value="classpath:org/acegisecurity/acls/jdbc/testData.sql"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="aclCache" class="org.acegisecurity.acls.jdbc.EhCacheBasedAclCache">
<constructor-arg>
@ -31,26 +35,33 @@
<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 ref="aclCache"/>
<constructor-arg ref="aclAuthorizationStrategy"/>
<constructor-arg>
<bean class="org.acegisecurity.acls.domain.ConsoleAuditLogger"/>
</constructor-arg>
</bean>
<bean id="aclAuthorizationStrategy" class="org.acegisecurity.acls.domain.AclAuthorizationStrategyImpl">
<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">
<bean id="aclService" class="org.acegisecurity.acls.jdbc.JdbcMutableAclService">
<constructor-arg ref="dataSource"/>
<constructor-arg ref="aclCache"/>
<constructor-arg ref="lookupStrategy"/>
<constructor-arg ref="lookupStrategy"/>
<constructor-arg ref="aclCache"/>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
@ -58,7 +69,8 @@
<value>org.hsqldb.jdbcDriver</value>
</property>
<property name="url">
<value>jdbc:hsqldb:mem:test</value>
<value>jdbc:hsqldb:mem:test</value>
<!-- <value>jdbc:hsqldb:hsql://localhost/acl</value> -->
</property>
<property name="username">
<value>sa</value>

View File

@ -1,23 +1,27 @@
-- 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_SID.PRINCIPAL as ACE_PRINCIPAL, ACL_SID.SID as ACE_SID,
ACLI_SID.PRINCIPAL as ACL_PRINCIPAL, ACLI_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
from ACL_OBJECT_IDENTITY, ACL_SID ACLI_SID, ACL_CLASS
LEFT JOIN ACL_ENTRY ON ACL_OBJECT_IDENTITY.ID = ACL_ENTRY.ACL_OBJECT_IDENTITY
LEFT JOIN ACL_SID ON ACL_ENTRY.SID = ACL_SID.ID
where
ACLI_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
(ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY = 2000
and ACL_CLASS.CLASS = 'sample.contact.Contact')
) order by ACL_ENTRY.ACL_OBJECT_IDENTITY asc, ACL_ENTRY.ACE_ORDER asc
) order by ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY asc, ACL_ENTRY.ACE_ORDER asc

View File

@ -0,0 +1,45 @@
-- Injected into DatabaseSeeder via applicationContext-test.xml (see test case JdbcAclServiceTests)
-- DROP TABLE ACL_ENTRY;
-- DROP TABLE ACL_OBJECT_IDENTITY;
-- DROP TABLE ACL_CLASS;
-- DROP TABLE ACL_SID;
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));
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));
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));

View File

@ -4702,9 +4702,97 @@ public boolean supports(Class clazz);</programlisting></para>
<sect2 id="after-invocation-acl-aware">
<title>ACL-Aware AfterInvocationProviders</title>
<para>TODO: This section will be removed when we deprecate the
existing ACL package. It should be discussed with the context of the
ACL implementation chapter instead.</para>
<para>PLEASE NOTE: Acegi Security 1.0.3 contains a preview of a new
ACL module. The new ACL module is a significant rewrite of the
existing ACL module. The new module can be found under the
<literal>org.acegisecurity.acls</literal> package, with the old ACL
module under <literal>org.acegisecurity.acl</literal>. We encourage
users to consider testing with the new ACL module and build
applications with it. The old ACL module should be considered
deprecated and may be removed from a future release. The following
information relates to the new ACL package, and is thus
recommended.</para>
<para>A common services layer method we've all written at one stage
or another looks like this:</para>
<para><programlisting>public Contact getById(Integer id);</programlisting></para>
<para>Quite often, only principals with permission to read the
<literal>Contact</literal> should be allowed to obtain it. In this
situation the <literal>AccessDecisionManager</literal> approach
provided by the <literal>AbstractSecurityInterceptor</literal> will
not suffice. This is because the identity of the
<literal>Contact</literal> is all that is available before the
secure object is invoked. The
<literal>AclAfterInvocationProvider</literal> delivers a solution,
and is configured as follows:</para>
<para><programlisting>&lt;bean id="afterAclRead" class="org.acegisecurity.afterinvocation.AclEntryAfterInvocationProvider"&gt;
&lt;constructor-arg&gt;
&lt;ref bean="aclService"/&gt;
&lt;/constructor-arg&gt;
&lt;constructor-arg&gt;
&lt;list&gt;
&lt;ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/&gt;
&lt;ref local="org.acegisecurity.acls.domain.BasePermission.READ"/&gt;
&lt;/list&gt;
&lt;/constructor-arg&gt;
&lt;/bean&gt; </programlisting></para>
<para>In the above example, the <literal>Contact</literal> will be
retrieved and passed to the
<literal>AclEntryAfterInvocationProvider</literal>. The provider
will thrown an <literal>AccessDeniedException</literal> if one of
the listed <literal>requirePermission</literal>s is not held by the
<literal>Authentication</literal>. The
<literal>AclEntryAfterInvocationProvider</literal> queries the
<literal>Acl</literal>Service to determine the ACL that applies for
this domain object to this <literal>Authentication</literal>.</para>
<para>Similar to the
<literal>AclEntryAfterInvocationProvider</literal> is
<literal>AclEntryAfterInvocationCollectionFilteringProvider</literal>.
It is designed to remove <literal>Collection</literal> or array
elements for which a principal does not have access. It never thrown
an <literal>AccessDeniedException</literal> - simply silently
removes the offending elements. The provider is configured as
follows:</para>
<para><programlisting>&lt;bean id="afterAclCollectionRead" class="org.acegisecurity.afterinvocation.AclEntryAfterInvocationCollectionFilteringProvider"&gt;
&lt;constructor-arg&gt;
&lt;ref bean="aclService"/&gt;
&lt;/constructor-arg&gt;
&lt;constructor-arg&gt;
&lt;list&gt;
&lt;ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/&gt;
&lt;ref local="org.acegisecurity.acls.domain.BasePermission.READ"/&gt;
&lt;/list&gt;
&lt;/constructor-arg&gt;
&lt;/bean&gt; </programlisting></para>
<para>As you can imagine, the returned <literal>Object</literal>
must be a <literal>Collection</literal> or array for this provider
to operate. It will remove any element if the
<literal>AclManager</literal> indicates the
<literal>Authentication</literal> does not hold one of the listed
<literal>requirePermission</literal>s.</para>
<para>The Contacts sample application demonstrates these two
<literal>AfterInvocationProvider</literal>s.</para>
</sect2>
<sect2 id="after-invocation-acl-aware-old">
<title>ACL-Aware AfterInvocationProviders (old ACL module)</title>
<para>PLEASE NOTE: Acegi Security 1.0.3 contains a preview of a new
ACL module. The new ACL module is a significant rewrite of the
existing ACL module. The new module can be found under the
<literal>org.acegisecurity.acls</literal> package, with the old ACL
module under <literal>org.acegisecurity.acl</literal>. We encourage
users to consider testing with the new ACL module and build
applications with it. The old ACL module should be considered
deprecated and may be removed from a future release.</para>
<para>A common services layer method we've all written at one stage
or another looks like this:</para>
@ -4838,25 +4926,28 @@ public boolean supports(Class clazz);</programlisting></para>
<literal>ifAllGranted</literal>, and finally, <literal>if
AnyGranted</literal>.</para>
<para><literal>AclTag</literal> is used to include content if the
current principal has a ACL to the indicated domain object.</para>
<para><literal>AccessControlListTag</literal> is used to include
content if the current principal has an ACL to the indicated domain
object.</para>
<para>The following JSP fragment illustrates how to use the
<literal>AclTag</literal>:</para>
<literal>AccessControlListTag</literal>:</para>
<para><programlisting>
&lt;authz:acl domainObject="${contact}" hasPermission="16,1"&gt;
<para><programlisting>&lt;authz:accesscontrollist domainObject="${contact}" hasPermission="8,16"&gt;
&lt;td&gt;&lt;A HREF="&lt;c:url value="del.htm"&gt;&lt;c:param name="contactId" value="${contact.id}"/&gt;&lt;/c:url&gt;"&gt;Del&lt;/A&gt;&lt;/td&gt;
&lt;/authz:acl&gt;
</programlisting></para>
&lt;/authz:accesscontrollist&gt;</programlisting></para>
<para>This tag would cause the tag's body to be output if the
principal holds either permission 16 or permission 1 for the "contact"
domain object. The numbers are actually integers that are used with
<literal>AbstractBasicAclEntry</literal> bit masking. Please refer to
the ACL section of this reference guide to understand more about the
ACL capabilities of Acegi Security</para>
<literal>BasePermission</literal> bit masking. Please refer to the ACL
section of this reference guide to understand more about the ACL
capabilities of Acegi Security.</para>
<para><literal>AclTag</literal> is part of the old ACL module and
should be considered deprecated. For the sake of historical reference,
works exactly the samae as
<literal>AccessControlListTag</literal>.</para>
</sect1>
</chapter>
@ -5371,6 +5462,15 @@ public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {
<section id="domain-acls-overview">
<title>Overview</title>
<para>PLEASE NOTE: Acegi Security 1.0.3 contains a preview of a new
ACL module. The new ACL module is a significant rewrite of the
existing ACL module. The new module can be found under the
<literal>org.acegisecurity.acls</literal> package, with the old ACL
module under <literal>org.acegisecurity.acl</literal>. We encourage
users to consider testing with the new ACL module and build
applications with it. The old ACL module should be considered
deprecated and may be removed from a future release.</para>
<para>Complex applications often will find the need to define access
permissions not simply at a web request or method invocation level.
Instead, security decisions need to comprise both who
@ -5448,7 +5548,183 @@ public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {
about below.</para>
</section>
<section id="domain-acls-basic">
<section id="domain-acls-key-concepts">
<title>Key Concepts</title>
<para>The org.acegisecurity.acls package should be consulted for its
major interfaces. The key interfaces are:</para>
<itemizedlist spacing="compact">
<listitem>
<para><literal>Acl</literal>: Every domain object has one and only
one <literal>Acl</literal> object, which internally holds the
<literal>AccessControlEntry</literal>s as well as knows the owner
of the <literal>Acl</literal>. An Acl does not refer directly to
the domain object, but instead to an
<literal>ObjectIdentity</literal>.</para>
</listitem>
<listitem>
<para><literal><literal>AccessControlEntry</literal></literal>: An
Acl holds multiple <literal>AccessControlEntry</literal>s, which
are often abbreviated as ACEs in the framework. Each ACE refers to
a specific tuple of <literal>Permission</literal>,
<literal>Sid</literal> and <literal>Acl</literal>. An ACE can also
be granting or non-granting and contain audit settings.</para>
</listitem>
<listitem>
<para><literal>Permission</literal>: A permission represents an
immutable particular bit mask, and offers convenience functions
for bit masking and outputting information.</para>
</listitem>
<listitem>
<para><literal>Sid</literal>: The ACL module needs to refer to
principals and <literal>GrantedAuthority[]</literal>s. A level of
indirection is provided by the <literal>Sid</literal> interface.
Common classes include <literal>PrincipalSid</literal> (to
represent the principal inside an
<literal>Authentication</literal> object) and
<literal>GrantedAuthoritySid</literal>.</para>
</listitem>
<listitem>
<para><literal>ObjectIdentity</literal>: Each domain object is
represented internally within the ACL module by an
<literal>ObjectIdentity</literal>.</para>
</listitem>
<listitem>
<para><literal>AclService</literal>: Retrieves the
<literal>Acl</literal> applicable for a given
<literal>ObjectIdentity</literal>.</para>
</listitem>
<listitem>
<para><literal>MutableAclService</literal>: Allows a modified
<literal>Acl</literal> to be presented for persistence. It is not
essential to use this interface if you do not wish.</para>
</listitem>
</itemizedlist>
<para>The ACL module was based on extensive feedback from the user
community following real-world use of the original ACL module. This
feedback resulted in a rearchitecture of the ACL module to offer
significantly enhanced performance (particularly in the area of
database retrieval), significantly better encapsulation, higher
cohesion, and enhanced customisation points.</para>
<para>The Contacts Sample that ships with Acegi Security 1.0.3 offers
a demonstration of the new ACL module. Converting Contacts from using
the old module to the new module was relatively simple, and users of
the old ACL module will likely find their applications can be modified
with relatively little work.</para>
<para>We will document the new ACL module more fully with a subsequent
release. Please note that the new ACL module should be considered a
preview only (ie do not use in production without proper prior
testing), and there is a small chance there may be changes between
1.0.3 and 1.1.0 when it will become final. Nevertheless,
compatibility-affecting changes are considered quite unlikely,
especially given the module is already based on several years of
feedback from users of the original ACL module.</para>
</section>
</chapter>
<chapter id="domain-acls-old">
<title>Domain Object Security (old ACL module)</title>
<section id="domain-acls-overview-old">
<title>Overview</title>
<para>PLEASE NOTE: Acegi Security 1.0.3 contains a preview of a new
ACL module. The new ACL module is a significant rewrite of the
existing ACL module. The new module can be found under the
<literal>org.acegisecurity.acls</literal> package, with the old ACL
module under <literal>org.acegisecurity.acl</literal>. We encourage
users to consider testing with the new ACL module and build
applications with it. The old ACL module should be considered
deprecated and may be removed from a future release.</para>
<para>Complex applications often will find the need to define access
permissions not simply at a web request or method invocation level.
Instead, security decisions need to comprise both who
(<literal>Authentication</literal>), where
(<literal>MethodInvocation</literal>) and what
(<literal>SomeDomainObject</literal>). In other words, authorization
decisions also need to consider the actual domain object instance
subject of a method invocation.</para>
<para>Imagine you're designing an application for a pet clinic. There
will be two main groups of users of your Spring-based application:
staff of the pet clinic, as well as the pet clinic's customers. The
staff will have access to all of the data, whilst your customers will
only be able to see their own customer records. To make it a little
more interesting, your customers can allow other users to see their
customer records, such as their "puppy preschool "mentor or president
of their local "Pony Club". Using Acegi Security as the foundation,
you have several approaches that can be used:<orderedlist>
<listitem>
<para>Write your business methods to enforce the security. You
could consult a collection within the
<literal>Customer</literal> domain object instance to determine
which users have access. By using the
<literal>SecurityContextHolder.getContext().getAuthentication()</literal>,
you'll be able to access the <literal>Authentication</literal>
object.</para>
</listitem>
<listitem>
<para>Write an <literal>AccessDecisionVoter</literal> to enforce
the security from the <literal>GrantedAuthority[]</literal>s
stored in the <literal>Authentication</literal> object. This
would mean your <literal>AuthenticationManager</literal> would
need to populate the <literal>Authentication</literal> with
custom <literal>GrantedAuthority</literal>[]s representing each
of the <literal>Customer</literal> domain object instances the
principal has access to.</para>
</listitem>
<listitem>
<para>Write an <literal>AccessDecisionVoter</literal> to enforce
the security and open the target <literal>Customer</literal>
domain object directly. This would mean your voter needs access
to a DAO that allows it to retrieve the
<literal>Customer</literal> object. It would then access the
<literal>Customer</literal> object's collection of approved
users and make the appropriate decision.</para>
</listitem>
</orderedlist></para>
<para>Each one of these approaches is perfectly legitimate. However,
the first couples your authorization checking to your business code.
The main problems with this include the enhanced difficulty of unit
testing and the fact it would be more difficult to reuse the
<literal>Customer</literal> authorization logic elsewhere. Obtaining
the <literal>GrantedAuthority[]</literal>s from the
<literal>Authentication</literal> object is also fine, but will not
scale to large numbers of <literal>Customer</literal>s. If a user
might be able to access 5,000 <literal>Customer</literal>s (unlikely
in this case, but imagine if it were a popular vet for a large Pony
Club!) the amount of memory consumed and time required to construct
the <literal>Authentication</literal> object would be undesirable. The
final method, opening the <literal>Customer</literal> directly from
external code, is probably the best of the three. It achieves
separation of concerns, and doesn't misuse memory or CPU cycles, but
it is still inefficient in that both the
<literal>AccessDecisionVoter</literal> and the eventual business
method itself will perform a call to the DAO responsible for
retrieving the <literal>Customer</literal> object. Two accesses per
method invocation is clearly undesirable. In addition, with every
approach listed you'll need to write your own access control list
(ACL) persistence and business logic from scratch.</para>
<para>Fortunately, there is another alternative, which we'll talk
about below.</para>
</section>
<section id="domain-acls-basic-old">
<title>Basic ACL Package</title>
<para>Please note that our Basic ACL services are currently being

View File

@ -265,7 +265,7 @@
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.7.3.0</version>
<version>1.8.0.4</version>
<type>jar</type>
<url>http://hsqldb.sourceforge.net/</url>
<properties>

View File

@ -12,15 +12,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact.annotation;
import org.acegisecurity.Authentication;
import org.acegisecurity.acl.basic.AclObjectIdentity;
import org.acegisecurity.acl.basic.BasicAclExtendedDao;
import org.acegisecurity.acl.basic.NamedEntityObjectIdentity;
import org.acegisecurity.acl.basic.SimpleAclEntry;
import org.acegisecurity.acls.AccessControlEntry;
import org.acegisecurity.acls.MutableAcl;
import org.acegisecurity.acls.MutableAclService;
import org.acegisecurity.acls.NotFoundException;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.domain.BasePermission;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.objectidentity.ObjectIdentityImpl;
import org.acegisecurity.acls.sid.PrincipalSid;
import org.acegisecurity.acls.sid.Sid;
import org.acegisecurity.annotation.Secured;
@ -54,28 +59,36 @@ import java.util.Random;
public class ContactManagerBackend extends ApplicationObjectSupport implements ContactManager, InitializingBean {
//~ Instance fields ================================================================================================
private BasicAclExtendedDao basicAclExtendedDao;
private ContactDao contactDao;
private int counter = 100;
// TODO: Assignment of annotations against class does not result in match in sample application
private MutableAclService mutableAclService;
private int counter = 1000;
//~ Methods ========================================================================================================
@Secured({"ACL_CONTACT_ADMIN"})
public void addPermission(Contact contact, String recipient, Integer permission) {
SimpleAclEntry simpleAclEntry = new SimpleAclEntry();
simpleAclEntry.setAclObjectIdentity(makeObjectIdentity(contact));
simpleAclEntry.setMask(permission.intValue());
simpleAclEntry.setRecipient(recipient);
basicAclExtendedDao.create(simpleAclEntry);
public void addPermission(Contact contact, Sid recipient, Permission permission) {
MutableAcl acl;
ObjectIdentity oid = new ObjectIdentityImpl(Contact.class, contact.getId());
try {
acl = (MutableAcl) mutableAclService.readAclById(oid);
} catch (NotFoundException nfe) {
acl = mutableAclService.createAcl(oid);
}
acl.insertAce(null, permission, recipient, true);
mutableAclService.updateAcl(acl);
if (logger.isDebugEnabled()) {
logger.debug("Added permission " + permission + " for recipient " + recipient + " contact " + contact);
logger.debug("Added permission " + permission + " for Sid " + recipient + " contact " + contact);
}
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(contactDao, "contactDao required");
Assert.notNull(basicAclExtendedDao, "basicAclExtendedDao required");
Assert.notNull(mutableAclService, "mutableAclService required");
}
@Secured({"ROLE_USER"})
@ -84,8 +97,8 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
contact.setId(new Long(counter++));
contactDao.create(contact);
// Grant the current principal access to the contact
addPermission(contact, getUsername(), new Integer(SimpleAclEntry.ADMINISTRATION));
// Grant the current principal administrative permission to the contact
addPermission(contact, new PrincipalSid(getUsername()), BasePermission.ADMINISTRATION);
if (logger.isDebugEnabled()) {
logger.debug("Created contact " + contact + " and granted admin permission to recipient " + getUsername());
@ -97,7 +110,8 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
contactDao.delete(contact.getId());
// Delete the ACL information as well
basicAclExtendedDao.delete(makeObjectIdentity(contact));
ObjectIdentity oid = new ObjectIdentityImpl(Contact.class, contact.getId());
mutableAclService.deleteAcl(oid, false);
if (logger.isDebugEnabled()) {
logger.debug("Deleted contact " + contact + " including ACL permissions");
@ -105,8 +119,20 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
}
@Secured({"ACL_CONTACT_ADMIN"})
public void deletePermission(Contact contact, String recipient) {
basicAclExtendedDao.delete(makeObjectIdentity(contact), recipient);
public void deletePermission(Contact contact, Sid recipient, Permission permission) {
ObjectIdentity oid = new ObjectIdentityImpl(Contact.class, contact.getId());
MutableAcl acl = (MutableAcl) mutableAclService.readAclById(oid);
// Remove all permissions associated with this particular recipient (string equality to KISS)
AccessControlEntry[] entries = acl.getEntries();
for (int i = 0; i < entries.length; i++) {
if (entries[i].getSid().equals(recipient) && entries[i].getPermission().equals(permission)) {
acl.deleteAce(entries[i].getId());
}
}
mutableAclService.updateAcl(acl);
if (logger.isDebugEnabled()) {
logger.debug("Deleted contact " + contact + " ACL permissions for recipient " + recipient);
@ -131,15 +157,10 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
}
List list = contactDao.findAllPrincipals();
list.addAll(contactDao.findAllRoles());
return list;
}
public BasicAclExtendedDao getBasicAclExtendedDao() {
return basicAclExtendedDao;
}
@Secured({"ROLE_USER", "AFTER_ACL_READ"})
@Transactional(readOnly = true)
public Contact getById(Long id) {
@ -150,10 +171,6 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
return contactDao.getById(id);
}
public ContactDao getContactDao() {
return contactDao;
}
/**
* This is a public method.
*
@ -181,18 +198,14 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
}
}
private AclObjectIdentity makeObjectIdentity(Contact contact) {
return new NamedEntityObjectIdentity(contact.getClass().getName(), contact.getId().toString());
}
public void setBasicAclExtendedDao(BasicAclExtendedDao basicAclExtendedDao) {
this.basicAclExtendedDao = basicAclExtendedDao;
}
public void setContactDao(ContactDao contactDao) {
this.contactDao = contactDao;
}
public void setMutableAclService(MutableAclService mutableAclService) {
this.mutableAclService = mutableAclService;
}
public void update(Contact contact) {
contactDao.update(contact);

View File

@ -1,163 +0,0 @@
<?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 authentication beans.
-
- Used by all artifacts.
-
- $Id$
-->
<beans>
<!-- ~~~~~~~~~~~~~~~~~~ "BEFORE INVOCATION" AUTHORIZATION DEFINITIONS ~~~~~~~~~~~~~~~~ -->
<!-- ACL permission masks used by this application -->
<bean id="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION</value></property>
</bean>
<bean id="net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ</value></property>
</bean>
<bean id="net.sf.acegisecurity.acl.basic.SimpleAclEntry.DELETE" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>net.sf.acegisecurity.acl.basic.SimpleAclEntry.DELETE</value></property>
</bean>
<!-- An access decision voter that reads ROLE_* configuration settings -->
<bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/>
<!-- An access decision voter that reads ACL_CONTACT_READ configuration settings -->
<bean id="aclContactReadVoter" class="net.sf.acegisecurity.vote.BasicAclEntryVoter">
<property name="processConfigAttribute"><value>ACL_CONTACT_READ</value></property>
<property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
<ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
</list>
</property>
</bean>
<!-- An access decision voter that reads ACL_CONTACT_DELETE configuration settings -->
<bean id="aclContactDeleteVoter" class="net.sf.acegisecurity.vote.BasicAclEntryVoter">
<property name="processConfigAttribute"><value>ACL_CONTACT_DELETE</value></property>
<property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
<ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.DELETE"/>
</list>
</property>
</bean>
<!-- An access decision voter that reads ACL_CONTACT_ADMIN configuration settings -->
<bean id="aclContactAdminVoter" class="net.sf.acegisecurity.vote.BasicAclEntryVoter">
<property name="processConfigAttribute"><value>ACL_CONTACT_ADMIN</value></property>
<property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
</list>
</property>
</bean>
<!-- An access decision manager used by the business objects -->
<bean id="businessAccessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions"><value>false</value></property>
<property name="decisionVoters">
<list>
<ref local="roleVoter"/>
<ref local="aclContactReadVoter"/>
<ref local="aclContactDeleteVoter"/>
<ref local="aclContactAdminVoter"/>
</list>
</property>
</bean>
<!-- ========= ACCESS CONTROL LIST LOOKUP MANAGER DEFINITIONS ========= -->
<bean id="aclManager" class="net.sf.acegisecurity.acl.AclProviderManager">
<property name="providers">
<list>
<ref local="basicAclProvider"/>
</list>
</property>
</bean>
<bean id="basicAclProvider" class="net.sf.acegisecurity.acl.basic.BasicAclProvider">
<property name="basicAclDao"><ref local="basicAclExtendedDao"/></property>
</bean>
<bean id="basicAclExtendedDao" class="net.sf.acegisecurity.acl.basic.jdbc.JdbcExtendedDaoImpl">
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
<!-- ============== "AFTER INTERCEPTION" AUTHORIZATION DEFINITIONS =========== -->
<bean id="afterInvocationManager" class="net.sf.acegisecurity.afterinvocation.AfterInvocationProviderManager">
<property name="providers">
<list>
<ref local="afterAclRead"/>
<ref local="afterAclCollectionRead"/>
</list>
</property>
</bean>
<!-- Processes AFTER_ACL_COLLECTION_READ configuration settings -->
<bean id="afterAclCollectionRead" class="net.sf.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationCollectionFilteringProvider">
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
<ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
</list>
</property>
</bean>
<!-- Processes AFTER_ACL_READ configuration settings -->
<bean id="afterAclRead" class="net.sf.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationProvider">
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
<ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
</list>
</property>
</bean>
<!-- ================= METHOD INVOCATION AUTHORIZATION ==================== -->
<!-- getRandomContact() is public.
The create, getAll, getById etc have ROLE_USER to ensure user is
authenticated (all users hold ROLE_USER in this application).
The delete and update methods don't need a ROLE_USER as they will
ensure the user is authenticated via their ACL_CONTACT_DELETE or
ACL_CONTACT_READ attribute, which also ensures the user has permission
to the Contact presented as a method argument.
-->
<bean id="contactManagerSecurity" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="accessDecisionManager"><ref local="businessAccessDecisionManager"/></property>
<property name="afterInvocationManager"><ref local="afterInvocationManager"/></property>
<property name="objectDefinitionSource">
<value>
sample.contact.ContactManager.create=ROLE_USER
sample.contact.ContactManager.getAllRecipients=ROLE_USER
sample.contact.ContactManager.getAll=ROLE_USER,AFTER_ACL_COLLECTION_READ
sample.contact.ContactManager.getById=ROLE_USER,AFTER_ACL_READ
sample.contact.ContactManager.delete=ACL_CONTACT_DELETE
sample.contact.ContactManager.deletePermission=ACL_CONTACT_ADMIN
sample.contact.ContactManager.addPermission=ACL_CONTACT_ADMIN
</value>
</property>
</bean>
</beans>

View File

@ -1,72 +0,0 @@
<?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="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>org.hsqldb.jdbcDriver</value>
</property>
<property name="url">
<value>jdbc:hsqldb:mem:contacts</value>
</property>
<property name="username">
<value>sa</value>
</property>
<property name="password">
<value></value>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"><ref local="dataSource"/></property>
</bean>
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager"><ref bean="transactionManager"/></property>
<property name="transactionAttributeSource">
<value>
sample.contact.ContactManager.create=PROPAGATION_REQUIRED
sample.contact.ContactManager.getAllRecipients=PROPAGATION_REQUIRED,readOnly
sample.contact.ContactManager.getAll=PROPAGATION_REQUIRED,readOnly
sample.contact.ContactManager.getById=PROPAGATION_REQUIRED,readOnly
sample.contact.ContactManager.delete=PROPAGATION_REQUIRED
sample.contact.ContactManager.deletePermission=PROPAGATION_REQUIRED
sample.contact.ContactManager.addPermission=PROPAGATION_REQUIRED
</value>
</property>
</bean>
<bean id="dataSourcePopulator" class="sample.contact.DataSourcePopulator">
<property name="dataSource"><ref local="dataSource"/></property>
</bean>
<bean id="contactDao" class="sample.contact.ContactDaoSpring">
<property name="dataSource"><ref local="dataSource"/></property>
</bean>
<bean id="contactManager" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>sample.contact.ContactManager</value></property>
<property name="interceptorNames">
<list>
<idref local="transactionInterceptor"/>
<idref bean="contactManagerSecurity"/>
<idref local="contactManagerTarget"/>
</list>
</property>
</bean>
<bean id="contactManagerTarget" class="sample.contact.ContactManagerBackend">
<property name="contactDao"><ref local="contactDao"/></property>
<property name="basicAclExtendedDao"><ref bean="basicAclExtendedDao"/></property>
</bean>
</beans>

View File

@ -21,7 +21,7 @@
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,basicProcessingFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
/**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,basicProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,switchUserProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
</value>
</property>
</bean>
@ -38,7 +38,7 @@
</property>
</bean>
<bean id="jdbcDaoImpl" class="org.acegisecurity.providers.dao.jdbc.JdbcDaoImpl">
<bean id="jdbcDaoImpl" class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
@ -90,6 +90,7 @@
</bean>
<bean id="rememberMeProcessingFilter" class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter">
<property name="authenticationManager"><ref local="authenticationManager"/></property>
<property name="rememberMeServices"><ref local="rememberMeServices"/></property>
</bean>
@ -101,6 +102,18 @@
<bean id="rememberMeAuthenticationProvider" class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
<property name="key"><value>springRocks</value></property>
</bean>
<bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter">
<constructor-arg value="/index.jsp"/> <!-- URL redirected to after logout -->
<constructor-arg>
<list>
<ref bean="rememberMeServices"/>
<bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>
</list>
</constructor-arg>
</bean>
<bean id="securityContextHolderAwareRequestFilter" class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter"/>
<!-- ===================== HTTP CHANNEL REQUIREMENTS ==================== -->
@ -136,6 +149,11 @@
<bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
<property name="authenticationEntryPoint"><ref local="authenticationProcessingFilterEntryPoint"/></property>
<property name="accessDeniedHandler">
<bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
<property name="errorPage" value="/accessDenied.jsp"/>
</bean>
</property>
</bean>
<bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
@ -173,10 +191,22 @@
/index.jsp=ROLE_ANONYMOUS,ROLE_USER
/hello.htm=ROLE_ANONYMOUS,ROLE_USER
/logoff.jsp=ROLE_ANONYMOUS,ROLE_USER
/switchuser.jsp=ROLE_SUPERVISOR
/j_acegi_switch_user=ROLE_SUPERVISOR
/acegilogin.jsp*=ROLE_ANONYMOUS,ROLE_USER
/**=ROLE_USER
</value>
</property>
</bean>
<!-- Filter used to switch the user context. Note: the switch and exit url must be secured
based on the role granted the ability to 'switch' to another user -->
<!-- In this example 'marissa' has ROLE_SUPERVISOR that can switch to regular ROLE_USER(s) -->
<bean id="switchUserProcessingFilter" class="org.acegisecurity.ui.switchuser.SwitchUserProcessingFilter">
<property name="userDetailsService" ref="jdbcDaoImpl" />
<property name="switchUserUrl"><value>/j_acegi_switch_user</value></property>
<property name="exitUserUrl"><value>/j_acegi_exit_user</value></property>
<property name="targetUrl"><value>/acegi-security-sample-contacts-filter/secure/index.htm</value></property>
</bean>
</beans>

View File

@ -12,60 +12,72 @@
<!-- ~~~~~~~~~~~~~~~~~~ "BEFORE INVOCATION" AUTHORIZATION DEFINITIONS ~~~~~~~~~~~~~~~~ -->
<!-- ACL permission masks used by this application -->
<bean id="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION</value></property>
<bean id="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION</value></property>
</bean>
<bean id="net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ</value></property>
<bean id="org.acegisecurity.acls.domain.BasePermission.READ" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>org.acegisecurity.acls.domain.BasePermission.READ</value></property>
</bean>
<bean id="net.sf.acegisecurity.acl.basic.SimpleAclEntry.DELETE" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>net.sf.acegisecurity.acl.basic.SimpleAclEntry.DELETE</value></property>
<bean id="org.acegisecurity.acls.domain.BasePermission.DELETE" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>org.acegisecurity.acls.domain.BasePermission.DELETE</value></property>
</bean>
<!-- An access decision voter that reads ROLE_* configuration settings -->
<bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/>
<bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter"/>
<!-- An access decision voter that reads ACL_CONTACT_READ configuration settings -->
<bean id="aclContactReadVoter" class="net.sf.acegisecurity.vote.BasicAclEntryVoter">
<property name="processConfigAttribute"><value>ACL_CONTACT_READ</value></property>
<bean id="aclContactReadVoter" class="org.acegisecurity.vote.AclEntryVoter">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<value>ACL_CONTACT_READ</value>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
<ref local="org.acegisecurity.acls.domain.BasePermission.READ"/>
</list>
</constructor-arg>
<property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
<ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
</list>
</property>
</bean>
<!-- An access decision voter that reads ACL_CONTACT_DELETE configuration settings -->
<bean id="aclContactDeleteVoter" class="net.sf.acegisecurity.vote.BasicAclEntryVoter">
<property name="processConfigAttribute"><value>ACL_CONTACT_DELETE</value></property>
<bean id="aclContactDeleteVoter" class="org.acegisecurity.vote.AclEntryVoter">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<value>ACL_CONTACT_DELETE</value>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
<ref local="org.acegisecurity.acls.domain.BasePermission.DELETE"/>
</list>
</constructor-arg>
<property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
<ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.DELETE"/>
</list>
</property>
</bean>
<!-- An access decision voter that reads ACL_CONTACT_ADMIN configuration settings -->
<bean id="aclContactAdminVoter" class="net.sf.acegisecurity.vote.BasicAclEntryVoter">
<property name="processConfigAttribute"><value>ACL_CONTACT_ADMIN</value></property>
<bean id="aclContactAdminVoter" class="org.acegisecurity.vote.AclEntryVoter">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<value>ACL_CONTACT_ADMIN</value>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
</list>
</constructor-arg>
<property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
</list>
</property>
</bean>
<!-- An access decision manager used by the business objects -->
<bean id="businessAccessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased">
<bean id="businessAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions"><value>false</value></property>
<property name="decisionVoters">
<list>
@ -79,25 +91,53 @@
<!-- ========= ACCESS CONTROL LIST LOOKUP MANAGER DEFINITIONS ========= -->
<bean id="aclManager" class="net.sf.acegisecurity.acl.AclProviderManager">
<property name="providers">
<list>
<ref local="basicAclProvider"/>
</list>
</property>
</bean>
<bean id="basicAclProvider" class="net.sf.acegisecurity.acl.basic.BasicAclProvider">
<property name="basicAclDao"><ref local="basicAclExtendedDao"/></property>
</bean>
<bean id="basicAclExtendedDao" class="net.sf.acegisecurity.acl.basic.jdbc.JdbcExtendedDaoImpl">
<property name="dataSource"><ref bean="dataSource"/></property>
</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 ref="aclAuthorizationStrategy"/>
<constructor-arg>
<bean class="org.acegisecurity.acls.domain.ConsoleAuditLogger"/>
</constructor-arg>
</bean>
<bean id="aclAuthorizationStrategy" class="org.acegisecurity.acls.domain.AclAuthorizationStrategyImpl">
<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.JdbcMutableAclService">
<constructor-arg ref="dataSource"/>
<constructor-arg ref="lookupStrategy"/>
<constructor-arg ref="aclCache"/>
</bean>
<!-- ============== "AFTER INTERCEPTION" AUTHORIZATION DEFINITIONS =========== -->
<bean id="afterInvocationManager" class="net.sf.acegisecurity.afterinvocation.AfterInvocationProviderManager">
<bean id="afterInvocationManager" class="org.acegisecurity.afterinvocation.AfterInvocationProviderManager">
<property name="providers">
<list>
<ref local="afterAclRead"/>
@ -107,38 +147,41 @@
</bean>
<!-- Processes AFTER_ACL_COLLECTION_READ configuration settings -->
<bean id="afterAclCollectionRead" class="net.sf.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationCollectionFilteringProvider">
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
<ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
</list>
</property>
<bean id="afterAclCollectionRead" class="org.acegisecurity.afterinvocation.AclEntryAfterInvocationCollectionFilteringProvider">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
<ref local="org.acegisecurity.acls.domain.BasePermission.READ"/>
</list>
</constructor-arg>
</bean>
<!-- Processes AFTER_ACL_READ configuration settings -->
<bean id="afterAclRead" class="net.sf.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationProvider">
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
<ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
</list>
</property>
<bean id="afterAclRead" class="org.acegisecurity.afterinvocation.AclEntryAfterInvocationProvider">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
<ref local="org.acegisecurity.acls.domain.BasePermission.READ"/>
</list>
</constructor-arg>
</bean>
<!-- ================= METHOD INVOCATION AUTHORIZATION ==================== -->
<bean id="attributes" class="net.sf.acegisecurity.annotation.SecurityAnnotationAttributes"/>
<bean id="attributes" class="org.acegisecurity.annotation.SecurityAnnotationAttributes"/>
<bean id="objectDefinitionSource" class="net.sf.acegisecurity.intercept.method.MethodDefinitionAttributes">
<bean id="objectDefinitionSource" class="org.acegisecurity.intercept.method.MethodDefinitionAttributes">
<property name="attributes"><ref local="attributes"/></property>
</bean>
<!-- We don't validate config attributes, as it's unsupported by MethodDefinitionAttributes -->
<bean id="securityInterceptor" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<bean id="securityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="validateConfigAttributes"><value>false</value></property>
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="accessDecisionManager"><ref bean="businessAccessDecisionManager"/></property>
@ -160,7 +203,7 @@
which in the above configuration is a JDK 5 Annotations Attributes-based source.
-->
<bean id="methodSecurityAdvisor"
class="net.sf.acegisecurity.intercept.method.aopalliance.MethodDefinitionSourceAdvisor"
class="org.acegisecurity.intercept.method.aopalliance.MethodDefinitionSourceAdvisor"
autowire="constructor" >
</bean>

View File

@ -31,7 +31,9 @@
</bean>
<bean id="dataSourcePopulator" class="sample.contact.DataSourcePopulator">
<property name="dataSource"><ref local="dataSource"/></property>
<property name="dataSource" ref="dataSource"/>
<property name="mutableAclService" ref="aclService"/>
<property name="platformTransactionManager" ref="transactionManager"/>
</bean>
<bean id="contactDao" class="sample.contact.ContactDaoSpring">
@ -42,7 +44,7 @@
<!-- Advised Contact Manager using Java 5 Annotations -->
<bean id="contactManager" class="sample.contact.annotation.ContactManagerBackend">
<property name="contactDao"><ref local="contactDao"/></property>
<property name="basicAclExtendedDao"><ref bean="basicAclExtendedDao"/></property>
<property name="mutableAclService"><ref bean="aclService"/></property>
</bean>
</beans>

View File

@ -33,10 +33,10 @@
<filter>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
<filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>net.sf.acegisecurity.util.FilterChainProxy</param-value>
<param-value>org.acegisecurity.util.FilterChainProxy</param-value>
</init-param>
</filter>
@ -64,7 +64,7 @@
to the WebApplicationContext
-->
<listener>
<listener-class>net.sf.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class>
<listener-class>org.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class>
</listener>
<!--

View File

@ -0,0 +1,16 @@
<%@ page import="org.acegisecurity.context.SecurityContextHolder" %>
<%@ page import="org.acegisecurity.Authentication" %>
<%@ page import="org.acegisecurity.ui.AccessDeniedHandlerImpl" %>
<h1>Sorry, access is denied</h1>
<p>
<%= request.getAttribute(AccessDeniedHandlerImpl.ACEGI_SECURITY_ACCESS_DENIED_EXCEPTION_KEY)%>
<p>
<% Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) { %>
Authentication object as a String: <%= auth.toString() %><BR><BR>
<% } %>

View File

@ -1,5 +0,0 @@
<html>
<title>Access denied!</title>
<h1>Access Denied</h1>
We're sorry, but you are not authorized to perform the requested operation.
</html>

View File

@ -12,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import org.acegisecurity.acl.basic.SimpleAclEntry;
@ -28,7 +27,7 @@ public class AddPermission {
//~ Instance fields ================================================================================================
public Contact contact;
public Integer permission = new Integer(SimpleAclEntry.NOTHING);
public Integer permission = new Integer(SimpleAclEntry.READ);
public String recipient;
//~ Methods ========================================================================================================

View File

@ -12,10 +12,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import org.acegisecurity.acl.basic.SimpleAclEntry;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.domain.BasePermission;
import org.acegisecurity.acls.sid.PrincipalSid;
import org.springframework.beans.factory.InitializingBean;
@ -59,7 +60,7 @@ public class AddPermissionController extends SimpleFormController implements Ini
protected ModelAndView disallowDuplicateFormSubmission(HttpServletRequest request, HttpServletResponse response)
throws Exception {
BindException errors = new BindException(formBackingObject(request), getCommandName());
errors.reject("err.duplicateFormSubmission", "Duplicate form submission.");
errors.reject("err.duplicateFormSubmission", "Duplicate form submission. *");
return showForm(request, response, errors);
}
@ -76,10 +77,6 @@ public class AddPermissionController extends SimpleFormController implements Ini
return addPermission;
}
public ContactManager getContactManager() {
return contactManager;
}
protected ModelAndView handleInvalidSubmit(HttpServletRequest request, HttpServletResponse response)
throws Exception {
return disallowDuplicateFormSubmission(request, response);
@ -87,16 +84,12 @@ public class AddPermissionController extends SimpleFormController implements Ini
private Map listPermissions(HttpServletRequest request) {
Map map = new LinkedHashMap();
map.put(new Integer(SimpleAclEntry.NOTHING),
getApplicationContext().getMessage("select.none", null, "None", request.getLocale()));
map.put(new Integer(SimpleAclEntry.ADMINISTRATION),
map.put(new Integer(BasePermission.ADMINISTRATION.getMask()),
getApplicationContext().getMessage("select.administer", null, "Administer", request.getLocale()));
map.put(new Integer(SimpleAclEntry.READ),
map.put(new Integer(BasePermission.READ.getMask()),
getApplicationContext().getMessage("select.read", null, "Read", request.getLocale()));
map.put(new Integer(SimpleAclEntry.DELETE),
map.put(new Integer(BasePermission.DELETE.getMask()),
getApplicationContext().getMessage("select.delete", null, "Delete", request.getLocale()));
map.put(new Integer(SimpleAclEntry.READ_WRITE_DELETE),
getApplicationContext().getMessage("select.readWriteDelete", null, "Read+Write+Delete", request.getLocale()));
return map;
}
@ -120,13 +113,14 @@ public class AddPermissionController extends SimpleFormController implements Ini
BindException errors) throws Exception {
AddPermission addPermission = (AddPermission) command;
PrincipalSid sid = new PrincipalSid(addPermission.getRecipient());
Permission permission = BasePermission.buildFromMask(addPermission.getPermission().intValue());
try {
contactManager.addPermission(addPermission.getContact(), addPermission.getRecipient(),
addPermission.getPermission());
contactManager.addPermission(addPermission.getContact(), sid, permission);
} catch (DataAccessException existingPermission) {
existingPermission.printStackTrace();
errors.rejectValue("recipient", "err.recipientExistsForContact",
"This recipient already has permissions to this contact.");
errors.rejectValue("recipient", "err.recipientExistsForContact", "Addition failure.");
return showForm(request, response, errors);
}

View File

@ -12,10 +12,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import org.acegisecurity.acl.basic.SimpleAclEntry;
import org.acegisecurity.acls.domain.BasePermission;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
@ -44,9 +43,8 @@ public class AddPermissionValidator implements Validator {
if (addPermission.getPermission() != null) {
int permission = addPermission.getPermission().intValue();
if ((permission != SimpleAclEntry.NOTHING) && (permission != SimpleAclEntry.ADMINISTRATION)
&& (permission != SimpleAclEntry.READ) && (permission != SimpleAclEntry.DELETE)
&& (permission != SimpleAclEntry.READ_WRITE_DELETE)) {
if ((permission != BasePermission.ADMINISTRATION.getMask())
&& (permission != BasePermission.READ.getMask()) && (permission != BasePermission.DELETE.getMask())) {
errors.rejectValue("permission", "err.permission.invalid", "The indicated permission is invalid. *");
}
}

View File

@ -12,11 +12,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import org.acegisecurity.acl.AclEntry;
import org.acegisecurity.acl.AclManager;
import org.acegisecurity.acls.Acl;
import org.acegisecurity.acls.AclService;
import org.acegisecurity.acls.objectidentity.ObjectIdentityImpl;
import org.springframework.beans.factory.InitializingBean;
@ -45,22 +45,14 @@ import javax.servlet.http.HttpServletResponse;
public class AdminPermissionController implements Controller, InitializingBean {
//~ Instance fields ================================================================================================
private AclManager aclManager;
private AclService aclService;
private ContactManager contactManager;
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
Assert.notNull(contactManager, "A ContactManager implementation is required");
Assert.notNull(aclManager, "An aclManager implementation is required");
}
public AclManager getAclManager() {
return aclManager;
}
public ContactManager getContactManager() {
return contactManager;
Assert.notNull(aclService, "An aclService implementation is required");
}
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
@ -68,17 +60,17 @@ public class AdminPermissionController implements Controller, InitializingBean {
int id = RequestUtils.getRequiredIntParameter(request, "contactId");
Contact contact = contactManager.getById(new Long(id));
AclEntry[] acls = aclManager.getAcls(contact);
Acl acl = aclService.readAclById(new ObjectIdentityImpl(contact));
Map model = new HashMap();
model.put("contact", contact);
model.put("acls", acls);
model.put("acl", acl);
return new ModelAndView("adminPermission", "model", model);
}
public void setAclManager(AclManager aclManager) {
this.aclManager = aclManager;
public void setAclService(AclService aclService) {
this.aclService = aclService;
}
public void setContactManager(ContactManager contact) {

View File

@ -12,9 +12,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.sid.Sid;
import java.util.List;
@ -27,13 +29,13 @@ import java.util.List;
public interface ContactManager {
//~ Methods ========================================================================================================
public void addPermission(Contact contact, String recipient, Integer permission);
public void addPermission(Contact contact, Sid recipient, Permission permission);
public void create(Contact contact);
public void delete(Contact contact);
public void deletePermission(Contact contact, String recipient);
public void deletePermission(Contact contact, Sid recipient, Permission permission);
public List getAll();

View File

@ -12,15 +12,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import org.acegisecurity.Authentication;
import org.acegisecurity.acl.basic.AclObjectIdentity;
import org.acegisecurity.acl.basic.BasicAclExtendedDao;
import org.acegisecurity.acl.basic.NamedEntityObjectIdentity;
import org.acegisecurity.acl.basic.SimpleAclEntry;
import org.acegisecurity.acls.AccessControlEntry;
import org.acegisecurity.acls.MutableAcl;
import org.acegisecurity.acls.MutableAclService;
import org.acegisecurity.acls.NotFoundException;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.domain.BasePermission;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.objectidentity.ObjectIdentityImpl;
import org.acegisecurity.acls.sid.PrincipalSid;
import org.acegisecurity.acls.sid.Sid;
import org.acegisecurity.context.SecurityContextHolder;
@ -45,27 +50,33 @@ import java.util.Random;
public class ContactManagerBackend extends ApplicationObjectSupport implements ContactManager, InitializingBean {
//~ Instance fields ================================================================================================
private BasicAclExtendedDao basicAclExtendedDao;
private ContactDao contactDao;
private MutableAclService mutableAclService;
private int counter = 1000;
//~ Methods ========================================================================================================
public void addPermission(Contact contact, String recipient, Integer permission) {
SimpleAclEntry simpleAclEntry = new SimpleAclEntry();
simpleAclEntry.setAclObjectIdentity(makeObjectIdentity(contact));
simpleAclEntry.setMask(permission.intValue());
simpleAclEntry.setRecipient(recipient);
basicAclExtendedDao.create(simpleAclEntry);
public void addPermission(Contact contact, Sid recipient, Permission permission) {
MutableAcl acl;
ObjectIdentity oid = new ObjectIdentityImpl(Contact.class, contact.getId());
try {
acl = (MutableAcl) mutableAclService.readAclById(oid);
} catch (NotFoundException nfe) {
acl = mutableAclService.createAcl(oid);
}
acl.insertAce(null, permission, recipient, true);
mutableAclService.updateAcl(acl);
if (logger.isDebugEnabled()) {
logger.debug("Added permission " + permission + " for recipient " + recipient + " contact " + contact);
logger.debug("Added permission " + permission + " for Sid " + recipient + " contact " + contact);
}
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(contactDao, "contactDao required");
Assert.notNull(basicAclExtendedDao, "basicAclExtendedDao required");
Assert.notNull(mutableAclService, "mutableAclService required");
}
public void create(Contact contact) {
@ -73,8 +84,8 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
contact.setId(new Long(counter++));
contactDao.create(contact);
// Grant the current principal access to the contact
addPermission(contact, getUsername(), new Integer(SimpleAclEntry.ADMINISTRATION));
// Grant the current principal administrative permission to the contact
addPermission(contact, new PrincipalSid(getUsername()), BasePermission.ADMINISTRATION);
if (logger.isDebugEnabled()) {
logger.debug("Created contact " + contact + " and granted admin permission to recipient " + getUsername());
@ -85,15 +96,28 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
contactDao.delete(contact.getId());
// Delete the ACL information as well
basicAclExtendedDao.delete(makeObjectIdentity(contact));
ObjectIdentity oid = new ObjectIdentityImpl(Contact.class, contact.getId());
mutableAclService.deleteAcl(oid, false);
if (logger.isDebugEnabled()) {
logger.debug("Deleted contact " + contact + " including ACL permissions");
}
}
public void deletePermission(Contact contact, String recipient) {
basicAclExtendedDao.delete(makeObjectIdentity(contact), recipient);
public void deletePermission(Contact contact, Sid recipient, Permission permission) {
ObjectIdentity oid = new ObjectIdentityImpl(Contact.class, contact.getId());
MutableAcl acl = (MutableAcl) mutableAclService.readAclById(oid);
// Remove all permissions associated with this particular recipient (string equality to KISS)
AccessControlEntry[] entries = acl.getEntries();
for (int i = 0; i < entries.length; i++) {
if (entries[i].getSid().equals(recipient) && entries[i].getPermission().equals(permission)) {
acl.deleteAce(entries[i].getId());
}
}
mutableAclService.updateAcl(acl);
if (logger.isDebugEnabled()) {
logger.debug("Deleted contact " + contact + " ACL permissions for recipient " + recipient);
@ -114,15 +138,10 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
}
List list = contactDao.findAllPrincipals();
list.addAll(contactDao.findAllRoles());
return list;
}
public BasicAclExtendedDao getBasicAclExtendedDao() {
return basicAclExtendedDao;
}
public Contact getById(Long id) {
if (logger.isDebugEnabled()) {
logger.debug("Returning contact with id: " + id);
@ -131,10 +150,6 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
return contactDao.getById(id);
}
public ContactDao getContactDao() {
return contactDao;
}
/**
* This is a public method.
*
@ -162,18 +177,14 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
}
}
private AclObjectIdentity makeObjectIdentity(Contact contact) {
return new NamedEntityObjectIdentity(contact.getClass().getName(), contact.getId().toString());
}
public void setBasicAclExtendedDao(BasicAclExtendedDao basicAclExtendedDao) {
this.basicAclExtendedDao = basicAclExtendedDao;
}
public void setContactDao(ContactDao contactDao) {
this.contactDao = contactDao;
}
public void setMutableAclService(MutableAclService mutableAclService) {
this.mutableAclService = mutableAclService;
}
public void update(Contact contact) {
contactDao.update(contact);

View File

@ -12,13 +12,34 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import org.acegisecurity.Authentication;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.acls.MutableAcl;
import org.acegisecurity.acls.MutableAclService;
import org.acegisecurity.acls.Permission;
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.PrincipalSid;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.Assert;
import java.util.Random;
@ -35,8 +56,10 @@ import javax.sql.DataSource;
public class DataSourcePopulator implements InitializingBean {
//~ Instance fields ================================================================================================
private DataSource dataSource;
JdbcTemplate template;
private MutableAclService mutableAclService;
Random rnd = new Random();
TransactionTemplate tt;
String[] firstNames = {
"Bob", "Mary", "James", "Jane", "Kristy", "Kirsty", "Kate", "Jeni", "Angela", "Melanie", "Kent", "William",
"Geoff", "Jeff", "Adrian", "Amanda", "Lisa", "Elizabeth", "Prue", "Richard", "Darin", "Phillip", "Michael",
@ -47,91 +70,28 @@ public class DataSourcePopulator implements InitializingBean {
"Edwards", "Gates", "Black", "Brown", "Gray", "Marwell", "Booch", "Johnson", "McTaggart", "Parklin",
"Findlay", "Robinson", "Giugni", "Lang", "Chi", "Carmichael"
};
private int createEntities = 1000;
private int createEntities = 50;
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
Assert.notNull(dataSource, "dataSource required");
Assert.notNull(mutableAclService, "mutableAclService required");
Assert.notNull(template, "dataSource required");
Assert.notNull(tt, "platformTransactionManager required");
JdbcTemplate template = new JdbcTemplate(dataSource);
// Set a user account that will initially own all the created data
Authentication authRequest = new UsernamePasswordAuthenticationToken("marissa", "koala",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_IGNORED")});
SecurityContextHolder.getContext().setAuthentication(authRequest);
template.execute(
"CREATE TABLE CONTACTS(ID BIGINT NOT NULL PRIMARY KEY, CONTACT_NAME VARCHAR_IGNORECASE(50) NOT NULL, EMAIL VARCHAR_IGNORECASE(50) NOT NULL)");
template.execute("INSERT INTO contacts VALUES (1, 'John Smith', 'john@somewhere.com');"); // marissa
template.execute("INSERT INTO contacts VALUES (2, 'Michael Citizen', 'michael@xyz.com');"); // marissa
template.execute("INSERT INTO contacts VALUES (3, 'Joe Bloggs', 'joe@demo.com');"); // marissa
template.execute("INSERT INTO contacts VALUES (4, 'Karen Sutherland', 'karen@sutherland.com');"); // marissa + dianne + scott
template.execute("INSERT INTO contacts VALUES (5, 'Mitchell Howard', 'mitchell@abcdef.com');"); // dianne
template.execute("INSERT INTO contacts VALUES (6, 'Rose Costas', 'rose@xyz.com');"); // dianne + scott
template.execute("INSERT INTO contacts VALUES (7, 'Amanda Smith', 'amanda@abcdef.com');"); // scott
template.execute("INSERT INTO contacts VALUES (8, 'Cindy Smith', 'cindy@smith.com');"); // dianne + scott
template.execute("INSERT INTO contacts VALUES (9, 'Jonathan Citizen', 'jonathan@xyz.com');"); // scott
for (int i = 10; i < createEntities; i++) {
String[] person = selectPerson();
template.execute("INSERT INTO contacts VALUES (" + i + ", '" + person[2] + "', '" + person[0].toLowerCase()
+ "@" + person[1].toLowerCase() + ".com');");
}
"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));");
template.execute(
"CREATE TABLE ACL_OBJECT_IDENTITY(ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,OBJECT_IDENTITY VARCHAR_IGNORECASE(250) NOT NULL,PARENT_OBJECT BIGINT,ACL_CLASS VARCHAR_IGNORECASE(250) NOT NULL,CONSTRAINT UNIQUE_OBJECT_IDENTITY UNIQUE(OBJECT_IDENTITY),CONSTRAINT SYS_FK_3 FOREIGN KEY(PARENT_OBJECT) REFERENCES ACL_OBJECT_IDENTITY(ID))");
"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));");
template.execute(
"INSERT INTO acl_object_identity VALUES (1, 'sample.contact.Contact:1', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
"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));");
template.execute(
"INSERT INTO acl_object_identity VALUES (2, 'sample.contact.Contact:2', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (3, 'sample.contact.Contact:3', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (4, 'sample.contact.Contact:4', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (5, 'sample.contact.Contact:5', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (6, 'sample.contact.Contact:6', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (7, 'sample.contact.Contact:7', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (8, 'sample.contact.Contact:8', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (9, 'sample.contact.Contact:9', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
for (int i = 10; i < createEntities; i++) {
template.execute("INSERT INTO acl_object_identity VALUES (" + i + ", 'sample.contact.Contact:" + i
+ "', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
}
template.execute(
"CREATE TABLE ACL_PERMISSION(ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,ACL_OBJECT_IDENTITY BIGINT NOT NULL,RECIPIENT VARCHAR_IGNORECASE(100) NOT NULL,MASK INTEGER NOT NULL,CONSTRAINT UNIQUE_RECIPIENT UNIQUE(ACL_OBJECT_IDENTITY,RECIPIENT),CONSTRAINT SYS_FK_7 FOREIGN KEY(ACL_OBJECT_IDENTITY) REFERENCES ACL_OBJECT_IDENTITY(ID))");
template.execute("INSERT INTO acl_permission VALUES (null, 1, 'marissa', 1);"); // administer
template.execute("INSERT INTO acl_permission VALUES (null, 2, 'marissa', 2);"); // read
template.execute("INSERT INTO acl_permission VALUES (null, 3, 'marissa', 22);"); // read+write+delete
template.execute("INSERT INTO acl_permission VALUES (null, 4, 'marissa', 1);"); // administer
template.execute("INSERT INTO acl_permission VALUES (null, 4, 'dianne', 1);"); // administer
template.execute("INSERT INTO acl_permission VALUES (null, 4, 'scott', 2);"); // read
template.execute("INSERT INTO acl_permission VALUES (null, 5, 'dianne', 2);"); // read
template.execute("INSERT INTO acl_permission VALUES (null, 6, 'dianne', 22);"); // read+write+delete
template.execute("INSERT INTO acl_permission VALUES (null, 6, 'scott', 2);"); // read
template.execute("INSERT INTO acl_permission VALUES (null, 7, 'scott', 1);"); // administer
template.execute("INSERT INTO acl_permission VALUES (null, 8, 'dianne', 2);"); // read
template.execute("INSERT INTO acl_permission VALUES (null, 8, 'scott', 2);"); // read
template.execute("INSERT INTO acl_permission VALUES (null, 9, 'scott', 22);"); // read+write+delete
String[] users = {"bill", "bob", "jane"}; // don't want to mess around with consistent sample data
int[] permissions = {1, 2, 22};
for (int i = 10; i < createEntities; i++) {
String user = users[rnd.nextInt(users.length)];
int permission = permissions[rnd.nextInt(permissions.length)];
template.execute("INSERT INTO acl_permission VALUES (null, " + i + ", '" + user + "', " + permission + ");");
String user2 = users[rnd.nextInt(users.length)];
int permission2 = permissions[rnd.nextInt(permissions.length)];
if (!user2.equals(user)) {
template.execute("INSERT INTO acl_permission VALUES (null, " + i + ", '" + user2 + "', " + permission2
+ ");");
}
}
"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));");
template.execute(
"CREATE TABLE USERS(USERNAME VARCHAR_IGNORECASE(50) NOT NULL PRIMARY KEY,PASSWORD VARCHAR_IGNORECASE(50) NOT NULL,ENABLED BOOLEAN NOT NULL);");
@ -139,6 +99,9 @@ public class DataSourcePopulator implements InitializingBean {
"CREATE TABLE AUTHORITIES(USERNAME VARCHAR_IGNORECASE(50) NOT NULL,AUTHORITY VARCHAR_IGNORECASE(50) NOT NULL,CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY(USERNAME) REFERENCES USERS(USERNAME));");
template.execute("CREATE UNIQUE INDEX IX_AUTH_USERNAME ON AUTHORITIES(USERNAME,AUTHORITY);");
template.execute(
"CREATE TABLE CONTACTS(ID BIGINT NOT NULL PRIMARY KEY, CONTACT_NAME VARCHAR_IGNORECASE(50) NOT NULL, EMAIL VARCHAR_IGNORECASE(50) NOT NULL)");
/*
Passwords encoded using MD5, NOT in Base64 format, with null as salt
Encoded password for marissa is "koala"
@ -165,14 +128,100 @@ public class DataSourcePopulator implements InitializingBean {
template.execute("INSERT INTO AUTHORITIES VALUES('bill','ROLE_USER');");
template.execute("INSERT INTO AUTHORITIES VALUES('bob','ROLE_USER');");
template.execute("INSERT INTO AUTHORITIES VALUES('jane','ROLE_USER');");
template.execute("INSERT INTO contacts VALUES (1, 'John Smith', 'john@somewhere.com');");
template.execute("INSERT INTO contacts VALUES (2, 'Michael Citizen', 'michael@xyz.com');");
template.execute("INSERT INTO contacts VALUES (3, 'Joe Bloggs', 'joe@demo.com');");
template.execute("INSERT INTO contacts VALUES (4, 'Karen Sutherland', 'karen@sutherland.com');");
template.execute("INSERT INTO contacts VALUES (5, 'Mitchell Howard', 'mitchell@abcdef.com');");
template.execute("INSERT INTO contacts VALUES (6, 'Rose Costas', 'rose@xyz.com');");
template.execute("INSERT INTO contacts VALUES (7, 'Amanda Smith', 'amanda@abcdef.com');");
template.execute("INSERT INTO contacts VALUES (8, 'Cindy Smith', 'cindy@smith.com');");
template.execute("INSERT INTO contacts VALUES (9, 'Jonathan Citizen', 'jonathan@xyz.com');");
for (int i = 10; i < createEntities; i++) {
String[] person = selectPerson();
template.execute("INSERT INTO contacts VALUES (" + i + ", '" + person[2] + "', '" + person[0].toLowerCase()
+ "@" + person[1].toLowerCase() + ".com');");
}
// Create acl_object_identity rows (and also acl_class rows as needed
for (int i = 1; i < createEntities; i++) {
final ObjectIdentity objectIdentity = new ObjectIdentityImpl(Contact.class, new Long(i));
tt.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus arg0) {
MutableAcl acl = mutableAclService.createAcl(objectIdentity);
return null;
}
});
}
// Now grant some permissions
grantPermissions(1, "marissa", BasePermission.ADMINISTRATION);
grantPermissions(2, "marissa", BasePermission.READ);
grantPermissions(3, "marissa", BasePermission.READ);
grantPermissions(3, "marissa", BasePermission.WRITE);
grantPermissions(3, "marissa", BasePermission.DELETE);
grantPermissions(4, "marissa", BasePermission.ADMINISTRATION);
grantPermissions(4, "dianne", BasePermission.ADMINISTRATION);
grantPermissions(4, "scott", BasePermission.READ);
grantPermissions(5, "dianne", BasePermission.ADMINISTRATION);
grantPermissions(5, "dianne", BasePermission.READ);
grantPermissions(6, "dianne", BasePermission.READ);
grantPermissions(6, "dianne", BasePermission.WRITE);
grantPermissions(6, "dianne", BasePermission.DELETE);
grantPermissions(6, "scott", BasePermission.READ);
grantPermissions(7, "scott", BasePermission.ADMINISTRATION);
grantPermissions(8, "dianne", BasePermission.ADMINISTRATION);
grantPermissions(8, "dianne", BasePermission.READ);
grantPermissions(8, "scott", BasePermission.READ);
grantPermissions(9, "scott", BasePermission.ADMINISTRATION);
grantPermissions(9, "scott", BasePermission.READ);
grantPermissions(9, "scott", BasePermission.WRITE);
grantPermissions(9, "scott", BasePermission.DELETE);
// Now expressly change the owner of the first ten contacts
// We have to do this last, because "marissa" owns all of them (doing it sooner would prevent ACL updates)
// Note that ownership has no impact on permissions - they're separate (ownership only allows ACl editing)
changeOwner(5, "dianne");
changeOwner(6, "dianne");
changeOwner(7, "scott");
changeOwner(8, "dianne");
changeOwner(9, "scott");
String[] users = {"bill", "bob", "jane"}; // don't want to mess around with consistent sample data
Permission[] permissions = {BasePermission.ADMINISTRATION, BasePermission.READ, BasePermission.DELETE};
for (int i = 10; i < createEntities; i++) {
String user = users[rnd.nextInt(users.length)];
Permission permission = permissions[rnd.nextInt(permissions.length)];
grantPermissions(i, user, permission);
String user2 = users[rnd.nextInt(users.length)];
Permission permission2 = permissions[rnd.nextInt(permissions.length)];
grantPermissions(i, user2, permission2);
}
SecurityContextHolder.clearContext();
}
private void changeOwner(int contactNumber, String newOwnerUsername) {
AclImpl acl = (AclImpl) mutableAclService.readAclById(new ObjectIdentityImpl(Contact.class,
new Long(contactNumber)));
acl.setOwner(new PrincipalSid(newOwnerUsername));
updateAclInTransaction(acl);
}
public int getCreateEntities() {
return createEntities;
}
public DataSource getDataSource() {
return dataSource;
private void grantPermissions(int contactNumber, String recipientUsername, Permission permission) {
AclImpl acl = (AclImpl) mutableAclService.readAclById(new ObjectIdentityImpl(Contact.class,
new Long(contactNumber)));
acl.insertAce(null, permission, new PrincipalSid(recipientUsername), true);
updateAclInTransaction(acl);
}
private String[] selectPerson() {
@ -187,6 +236,24 @@ public class DataSourcePopulator implements InitializingBean {
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.template = new JdbcTemplate(dataSource);
}
public void setMutableAclService(MutableAclService mutableAclService) {
this.mutableAclService = mutableAclService;
}
public void setPlatformTransactionManager(PlatformTransactionManager platformTransactionManager) {
this.tt = new TransactionTemplate(platformTransactionManager);
}
private void updateAclInTransaction(final MutableAcl acl) {
tt.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus arg0) {
mutableAclService.updateAcl(acl);
return null;
}
});
}
}

View File

@ -12,10 +12,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import org.acegisecurity.acl.AclManager;
import org.acegisecurity.acls.AclService;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.domain.BasePermission;
import org.acegisecurity.acls.sid.PrincipalSid;
import org.acegisecurity.acls.sid.Sid;
import org.springframework.beans.factory.InitializingBean;
@ -44,42 +47,40 @@ import javax.servlet.http.HttpServletResponse;
public class DeletePermissionController implements Controller, InitializingBean {
//~ Instance fields ================================================================================================
private AclManager aclManager;
private AclService aclService;
private ContactManager contactManager;
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
Assert.notNull(contactManager, "A ContactManager implementation is required");
Assert.notNull(aclManager, "An aclManager implementation is required");
}
public AclManager getAclManager() {
return aclManager;
}
public ContactManager getContactManager() {
return contactManager;
Assert.notNull(aclService, "An aclService implementation is required");
}
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// <c:param name="sid" value="${acl.sid.principal}"/><c:param name="permission" value="${acl.permission.mask}"/></c:url>">Del</A>
int contactId = RequestUtils.getRequiredIntParameter(request, "contactId");
String recipient = RequestUtils.getRequiredStringParameter(request, "recipient");
String sid = RequestUtils.getRequiredStringParameter(request, "sid");
int mask = RequestUtils.getRequiredIntParameter(request, "permission");
Contact contact = contactManager.getById(new Long(contactId));
contactManager.deletePermission(contact, recipient);
Sid sidObject = new PrincipalSid(sid);
Permission permission = BasePermission.buildFromMask(mask);
contactManager.deletePermission(contact, sidObject, permission);
Map model = new HashMap();
model.put("contact", contact);
model.put("recipient", recipient);
model.put("sid", sidObject);
model.put("permission", permission);
return new ModelAndView("deletePermission", "model", model);
}
public void setAclManager(AclManager aclManager) {
this.aclManager = aclManager;
public void setAclService(AclService aclService) {
this.aclService = aclService;
}
public void setContactManager(ContactManager contact) {

View File

@ -22,14 +22,14 @@
<!-- ~~~~~~~~~~~~~~~~~~ "BEFORE INVOCATION" AUTHORIZATION DEFINITIONS ~~~~~~~~~~~~~~~~ -->
<!-- ACL permission masks used by this application -->
<bean id="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION</value></property>
<bean id="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION</value></property>
</bean>
<bean id="org.acegisecurity.acl.basic.SimpleAclEntry.READ" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>org.acegisecurity.acl.basic.SimpleAclEntry.READ</value></property>
<bean id="org.acegisecurity.acls.domain.BasePermission.READ" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>org.acegisecurity.acls.domain.BasePermission.READ</value></property>
</bean>
<bean id="org.acegisecurity.acl.basic.SimpleAclEntry.DELETE" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>org.acegisecurity.acl.basic.SimpleAclEntry.DELETE</value></property>
<bean id="org.acegisecurity.acls.domain.BasePermission.DELETE" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>org.acegisecurity.acls.domain.BasePermission.DELETE</value></property>
</bean>
@ -37,41 +37,53 @@
<bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter"/>
<!-- An access decision voter that reads ACL_CONTACT_READ configuration settings -->
<bean id="aclContactReadVoter" class="org.acegisecurity.vote.BasicAclEntryVoter">
<property name="processConfigAttribute"><value>ACL_CONTACT_READ</value></property>
<bean id="aclContactReadVoter" class="org.acegisecurity.vote.AclEntryVoter">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<value>ACL_CONTACT_READ</value>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
<ref local="org.acegisecurity.acls.domain.BasePermission.READ"/>
</list>
</constructor-arg>
<property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
<ref local="org.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
</list>
</property>
</bean>
<!-- An access decision voter that reads ACL_CONTACT_DELETE configuration settings -->
<bean id="aclContactDeleteVoter" class="org.acegisecurity.vote.BasicAclEntryVoter">
<property name="processConfigAttribute"><value>ACL_CONTACT_DELETE</value></property>
<bean id="aclContactDeleteVoter" class="org.acegisecurity.vote.AclEntryVoter">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<value>ACL_CONTACT_DELETE</value>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
<ref local="org.acegisecurity.acls.domain.BasePermission.DELETE"/>
</list>
</constructor-arg>
<property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
<ref local="org.acegisecurity.acl.basic.SimpleAclEntry.DELETE"/>
</list>
</property>
</bean>
<!-- An access decision voter that reads ACL_CONTACT_ADMIN configuration settings -->
<bean id="aclContactAdminVoter" class="org.acegisecurity.vote.BasicAclEntryVoter">
<property name="processConfigAttribute"><value>ACL_CONTACT_ADMIN</value></property>
<bean id="aclContactAdminVoter" class="org.acegisecurity.vote.AclEntryVoter">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<value>ACL_CONTACT_ADMIN</value>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
</list>
</constructor-arg>
<property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
</list>
</property>
</bean>
<!-- An access decision manager used by the business objects -->
@ -89,21 +101,49 @@
<!-- ========= ACCESS CONTROL LIST LOOKUP MANAGER DEFINITIONS ========= -->
<bean id="aclManager" class="org.acegisecurity.acl.AclProviderManager">
<property name="providers">
<list>
<ref local="basicAclProvider"/>
</list>
</property>
</bean>
<bean id="basicAclProvider" class="org.acegisecurity.acl.basic.BasicAclProvider">
<property name="basicAclDao"><ref local="basicAclExtendedDao"/></property>
</bean>
<bean id="basicAclExtendedDao" class="org.acegisecurity.acl.basic.jdbc.JdbcExtendedDaoImpl">
<property name="dataSource"><ref bean="dataSource"/></property>
</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 ref="aclAuthorizationStrategy"/>
<constructor-arg>
<bean class="org.acegisecurity.acls.domain.ConsoleAuditLogger"/>
</constructor-arg>
</bean>
<bean id="aclAuthorizationStrategy" class="org.acegisecurity.acls.domain.AclAuthorizationStrategyImpl">
<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.JdbcMutableAclService">
<constructor-arg ref="dataSource"/>
<constructor-arg ref="lookupStrategy"/>
<constructor-arg ref="aclCache"/>
</bean>
<!-- ============== "AFTER INTERCEPTION" AUTHORIZATION DEFINITIONS =========== -->
@ -117,28 +157,31 @@
</bean>
<!-- Processes AFTER_ACL_COLLECTION_READ configuration settings -->
<bean id="afterAclCollectionRead" class="org.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationCollectionFilteringProvider">
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
<ref local="org.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
</list>
</property>
<bean id="afterAclCollectionRead" class="org.acegisecurity.afterinvocation.AclEntryAfterInvocationCollectionFilteringProvider">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
<ref local="org.acegisecurity.acls.domain.BasePermission.READ"/>
</list>
</constructor-arg>
</bean>
<!-- Processes AFTER_ACL_READ configuration settings -->
<bean id="afterAclRead" class="org.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationProvider">
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
<ref local="org.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
</list>
</property>
<bean id="afterAclRead" class="org.acegisecurity.afterinvocation.AclEntryAfterInvocationProvider">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
<ref local="org.acegisecurity.acls.domain.BasePermission.READ"/>
</list>
</constructor-arg>
</bean>
<!-- ================= METHOD INVOCATION AUTHORIZATION ==================== -->
<!-- getRandomContact() is public.

View File

@ -16,7 +16,8 @@
<value>org.hsqldb.jdbcDriver</value>
</property>
<property name="url">
<value>jdbc:hsqldb:mem:contacts</value>
<value>jdbc:hsqldb:mem:test</value>
<!-- <value>jdbc:hsqldb:hsql://localhost/acl</value> -->
</property>
<property name="username">
<value>sa</value>
@ -46,7 +47,9 @@
</bean>
<bean id="dataSourcePopulator" class="sample.contact.DataSourcePopulator">
<property name="dataSource"><ref local="dataSource"/></property>
<property name="dataSource" ref="dataSource"/>
<property name="mutableAclService" ref="aclService"/>
<property name="platformTransactionManager" ref="transactionManager"/>
</bean>
<bean id="contactDao" class="sample.contact.ContactDaoSpring">
@ -66,7 +69,7 @@
<bean id="contactManagerTarget" class="sample.contact.ContactManagerBackend">
<property name="contactDao"><ref local="contactDao"/></property>
<property name="basicAclExtendedDao"><ref bean="basicAclExtendedDao"/></property>
<property name="mutableAclService"><ref bean="aclService"/></property>
</bean>
</beans>

View File

@ -29,12 +29,12 @@
<bean id="adminPermissionController" class="sample.contact.AdminPermissionController">
<property name="contactManager"><ref bean="contactManager"/></property>
<property name="aclManager"><ref bean="aclManager"/></property>
<property name="aclService"><ref bean="aclService"/></property>
</bean>
<bean id="deletePermissionController" class="sample.contact.DeletePermissionController">
<property name="contactManager"><ref bean="contactManager"/></property>
<property name="aclManager"><ref bean="aclManager"/></property>
<property name="aclService"><ref bean="aclService"/></property>
</bean>
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

View File

@ -1,4 +1,3 @@
<%@ page import="org.acegisecurity.acl.basic.SimpleAclEntry" %>
<%@ include file="/WEB-INF/jsp/include.jsp" %>
<html>
@ -11,27 +10,17 @@
</code>
<P>
<table cellpadding=3 border=0>
<c:forEach var="acl" items="${model.acls}">
<c:if test="${acl.class.name eq 'org.acegisecurity.acl.basic.SimpleAclEntry'}">
<c:forEach var="acl" items="${model.acl.entries}">
<tr>
<td>
<code>
<%
SimpleAclEntry simpleAcl = ((SimpleAclEntry) pageContext.getAttribute("acl"));
String permissionBlock = simpleAcl.printPermissionsBlock();
%>
<%= permissionBlock %>
[<c:out value="${acl.mask}"/>]
<c:out value="${acl.recipient}"/>
<c:out value="${acl}"/>
</code>
</td>
<td>
<!-- This application doesn't use ACL inheritance, so we can safely use
the model's contact and know it was directly assigned the ACL -->
<A HREF="<c:url value="deletePermission.htm"><c:param name="contactId" value="${model.contact.id}"/><c:param name="recipient" value="${acl.recipient}"/></c:url>">Del</A>
<A HREF="<c:url value="deletePermission.htm"><c:param name="contactId" value="${model.contact.id}"/><c:param name="sid" value="${acl.sid.principal}"/><c:param name="permission" value="${acl.permission.mask}"/></c:url>">Del</A>
</td>
</tr>
</c:if>
</c:forEach>
</table>
<p><a href="<c:url value="addPermission.htm"><c:param name="contactId" value="${model.contact.id}"/></c:url>">Add Permission</a> <a href="<c:url value="index.htm"/>">Manage</a>

View File

@ -1,4 +1,3 @@
<%@ page import="org.acegisecurity.acl.basic.SimpleAclEntry" %>
<%@ include file="/WEB-INF/jsp/include.jsp" %>
<html>
@ -11,8 +10,11 @@
</code>
<P>
<code>
<c:out value="${model.recipient}"/>
<c:out value="${model.sid}"/>
</code>
<code>
<c:out value="${model.permission}"/>
</code>
<p><a href="<c:url value="index.htm"/>">Manage</a>
</body>
</html>

View File

@ -18,12 +18,12 @@
<td>
<c:out value="${contact.email}"/>
</td>
<authz:acl domainObject="${contact}" hasPermission="16,1">
<authz:accesscontrollist domainObject="${contact}" hasPermission="8,16">
<td><A HREF="<c:url value="del.htm"><c:param name="contactId" value="${contact.id}"/></c:url>">Del</A></td>
</authz:acl>
<authz:acl domainObject="${contact}" hasPermission="1">
</authz:accesscontrollist>
<authz:accesscontrollist domainObject="${contact}" hasPermission="16">
<td><A HREF="<c:url value="adminPermission.htm"><c:param name="contactId" value="${contact.id}"/></c:url>">Admin Permission</A></td>
</authz:acl>
</authz:accesscontrollist>
</tr>
</c:forEach>
</table>

View File

@ -1,115 +0,0 @@
package sample.contact;
import java.util.Iterator;
import java.util.List;
import org.acegisecurity.Authentication;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.context.SecurityContextImpl;
import org.acegisecurity.context.SecurityContextHolder;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.test.AbstractTransactionalSpringContextTests;
/**
* Provides simplified access to the <code>ContactManager</code> bean and
* convenience test support methods.
*
* @author David Leal
* @author Ben Alex
*/
public abstract class AbstractContactsSampleTest extends AbstractTransactionalSpringContextTests {
protected ContactManager contactManager;
protected String[] getConfigLocations() {
setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME);
return new String[] { "applicationContext-common-authorization.xml",
"applicationContext-common-business.xml",
"applicationContext-contacts-test.xml" };
}
/**
* Locates the first <code>Contact</code> of the exact name specified.
*
* <p>
* Uses the {@link ContactManager#getAll()} method.
* </p>
*
* @param id
* Identify of the contact to locate (must be an exact match)
*
* @return the domain or <code>null</code> if not found
*/
protected Contact getContact(String id) {
List contacts = contactManager.getAll();
Iterator iter = contacts.iterator();
while (iter.hasNext()) {
Contact contact = (Contact) iter.next();
if (contact.getId().equals(id)) {
return contact;
}
}
return null;
}
protected void assertContainsContact(String id, List contacts) {
Iterator iter = contacts.iterator();
System.out.println(contacts);
while (iter.hasNext()) {
Contact contact = (Contact) iter.next();
if (contact.getId().toString().equals(id)) {
return;
}
}
fail("List of contacts should have contained: " + id);
}
protected void assertNotContainsContact(String id, List contacts) {
Iterator iter = contacts.iterator();
while (iter.hasNext()) {
Contact domain = (Contact) iter.next();
if (domain.getId().toString().equals(id)) {
fail("List of contact should NOT (but did) contain: " + id);
}
}
}
protected void makeActiveUser(String username) {
String password = "";
if ("marissa".equals(username)) {
password = "koala";
} else if ("dianne".equals(username)) {
password = "emu";
} else if ("scott".equals(username)) {
password = "wombat";
} else if ("peter".equals(username)) {
password = "opal";
}
Authentication authRequest = new UsernamePasswordAuthenticationToken(
username, password);
SecurityContextImpl secureContext = new SecurityContextImpl();
secureContext.setAuthentication(authRequest);
SecurityContextHolder.setContext(secureContext);
}
protected void onTearDownInTransaction() {
destroySecureContext();
}
private static void destroySecureContext() {
SecurityContextHolder.setContext(new SecurityContextImpl());
}
public void setContactManager(ContactManager contactManager) {
this.contactManager = contactManager;
}
}

View File

@ -12,68 +12,174 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import org.acegisecurity.Authentication;
import org.acegisecurity.acls.domain.BasePermission;
import org.acegisecurity.acls.sid.PrincipalSid;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.test.AbstractTransactionalSpringContextTests;
import java.util.Iterator;
import java.util.List;
/**
* Tests {@link
* com.acegitech.dns.domain.DomainManager#findAllDomainsLike(String)}.
* Tests {@link ContactManager}.
*
* @author David Leal
* @author Ben Alex
*/
public class GetAllContactsTests extends AbstractContactsSampleTest {
//~ Methods ================================================================
public class GetAllContactsTests extends AbstractTransactionalSpringContextTests {
//~ Instance fields ================================================================================================
public void testFindAllDomainsLikeAsDianne() {
protected ContactManager contactManager;
//~ Methods ========================================================================================================
protected void assertContainsContact(String id, List contacts) {
Iterator iter = contacts.iterator();
System.out.println(contacts);
while (iter.hasNext()) {
Contact contact = (Contact) iter.next();
if (contact.getId().toString().equals(id)) {
return;
}
}
fail("List of contacts should have contained: " + id);
}
protected void assertNotContainsContact(String id, List contacts) {
Iterator iter = contacts.iterator();
while (iter.hasNext()) {
Contact domain = (Contact) iter.next();
if (domain.getId().toString().equals(id)) {
fail("List of contact should NOT (but did) contain: " + id);
}
}
}
private static void destroySecureContext() {
SecurityContextHolder.clearContext();
}
protected String[] getConfigLocations() {
setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME);
return new String[] {
"applicationContext-common-authorization.xml", "applicationContext-common-business.xml",
"applicationContext-contacts-test.xml"
};
}
/**
* Locates the first <code>Contact</code> of the exact name specified.<p>Uses the {@link
* ContactManager#getAll()} method.</p>
*
* @param id Identify of the contact to locate (must be an exact match)
*
* @return the domain or <code>null</code> if not found
*/
protected Contact getContact(String id) {
List contacts = contactManager.getAll();
Iterator iter = contacts.iterator();
while (iter.hasNext()) {
Contact contact = (Contact) iter.next();
if (contact.getId().equals(id)) {
return contact;
}
}
return null;
}
protected void makeActiveUser(String username) {
String password = "";
if ("marissa".equals(username)) {
password = "koala";
} else if ("dianne".equals(username)) {
password = "emu";
} else if ("scott".equals(username)) {
password = "wombat";
} else if ("peter".equals(username)) {
password = "opal";
}
Authentication authRequest = new UsernamePasswordAuthenticationToken(username, password);
SecurityContextHolder.getContext().setAuthentication(authRequest);
}
protected void onTearDownInTransaction() {
destroySecureContext();
}
public void setContactManager(ContactManager contactManager) {
this.contactManager = contactManager;
}
public void testDianne() {
makeActiveUser("dianne"); // has ROLE_USER
List contacts = contactManager.getAll();
assertEquals(4, contacts.size());
assertContainsContact(Long.toString(4), contacts);
assertContainsContact(Long.toString(5), contacts);
assertContainsContact(Long.toString(6), contacts);
assertContainsContact(Long.toString(8), contacts);
assertNotContainsContact(Long.toString(1), contacts);
assertNotContainsContact(Long.toString(2), contacts);
assertNotContainsContact(Long.toString(3), contacts);
}
public void testFindAllDomainsLikeAsMarissa() {
public void testMarissa() {
makeActiveUser("marissa"); // has ROLE_SUPERVISOR
List contacts = contactManager.getAll();
List contacts = contactManager.getAll();
assertEquals(4, contacts.size());
assertContainsContact(Long.toString(1), contacts);
assertContainsContact(Long.toString(2), contacts);
assertContainsContact(Long.toString(3), contacts);
assertContainsContact(Long.toString(4), contacts);
assertNotContainsContact(Long.toString(5), contacts);
assertNotContainsContact(Long.toString(5), contacts);
Contact c1 = contactManager.getById(new Long(4));
contactManager.deletePermission(c1, new PrincipalSid("bob"), BasePermission.ADMINISTRATION);
}
public void testFindAllDomainsLikeAsScott() {
public void testScott() {
makeActiveUser("scott"); // has ROLE_USER
List contacts = contactManager.getAll();
assertEquals(5, contacts.size());
assertEquals(5, contacts.size());
assertContainsContact(Long.toString(4), contacts);
assertContainsContact(Long.toString(6), contacts);
assertContainsContact(Long.toString(7), contacts);
assertContainsContact(Long.toString(8), contacts);
assertContainsContact(Long.toString(9), contacts);
assertNotContainsContact(Long.toString(1), contacts);
assertNotContainsContact(Long.toString(1), contacts);
}
}

View File

@ -1,106 +0,0 @@
/* 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;
/**
* DOCUMENT ME!
*
* @author $author$
* @version $Revision$
*/
public class BasePermission implements Permission {
//~ Static fields/initializers =====================================================================================
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 DELETE = new BasePermission(1 << 3, 'D'); // 8
public static final Permission ADMINISTRATION = new BasePermission(1 << 4, 'A'); // 16
//~ Instance fields ================================================================================================
private char code;
private int mask;
//~ Constructors ===================================================================================================
private BasePermission(int mask, char code) {
this.mask = mask;
this.code = code;
}
//~ Methods ========================================================================================================
/**
* Dynamically creates a <code>CumulativePermission</code> representing the active bits in the passed mask.
* NB: Only uses <code>BasePermission</code>!
*
* @param mask to review
*
* @return DOCUMENT ME!
*/
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(DELETE);
}
if (mask == 16) {
permission.set(ADMINISTRATION);
}
return permission;
}
public boolean equals(Object arg0) {
if (!(arg0 instanceof BasePermission)) {
return false;
}
BasePermission rhs = (BasePermission) arg0;
return (this.mask == rhs.getMask());
}
public int getMask() {
return mask;
}
public String getPattern() {
return AclFormattingUtils.printBinary(mask, code);
}
public String toString() {
return "BasePermission[" + getPattern() + "=" + mask + "]";
}
}

View File

@ -1,78 +0,0 @@
/* 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.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;
import java.util.Map;
import javax.sql.DataSource;
/**
* 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.</p>
*
* @author Ben Alex
* @version $Id$
*/
public class JdbcAclService implements AclService /*, MutableAclService */ {
//~ Instance fields ================================================================================================
private AclCache aclCache;
private JdbcTemplate template;
private LookupStrategy lookupStrategy;
//~ Constructors ===================================================================================================
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;
}
//~ Methods ========================================================================================================
public Map readAclsById(ObjectIdentity[] objects) {
return readAclsById(objects, null);
}
/**
* Method required by interface.
*
* @param objects DOCUMENT ME!
* @param sids DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws NotFoundException DOCUMENT ME!
*/
public Map readAclsById(ObjectIdentity[] objects, Sid[] sids)
throws NotFoundException {
return lookupStrategy.readAclsById(objects, sids);
}
}

View File

@ -1,5 +0,0 @@
<html>
<body>
Enables retrieval of access control lists (ACLs) for domain object instances.
</body>
</html>

View File

@ -1,65 +0,0 @@
/* 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.Acl;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.objectidentity.ObjectIdentityImpl;
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
import java.util.Iterator;
import java.util.Map;
/**
* DOCUMENT ME!
*
* @author $author$
* @version $Revision$
*/
public class JdbcAclServiceTests extends AbstractDependencyInjectionSpringContextTests {
//~ Instance fields ================================================================================================
private JdbcAclService jdbcAclService;
//~ Methods ========================================================================================================
protected String[] getConfigLocations() {
return new String[] {"classpath:org/acegisecurity/acls/jdbc/applicationContext-test.xml"};
}
public void setJdbcAclService(JdbcAclService jdbcAclService) {
this.jdbcAclService = jdbcAclService;
}
public void testStub() {
ObjectIdentity id1 = new ObjectIdentityImpl("java.lang.Object", new Long(1));
ObjectIdentity id2 = new ObjectIdentityImpl("java.lang.Object", new Long(2));
ObjectIdentity id3 = new ObjectIdentityImpl("java.lang.Object", new Long(3));
ObjectIdentity id4 = new ObjectIdentityImpl("java.lang.Object", new Long(4));
ObjectIdentity id5 = new ObjectIdentityImpl("java.lang.Object", new Long(5));
ObjectIdentity id6 = new ObjectIdentityImpl("java.lang.Object", 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));
}
}
}

View File

@ -1,70 +0,0 @@
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);