Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| df17a2d885 |
@@ -0,0 +1,57 @@
|
||||
#Mon Nov 07 22:01:53 EST 2005
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.5
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.autoboxing=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deprecation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
|
||||
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
|
||||
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
|
||||
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
|
||||
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
|
||||
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
|
||||
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
|
||||
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLocal=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.5
|
||||
@@ -0,0 +1,3 @@
|
||||
#Mon Nov 07 21:58:48 EST 2005
|
||||
eclipse.preferences.version=1
|
||||
internal.default.compliance=default
|
||||
+5
-29
@@ -3,14 +3,13 @@
|
||||
<parent>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<version>2.0.3</version>
|
||||
<version>2.0-M2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-acl</artifactId>
|
||||
<name>Spring Security - ACL module</name>
|
||||
<version>2.0.3</version>
|
||||
<packaging>bundle</packaging>
|
||||
<name>Spring Security - ACL Module</name>
|
||||
<version>2.0-M2</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -37,37 +36,14 @@
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
<artifactId>ehcache</artifactId>
|
||||
<version>1.3.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<version>1.8.0.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring.osgi.export>
|
||||
org.springframework.security.*;version=${pom.version.osgi}
|
||||
</spring.osgi.export>
|
||||
|
||||
<spring.osgi.import>
|
||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||
org.springframework.security.*;version="[${pom.version.osgi},${pom.version.osgi}]",
|
||||
org.springframework.context.*;version="${spring.version.osgi}",
|
||||
org.springframework.dao.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.jdbc.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.transaction.support.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.util.*;version="${spring.version.osgi}",
|
||||
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
|
||||
javax.sql.*
|
||||
</spring.osgi.import>
|
||||
|
||||
<spring.osgi.private.pkg>
|
||||
!org.springframework.security.*
|
||||
</spring.osgi.private.pkg>
|
||||
|
||||
<spring.osgi.symbolic.name>org.springframework.security.acls</spring.osgi.symbolic.name>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -31,7 +31,7 @@ import java.io.Serializable;
|
||||
* @version $Id$
|
||||
*
|
||||
*/
|
||||
public interface AccessControlEntry extends Serializable {
|
||||
public interface AccessControlEntry {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
Acl getAcl();
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.io.Serializable;
|
||||
* Represents an access control list (ACL) for a domain object.
|
||||
*
|
||||
* <p>
|
||||
* An <tt>Acl</tt> represents all ACL entries for a given domain object. In
|
||||
* An <code>Acl</code> represents all ACL entries for a given domain object. In
|
||||
* order to avoid needing references to the domain object itself, this
|
||||
* interface handles indirection between a domain object and an ACL object
|
||||
* identity via the {@link
|
||||
@@ -32,139 +32,124 @@ import java.io.Serializable;
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Implementing classes may elect to return instances that represent
|
||||
* {@link org.springframework.security.acls.Permission} information for either
|
||||
* some OR all {@link org.springframework.security.acls.sid.Sid}
|
||||
* instances. Therefore, an instance may NOT necessarily contain ALL <tt>Sid</tt>s
|
||||
* for a given domain object.
|
||||
* An implementation represents the {@link org.springframework.security.acls.Permission}
|
||||
* list applicable for some or all {@link org.springframework.security.acls.sid.Sid}
|
||||
* instances.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface Acl extends Serializable {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Returns all of the entries represented by the present <tt>Acl</tt>. Entries associated with
|
||||
* the <tt>Acl</tt> parents are not returned.
|
||||
*
|
||||
* <p>This method is typically used for administrative purposes.</p>
|
||||
*
|
||||
* <p>The order that entries appear in the array is important for methods declared in the
|
||||
* {@link MutableAcl} interface. Furthermore, some implementations MAY use ordering as
|
||||
* part of advanced permission checking.</p>
|
||||
*
|
||||
* <p>Do <em>NOT</em> use this method for making authorization decisions. Instead use {@link
|
||||
/**
|
||||
* 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[], boolean)}.</p>
|
||||
*
|
||||
* <p>This method must operate correctly even if the <tt>Acl</tt> only represents a subset of
|
||||
* <tt>Sid</tt>s. The caller is responsible for correctly handling the result if only a subset of
|
||||
* <tt>Sid</tt>s is represented.</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 <tt>Acl</tt>, or <tt>null</tt> if there are
|
||||
* no entries presently associated with this <tt>Acl</tt>.
|
||||
* @return the list of entries represented by the <code>Acl</code>
|
||||
*/
|
||||
AccessControlEntry[] getEntries();
|
||||
|
||||
/**
|
||||
* Obtains the domain object this <tt>Acl</tt> provides entries for. This is immutable once an
|
||||
* <tt>Acl</tt> is created.
|
||||
* 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 (never <tt>null</tt>)
|
||||
* @return the object identity
|
||||
*/
|
||||
ObjectIdentity getObjectIdentity();
|
||||
|
||||
/**
|
||||
* Determines the owner of the <tt>Acl</tt>. The meaning of ownership varies by implementation and is
|
||||
* Determines the owner of the <code>Acl</code>. The meaning of ownership varies by implementation and is
|
||||
* unspecified.
|
||||
*
|
||||
* @return the owner (may be <tt>null</tt> if the implementation does not use ownership concepts)
|
||||
* @return the owner (may be null if the implementation does not use ownership concepts)
|
||||
*/
|
||||
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 <tt>Acl</tt> and this
|
||||
* <tt>Acl</tt>. For actual inheritance to take place, the {@link #isEntriesInheriting()} must also be
|
||||
* <tt>true</tt>.</p>
|
||||
*
|
||||
* <p>This method must operate correctly even if the <tt>Acl</tt> only represents a subset of
|
||||
* <tt>Sid</tt>s. The caller is responsible for correctly handling the result if only a subset of
|
||||
* <tt>Sid</tt>s is represented.</p>
|
||||
* 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 <tt>Acl</tt> (may be <tt>null</tt> if this <tt>Acl</tt> does not have a parent)
|
||||
* @return the parent <code>Acl</code>
|
||||
*/
|
||||
Acl getParentAcl();
|
||||
|
||||
/**
|
||||
* Indicates whether the ACL entries from the {@link #getParentAcl()} should flow down into the current
|
||||
* <tt>Acl</tt>.<p>The mere link between an <tt>Acl</tt> and a parent <tt>Acl</tt> on its own
|
||||
* <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 inheritance of entries.</p>
|
||||
* whether or not the navigation relationship also extends to the actual inheritence of entries.</p>
|
||||
*
|
||||
* @return <tt>true</tt> if parent ACL entries inherit into the current <tt>Acl</tt>
|
||||
* @return <code>true</code> if parent ACL entries inherit into the current <code>Acl</code>
|
||||
*/
|
||||
boolean isEntriesInheriting();
|
||||
|
||||
/**
|
||||
* This is the actual authorization logic method, and must be used whenever ACL authorization decisions are
|
||||
* required.
|
||||
*
|
||||
* <p>An array of <tt>Sid</tt>s are presented, representing security identifies of the current
|
||||
* principal. In addition, an array of <tt>Permission</tt>s is presented which will have one or more bits set
|
||||
* 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 <tt>Permission</tt>s inside the array will be sufficient for an
|
||||
* 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
|
||||
* <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 <tt>Permission</tt>, 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 <tt>Permission</tt>s passed
|
||||
* 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 <tt>true</tt>, the authorization decision may be
|
||||
* 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 <tt>Acl</tt> only represents a subset of <tt>Sid</tt>s,
|
||||
* although the implementation is permitted to throw one of the signature-defined exceptions if the method
|
||||
* is called requesting an authorization decision for a {@link Sid} that was never loaded in this <tt>Acl</tt>.
|
||||
* </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 (at least one entry required)
|
||||
* @param sids the security identities held by the principal (at least one entry required)
|
||||
* @param administrativeMode if <tt>true</tt> denotes the query is for administrative purposes and no logging
|
||||
* @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 <tt>true</tt> if authorization is granted
|
||||
* @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 <tt>Acl</tt> does not have details for one or more of the
|
||||
* <tt>Sid</tt>s passed as arguments
|
||||
* @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
|
||||
*/
|
||||
boolean isGranted(Permission[] permission, Sid[] sids, boolean administrativeMode)
|
||||
throws NotFoundException, UnloadedSidException;
|
||||
|
||||
/**
|
||||
* For efficiency reasons an <tt>Acl</tt> may be loaded and <em>not</em> contain entries for every
|
||||
* <tt>Sid</tt> in the system. If an <tt>Acl</tt> has been loaded and does not represent every
|
||||
* <tt>Sid</tt>, all methods of the <tt>Acl</tt> can only be used within the limited scope of the
|
||||
* <tt>Sid</tt> instances it actually represents.
|
||||
* 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 <tt>Acl</tt> for only particular <tt>Sid</tt>s if read-only authorization
|
||||
* decisions are being made. However, if user interface reporting or modification of <tt>Acl</tt>s are
|
||||
* desired, an <tt>Acl</tt> should be loaded with all <tt>Sid</tt>s. This method denotes whether or
|
||||
* not the specified <tt>Sid</tt>s have been loaded or not.
|
||||
* 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 <tt>Sid</tt>
|
||||
* @param sids one or more security identities the caller is interest in knowing whether this <code>Sid</code>
|
||||
* supports
|
||||
*
|
||||
* @return <tt>true</tt> if every passed <tt>Sid</tt> is represented by this <tt>Acl</tt> instance
|
||||
* @return <code>true</code> if every passed <code>Sid</code> is represented by this <code>Acl</code> instance
|
||||
*/
|
||||
boolean isSidLoaded(Sid[] sids);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,13 @@ import org.springframework.util.Assert;
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class AclFormattingUtils {
|
||||
public final class AclFormattingUtils {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
private AclFormattingUtils() {
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public static String demergePatterns(String original, String removeBits) {
|
||||
Assert.notNull(original, "Original string required");
|
||||
|
||||
@@ -34,67 +34,66 @@ public interface AclService {
|
||||
*
|
||||
* @param parentIdentity to locate children of
|
||||
*
|
||||
* @return the children (or <tt>null</tt> if none were found)
|
||||
* @return the children (or <code>null</code> if none were found)
|
||||
*/
|
||||
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
|
||||
* <tt>Acl</tt> entries based on a {@link Sid} parameter.</p>
|
||||
* <code>Acl</code> entries based on a {@link Sid} parameter.</p>
|
||||
*
|
||||
* @param object to locate an {@link Acl} for
|
||||
* @param object DOCUMENT ME!
|
||||
*
|
||||
* @return the {@link Acl} for the requested {@link ObjectIdentity} (never <tt>null</tt>)
|
||||
* @return DOCUMENT ME!
|
||||
*
|
||||
* @throws NotFoundException if an {@link Acl} was not found for the requested {@link ObjectIdentity}
|
||||
* @throws NotFoundException DOCUMENT ME!
|
||||
*/
|
||||
Acl readAclById(ObjectIdentity object) throws NotFoundException;
|
||||
|
||||
/**
|
||||
* Same as {@link #readAclsById(ObjectIdentity[], Sid[])} except it returns only a single Acl.
|
||||
*
|
||||
* @param object to locate an {@link Acl} for
|
||||
* @param sids the security identities for which {@link Acl} information is required
|
||||
* (may be <tt>null</tt> to denote all entries)
|
||||
* @param object DOCUMENT ME!
|
||||
* @param sids DOCUMENT ME!
|
||||
*
|
||||
* @return the {@link Acl} for the requested {@link ObjectIdentity} (never <tt>null</tt>)
|
||||
* @return DOCUMENT ME!
|
||||
*
|
||||
* @throws NotFoundException if an {@link Acl} was not found for the requested {@link ObjectIdentity}
|
||||
* @throws NotFoundException DOCUMENT ME!
|
||||
*/
|
||||
Acl readAclById(ObjectIdentity object, Sid[] sids)
|
||||
throws NotFoundException;
|
||||
|
||||
/**
|
||||
* Obtains all the <tt>Acl</tt>s that apply for the passed <tt>Object</tt>s.<p>The returned map is
|
||||
* keyed on the passed objects, with the values being the <tt>Acl</tt> instances. Any unknown objects will not
|
||||
* 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 {@link Acl} information for
|
||||
* @param objects the objects to find ACL information for
|
||||
*
|
||||
* @return a map with exactly one element for each {@link ObjectIdentity} passed as an argument (never <tt>null</tt>)
|
||||
* @return a map with zero or more elements (never <code>null</code>)
|
||||
*
|
||||
* @throws NotFoundException if an {@link Acl} was not found for each requested {@link ObjectIdentity}
|
||||
* @throws NotFoundException DOCUMENT ME!
|
||||
*/
|
||||
Map readAclsById(ObjectIdentity[] objects) throws NotFoundException;
|
||||
|
||||
/**
|
||||
* Obtains all the <tt>Acl</tt>s that apply for the passed <tt>Object</tt>s, but only for the
|
||||
* 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 <tt>Acl</tt>
|
||||
* instances. Any unknown objects (or objects for which the interested <tt>Sid</tt>s do not have entries) will
|
||||
* <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 {@link Acl} information for
|
||||
* @param sids the security identities for which {@link Acl} information is required
|
||||
* (may be <tt>null</tt> to denote all entries)
|
||||
* @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 exactly one element for each {@link ObjectIdentity} passed as an argument (never <tt>null</tt>)
|
||||
* @return a map with zero or more elements (never <code>null</code>)
|
||||
*
|
||||
* @throws NotFoundException if an {@link Acl} was not found for each requested {@link ObjectIdentity}
|
||||
* @throws NotFoundException DOCUMENT ME!
|
||||
*/
|
||||
Map readAclsById(ObjectIdentity[] objects, Sid[] sids)
|
||||
throws NotFoundException;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
@@ -26,5 +27,5 @@ package org.springframework.security.acls;
|
||||
public interface AuditableAcl extends MutableAcl {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
void updateAuditing(int aceIndex, boolean auditSuccess, boolean auditFailure);
|
||||
void updateAuditing(Serializable aceId, boolean auditSuccess, boolean auditFailure);
|
||||
}
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
*/
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* A mutable <tt>Acl</tt>.
|
||||
* A mutable <code>Acl</code>.
|
||||
*
|
||||
* <p>
|
||||
* A mutable ACL must ensure that appropriate security checks are performed
|
||||
@@ -33,25 +33,29 @@ import org.springframework.security.acls.sid.Sid;
|
||||
public interface MutableAcl extends Acl {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
void deleteAce(int aceIndex) throws NotFoundException;
|
||||
void deleteAce(Serializable aceId) throws NotFoundException;
|
||||
|
||||
/**
|
||||
* Obtains an identifier that represents this <tt>MutableAcl</tt>.
|
||||
* 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 the identifier, or <tt>null</tt> if unsaved
|
||||
* @return DOCUMENT ME!
|
||||
*/
|
||||
AccessControlEntry[] getEntries();
|
||||
|
||||
/**
|
||||
* Obtains an identifier that represents this <code>MutableAcl</code>.
|
||||
*
|
||||
* @return the identifier, or <code>null</code> if unsaved
|
||||
*/
|
||||
Serializable getId();
|
||||
|
||||
void insertAce(int atIndexLocation, Permission permission, Sid sid, boolean granting)
|
||||
void insertAce(Serializable afterAceId, Permission permission, Sid sid, boolean granting)
|
||||
throws NotFoundException;
|
||||
|
||||
/**
|
||||
* Changes the present owner to a different owner.
|
||||
*
|
||||
* @param newOwner the new owner (mandatory; cannot be null)
|
||||
*/
|
||||
void setOwner(Sid newOwner);
|
||||
|
||||
/**
|
||||
* Change the value returned by {@link Acl#isEntriesInheriting()}.
|
||||
*
|
||||
@@ -66,6 +70,6 @@ public interface MutableAcl extends Acl {
|
||||
*/
|
||||
void setParent(Acl newParent);
|
||||
|
||||
void updateAce(int aceIndex, Permission permission)
|
||||
void updateAce(Serializable aceId, Permission permission)
|
||||
throws NotFoundException;
|
||||
}
|
||||
|
||||
@@ -14,15 +14,13 @@
|
||||
*/
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Represents a permission granted to a {@link org.springframework.security.acls.sid.Sid Sid} for a given domain object.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface Permission extends Serializable {
|
||||
public interface Permission {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
char RESERVED_ON = '~';
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.AclFormattingUtils;
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
/**
|
||||
* Provides an abstract superclass for {@link Permission} implementations.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @since 2.0.3
|
||||
* @see AbstractRegisteredPermission
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractPermission implements Permission {
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
protected char code;
|
||||
protected int mask;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
protected AbstractPermission(int mask, char code) {
|
||||
this.mask = mask;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public final boolean equals(Object arg0) {
|
||||
if (arg0 == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(arg0 instanceof Permission)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Permission rhs = (Permission) arg0;
|
||||
|
||||
return (this.mask == rhs.getMask());
|
||||
}
|
||||
|
||||
public final int getMask() {
|
||||
return mask;
|
||||
}
|
||||
|
||||
public String getPattern() {
|
||||
return AclFormattingUtils.printBinary(mask, code);
|
||||
}
|
||||
|
||||
public final String toString() {
|
||||
return this.getClass().getSimpleName() + "[" + getPattern() + "=" + mask + "]";
|
||||
}
|
||||
|
||||
public final int hashCode() {
|
||||
return this.mask;
|
||||
}
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
/**
|
||||
* Provides an abstract base for standard {@link Permission} instances that wish to offer static convenience
|
||||
* methods to callers via delegation to {@link DefaultPermissionFactory}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @since 2.0.3
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractRegisteredPermission extends AbstractPermission {
|
||||
protected static DefaultPermissionFactory defaultPermissionFactory = new DefaultPermissionFactory();
|
||||
|
||||
protected AbstractRegisteredPermission(int mask, char code) {
|
||||
super(mask, code);
|
||||
}
|
||||
|
||||
protected final static void registerPermissionsFor(Class subClass) {
|
||||
defaultPermissionFactory.registerPublicPermissions(subClass);
|
||||
}
|
||||
|
||||
public final static Permission buildFromMask(int mask) {
|
||||
return defaultPermissionFactory.buildFromMask(mask);
|
||||
}
|
||||
|
||||
public final static Permission[] buildFromMask(int[] masks) {
|
||||
return defaultPermissionFactory.buildFromMask(masks);
|
||||
}
|
||||
|
||||
public final static Permission buildFromName(String name) {
|
||||
return defaultPermissionFactory.buildFromName(name);
|
||||
}
|
||||
|
||||
public final static Permission[] buildFromName(String[] names) {
|
||||
return defaultPermissionFactory.buildFromName(names);
|
||||
}
|
||||
}
|
||||
+1
-43
@@ -67,50 +67,8 @@ public class AccessControlEntryImpl implements AccessControlEntry, AuditableAcce
|
||||
|
||||
AccessControlEntryImpl rhs = (AccessControlEntryImpl) arg0;
|
||||
|
||||
if (this.acl == null) {
|
||||
if (rhs.getAcl() != null) {
|
||||
return false;
|
||||
}
|
||||
// Both this.acl and rhs.acl are null and thus equal
|
||||
} else {
|
||||
// this.acl is non-null
|
||||
if (rhs.getAcl() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Both this.acl and rhs.acl are non-null, so do a comparison
|
||||
if (this.acl.getObjectIdentity() == null) {
|
||||
if (rhs.acl.getObjectIdentity() != null) {
|
||||
return false;
|
||||
}
|
||||
// Both this.acl and rhs.acl are null and thus equal
|
||||
} else {
|
||||
// Both this.acl.objectIdentity and rhs.acl.objectIdentity are non-null
|
||||
if (!this.acl.getObjectIdentity().equals(rhs.getAcl().getObjectIdentity())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.id == null) {
|
||||
if (rhs.id != null) {
|
||||
return false;
|
||||
}
|
||||
// Both this.id and rhs.id are null and thus equal
|
||||
} else {
|
||||
// this.id is non-null
|
||||
if (rhs.id == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Both this.id and rhs.id are non-null
|
||||
if (!this.id.equals(rhs.id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((this.auditFailure != rhs.isAuditFailure()) || (this.auditSuccess != rhs.isAuditSuccess())
|
||||
|| (this.granting != rhs.isGranting())
|
||||
|| (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;
|
||||
}
|
||||
|
||||
@@ -14,11 +14,6 @@
|
||||
*/
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AuditableAcl;
|
||||
@@ -29,8 +24,15 @@ import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.UnloadedSidException;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
|
||||
/**
|
||||
* Base implementation of <code>Acl</code>.
|
||||
@@ -40,10 +42,10 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
|
||||
private Acl parentAcl;
|
||||
private transient AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
private transient AuditLogger auditLogger;
|
||||
private AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
private AuditLogger auditLogger;
|
||||
private List aces = new Vector();
|
||||
private ObjectIdentity objectIdentity;
|
||||
private Serializable id;
|
||||
@@ -114,22 +116,34 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
private void verifyAceIndexExists(int aceIndex) {
|
||||
if (aceIndex < 0) {
|
||||
throw new NotFoundException("aceIndex must be greater than or equal to zero");
|
||||
}
|
||||
if (aceIndex > this.aces.size()) {
|
||||
throw new NotFoundException("aceIndex must correctly refer to an index of the AccessControlEntry collection");
|
||||
public void deleteAce(Serializable aceId) throws NotFoundException {
|
||||
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
|
||||
synchronized (aces) {
|
||||
int offset = findAceOffset(aceId);
|
||||
|
||||
if (offset == -1) {
|
||||
throw new NotFoundException("Requested ACE ID not found");
|
||||
}
|
||||
|
||||
this.aces.remove(offset);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteAce(int aceIndex) throws NotFoundException {
|
||||
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
verifyAceIndexExists(aceIndex);
|
||||
|
||||
|
||||
private int findAceOffset(Serializable aceId) {
|
||||
Assert.notNull(aceId, "ACE ID is required");
|
||||
|
||||
synchronized (aces) {
|
||||
this.aces.remove(aceIndex);
|
||||
for (int i = 0; i < aces.size(); i++) {
|
||||
AccessControlEntry ace = (AccessControlEntry) aces.get(i);
|
||||
|
||||
if (ace.getId().equals(aceId)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public AccessControlEntry[] getEntries() {
|
||||
@@ -153,22 +167,26 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
return parentAcl;
|
||||
}
|
||||
|
||||
public void insertAce(int atIndexLocation, Permission permission, Sid sid, boolean granting)
|
||||
public void insertAce(Serializable afterAceId, Permission permission, Sid sid, boolean granting)
|
||||
throws NotFoundException {
|
||||
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.notNull(permission, "Permission required");
|
||||
Assert.notNull(sid, "Sid required");
|
||||
if (atIndexLocation < 0) {
|
||||
throw new NotFoundException("atIndexLocation must be greater than or equal to zero");
|
||||
}
|
||||
if (atIndexLocation > this.aces.size()) {
|
||||
throw new NotFoundException("atIndexLocation must be less than or equal to the size of the AccessControlEntry collection");
|
||||
}
|
||||
|
||||
AccessControlEntryImpl ace = new AccessControlEntryImpl(null, this, sid, permission, granting, false, false);
|
||||
|
||||
synchronized (aces) {
|
||||
this.aces.add(atIndexLocation, ace);
|
||||
if (afterAceId != null) {
|
||||
int offset = findAceOffset(afterAceId);
|
||||
|
||||
if (offset == -1) {
|
||||
throw new NotFoundException("Requested ACE ID not found");
|
||||
}
|
||||
|
||||
this.aces.add(offset + 1, ace);
|
||||
} else {
|
||||
this.aces.add(ace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,7 +337,8 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
|
||||
public void setParent(Acl newParent) {
|
||||
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.isTrue(newParent == null || !newParent.equals(this), "Cannot be the parent of yourself");
|
||||
Assert.notNull(newParent, "New Parent required");
|
||||
Assert.isTrue(!newParent.equals(this), "Cannot be the parent of yourself");
|
||||
this.parentAcl = newParent;
|
||||
}
|
||||
|
||||
@@ -349,63 +368,40 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
|
||||
sb.append("inheriting: ").append(this.entriesInheriting).append("; ");
|
||||
sb.append("parent: ").append((this.parentAcl == null) ? "Null" : this.parentAcl.getObjectIdentity().toString());
|
||||
sb.append("aclAuthorizationStrategy: ").append(this.aclAuthorizationStrategy).append("; ");
|
||||
sb.append("auditLogger: ").append(this.auditLogger);
|
||||
sb.append("]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void updateAce(int aceIndex, Permission permission)
|
||||
public void updateAce(Serializable aceId, Permission permission)
|
||||
throws NotFoundException {
|
||||
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
verifyAceIndexExists(aceIndex);
|
||||
|
||||
|
||||
synchronized (aces) {
|
||||
AccessControlEntryImpl ace = (AccessControlEntryImpl) aces.get(aceIndex);
|
||||
int offset = findAceOffset(aceId);
|
||||
|
||||
if (offset == -1) {
|
||||
throw new NotFoundException("Requested ACE ID not found");
|
||||
}
|
||||
|
||||
AccessControlEntryImpl ace = (AccessControlEntryImpl) aces.get(offset);
|
||||
ace.setPermission(permission);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateAuditing(int aceIndex, boolean auditSuccess, boolean auditFailure) {
|
||||
public void updateAuditing(Serializable aceId, boolean auditSuccess, boolean auditFailure) {
|
||||
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
verifyAceIndexExists(aceIndex);
|
||||
|
||||
|
||||
synchronized (aces) {
|
||||
AccessControlEntryImpl ace = (AccessControlEntryImpl) aces.get(aceIndex);
|
||||
int offset = findAceOffset(aceId);
|
||||
|
||||
if (offset == -1) {
|
||||
throw new NotFoundException("Requested ACE ID not found");
|
||||
}
|
||||
|
||||
AccessControlEntryImpl ace = (AccessControlEntryImpl) aces.get(offset);
|
||||
ace.setAuditSuccess(auditSuccess);
|
||||
ace.setAuditFailure(auditFailure);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof AclImpl) {
|
||||
AclImpl rhs = (AclImpl) obj;
|
||||
if (this.aces.equals(rhs.aces)) {
|
||||
if ((this.parentAcl == null && rhs.parentAcl == null) || (this.parentAcl.equals(rhs.parentAcl))) {
|
||||
if ((this.objectIdentity == null && rhs.objectIdentity == null) || (this.objectIdentity.equals(rhs.objectIdentity))) {
|
||||
if ((this.id == null && rhs.id == null) || (this.id.equals(rhs.id))) {
|
||||
if ((this.owner == null && rhs.owner == null) || this.owner.equals(rhs.owner)) {
|
||||
if (this.entriesInheriting == rhs.entriesInheriting) {
|
||||
if ((this.loadedSids == null && rhs.loadedSids == null)) {
|
||||
return true;
|
||||
}
|
||||
if (this.loadedSids.length == rhs.loadedSids.length) {
|
||||
for (int i = 0; i < this.loadedSids.length; i++) {
|
||||
if (!this.loadedSids[i].equals(rhs.loadedSids[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,36 +14,157 @@
|
||||
*/
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.AclFormattingUtils;
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* A set of standard permissions.
|
||||
*
|
||||
* <p>
|
||||
* You may subclass this class to add additional permissions, or use this class as a guide
|
||||
* for creating your own permission classes.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class BasePermission extends AbstractRegisteredPermission {
|
||||
public final 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
|
||||
|
||||
/**
|
||||
* Registers the public static permissions defined on this class. This is mandatory so
|
||||
* that the static methods will operate correctly.
|
||||
*/
|
||||
private static Map locallyDeclaredPermissionsByInteger = new HashMap();
|
||||
private static Map locallyDeclaredPermissionsByName = new HashMap();
|
||||
|
||||
static {
|
||||
registerPermissionsFor(BasePermission.class);
|
||||
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) {}
|
||||
}
|
||||
}
|
||||
|
||||
protected BasePermission(int mask, char code) {
|
||||
super(mask, code);
|
||||
//~ 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[0];
|
||||
}
|
||||
|
||||
Permission[] permissions = new Permission[masks.length];
|
||||
|
||||
for (int i = 0; i < masks.length; i++) {
|
||||
permissions[i] = buildFromMask(masks[i]);
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
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[0];
|
||||
}
|
||||
|
||||
Permission[] permissions = new Permission[names.length];
|
||||
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
permissions[i] = buildFromName(names[i]);
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
public boolean equals(Object arg0) {
|
||||
if (arg0 == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(arg0 instanceof Permission)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Permission rhs = (Permission) 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 + "]";
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.mask;
|
||||
}
|
||||
}
|
||||
|
||||
+38
-12
@@ -19,21 +19,20 @@ import org.springframework.security.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>
|
||||
* 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 extends AbstractPermission {
|
||||
public class CumulativePermission implements Permission {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private String pattern = THIRTY_TWO_RESERVED_OFF;
|
||||
private int mask = 0;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public CumulativePermission() {
|
||||
super(0, ' ');
|
||||
}
|
||||
|
||||
public CumulativePermission clear(Permission permission) {
|
||||
this.mask &= ~permission.getMask();
|
||||
this.pattern = AclFormattingUtils.demergePatterns(this.pattern, permission.getPattern());
|
||||
@@ -47,16 +46,43 @@ public class CumulativePermission extends AbstractPermission {
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public boolean equals(Object arg0) {
|
||||
if (arg0 == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(arg0 instanceof Permission)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Permission rhs = (Permission) arg0;
|
||||
|
||||
return (this.mask == rhs.getMask());
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.mask;
|
||||
}
|
||||
|
||||
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 getPattern() {
|
||||
return this.pattern;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "CumulativePermission[" + pattern + "=" + this.mask + "]";
|
||||
}
|
||||
}
|
||||
|
||||
-127
@@ -1,127 +0,0 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.jdbc.LookupStrategy;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link PermissionFactory}.
|
||||
*
|
||||
* <p>
|
||||
* Generally this class will be used by a {@link Permission} instance, as opposed to being dependency
|
||||
* injected into a {@link LookupStrategy} or similar. Nevertheless, the latter mode of operation is
|
||||
* fully supported (in which case your {@link Permission} implementations probably should extend
|
||||
* {@link AbstractPermission} instead of {@link AbstractRegisteredPermission}).
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @since 2.0.3
|
||||
*
|
||||
*/
|
||||
public class DefaultPermissionFactory implements PermissionFactory {
|
||||
private Map registeredPermissionsByInteger = new HashMap();
|
||||
private Map registeredPermissionsByName = new HashMap();
|
||||
|
||||
/**
|
||||
* Permit registration of a {@link DefaultPermissionFactory} class. The class must provide
|
||||
* public static fields of type {@link Permission} to represent the possible permissions.
|
||||
*
|
||||
* @param clazz a {@link Permission} class with public static fields to register
|
||||
*/
|
||||
public void registerPublicPermissions(Class clazz) {
|
||||
Assert.notNull(clazz, "Class required");
|
||||
Assert.isAssignable(Permission.class, clazz);
|
||||
|
||||
Field[] fields = clazz.getFields();
|
||||
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
try {
|
||||
Object fieldValue = fields[i].get(null);
|
||||
|
||||
if (Permission.class.isAssignableFrom(fieldValue.getClass())) {
|
||||
// Found a Permission static field
|
||||
Permission perm = (Permission) fieldValue;
|
||||
String permissionName = fields[i].getName();
|
||||
|
||||
registerPermission(perm, permissionName);
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
public void registerPermission(Permission perm, String permissionName) {
|
||||
Assert.notNull(perm, "Permission required");
|
||||
Assert.hasText(permissionName, "Permission name required");
|
||||
|
||||
Integer mask = new Integer(perm.getMask());
|
||||
|
||||
// Ensure no existing Permission uses this integer or code
|
||||
Assert.isTrue(!registeredPermissionsByInteger.containsKey(mask), "An existing Permission already provides mask " + mask);
|
||||
Assert.isTrue(!registeredPermissionsByName.containsKey(permissionName), "An existing Permission already provides name '" + permissionName + "'");
|
||||
|
||||
// Register the new Permission
|
||||
registeredPermissionsByInteger.put(mask, perm);
|
||||
registeredPermissionsByName.put(permissionName, perm);
|
||||
}
|
||||
|
||||
public Permission buildFromMask(int mask) {
|
||||
if (registeredPermissionsByInteger.containsKey(new Integer(mask))) {
|
||||
// The requested mask has an exactly match against a statically-defined Permission, so return it
|
||||
return (Permission) registeredPermissionsByInteger.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) registeredPermissionsByInteger.get(new Integer(permissionToCheck));
|
||||
Assert.state(p != null, "Mask " + permissionToCheck + " does not have a corresponding static Permission");
|
||||
permission.set(p);
|
||||
}
|
||||
}
|
||||
|
||||
return permission;
|
||||
}
|
||||
|
||||
public Permission[] buildFromMask(int[] masks) {
|
||||
if ((masks == null) || (masks.length == 0)) {
|
||||
return new Permission[0];
|
||||
}
|
||||
|
||||
Permission[] permissions = new Permission[masks.length];
|
||||
|
||||
for (int i = 0; i < masks.length; i++) {
|
||||
permissions[i] = buildFromMask(masks[i]);
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
public Permission buildFromName(String name) {
|
||||
Assert.isTrue(registeredPermissionsByName.containsKey(name), "Unknown permission '" + name + "'");
|
||||
|
||||
return (Permission) registeredPermissionsByName.get(name);
|
||||
}
|
||||
|
||||
public Permission[] buildFromName(String[] names) {
|
||||
if ((names == null) || (names.length == 0)) {
|
||||
return new Permission[0];
|
||||
}
|
||||
|
||||
Permission[] permissions = new Permission[names.length];
|
||||
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
permissions[i] = buildFromName(names[i]);
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
/**
|
||||
* Provides a simple mechanism to retrieve {@link Permission} instances from integer masks.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @since 2.0.3
|
||||
*
|
||||
*/
|
||||
public interface PermissionFactory {
|
||||
|
||||
/**
|
||||
* 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 abstract Permission buildFromMask(int mask);
|
||||
|
||||
}
|
||||
+117
-140
@@ -14,23 +14,6 @@
|
||||
*/
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.PreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
@@ -47,9 +30,31 @@ import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.sid.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.PreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
|
||||
/**
|
||||
@@ -74,7 +79,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructor accepting mandatory arguments
|
||||
*
|
||||
* @param dataSource to access the database
|
||||
@@ -98,30 +103,19 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
private static String computeRepeatingSql(String repeatingSql, int requiredRepetitions) {
|
||||
Assert.isTrue(requiredRepetitions >= 1, "Must be => 1");
|
||||
|
||||
String startSql = "select acl_object_identity.object_id_identity, "
|
||||
+ "acl_entry.ace_order, "
|
||||
+ "acl_object_identity.id as acl_id, "
|
||||
+ "acl_object_identity.parent_object, "
|
||||
+ "acl_object_identity.entries_inheriting, "
|
||||
+ "acl_entry.id as ace_id, "
|
||||
+ "acl_entry.mask, "
|
||||
+ "acl_entry.granting, "
|
||||
+ "acl_entry.audit_success, "
|
||||
+ "acl_entry.audit_failure, "
|
||||
+ "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 "
|
||||
+ "left join acl_sid acli_sid on acli_sid.id = acl_object_identity.owner_sid "
|
||||
+ "left join acl_class on acl_class.id = acl_object_identity.object_id_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 ( ";
|
||||
String startSql = "select ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY, ACL_ENTRY.ACE_ORDER, "
|
||||
+ "ACL_OBJECT_IDENTITY.ID as ACL_ID, " + "ACL_OBJECT_IDENTITY.PARENT_OBJECT, "
|
||||
+ "ACL_OBJECT_IDENTITY,ENTRIES_INHERITING, "
|
||||
+ "ACL_ENTRY.ID as ACE_ID, ACL_ENTRY.MASK, ACL_ENTRY.GRANTING, "
|
||||
+ "ACL_ENTRY.AUDIT_SUCCESS, ACL_ENTRY.AUDIT_FAILURE, "
|
||||
+ "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_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 ( ";
|
||||
|
||||
String endSql = ") order by acl_object_identity.object_id_identity"
|
||||
+ " asc, acl_entry.ace_order asc";
|
||||
String endSql = ") order by ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY asc, ACL_ENTRY.ACE_ORDER asc";
|
||||
|
||||
StringBuffer sqlStringBuffer = new StringBuffer();
|
||||
sqlStringBuffer.append(startSql);
|
||||
@@ -197,30 +191,30 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
*/
|
||||
private void convertCurrentResultIntoObject(Map acls, ResultSet rs)
|
||||
throws SQLException {
|
||||
Long id = new Long(rs.getLong("acl_id"));
|
||||
Long id = new Long(rs.getLong("ACL_ID"));
|
||||
|
||||
// If we already have an ACL for this ID, just create the ACE
|
||||
AclImpl acl = (AclImpl) acls.get(id);
|
||||
|
||||
if (acl == null) {
|
||||
// Make an AclImpl and pop it into the Map
|
||||
ObjectIdentity objectIdentity = new ObjectIdentityImpl(rs.getString("class"),
|
||||
new Long(rs.getLong("object_id_identity")));
|
||||
ObjectIdentity objectIdentity = new ObjectIdentityImpl(rs.getString("CLASS"),
|
||||
new Long(rs.getLong("OBJECT_ID_IDENTITY")));
|
||||
|
||||
Acl parentAcl = null;
|
||||
long parentAclId = rs.getLong("parent_object");
|
||||
long parentAclId = rs.getLong("PARENT_OBJECT");
|
||||
|
||||
if (parentAclId != 0) {
|
||||
parentAcl = new StubAclParent(new Long(parentAclId));
|
||||
}
|
||||
|
||||
boolean entriesInheriting = rs.getBoolean("entries_inheriting");
|
||||
boolean entriesInheriting = rs.getBoolean("ENTRIES_INHERITING");
|
||||
Sid owner;
|
||||
|
||||
if (rs.getBoolean("acl_principal")) {
|
||||
owner = new PrincipalSid(rs.getString("acl_sid"));
|
||||
if (rs.getBoolean("ACL_PRINCIPAL")) {
|
||||
owner = new PrincipalSid(rs.getString("ACL_SID"));
|
||||
} else {
|
||||
owner = new GrantedAuthoritySid(rs.getString("acl_sid"));
|
||||
owner = new GrantedAuthoritySid(rs.getString("ACL_SID"));
|
||||
}
|
||||
|
||||
acl = new AclImpl(objectIdentity, id, aclAuthorizationStrategy, auditLogger, parentAcl, null,
|
||||
@@ -230,21 +224,20 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
|
||||
// Add an extra ACE to the ACL (ORDER BY maintains the ACE list order)
|
||||
// It is permissable to have no ACEs in an ACL (which is detected by a null ACE_SID)
|
||||
if (rs.getString("ace_sid") != null) {
|
||||
Long aceId = new Long(rs.getLong("ace_id"));
|
||||
if (rs.getString("ACE_SID") != null) {
|
||||
Long aceId = new Long(rs.getLong("ACE_ID"));
|
||||
Sid recipient;
|
||||
|
||||
if (rs.getBoolean("ace_principal")) {
|
||||
recipient = new PrincipalSid(rs.getString("ace_sid"));
|
||||
if (rs.getBoolean("ACE_PRINCIPAL")) {
|
||||
recipient = new PrincipalSid(rs.getString("ACE_SID"));
|
||||
} else {
|
||||
recipient = new GrantedAuthoritySid(rs.getString("ace_sid"));
|
||||
recipient = new GrantedAuthoritySid(rs.getString("ACE_SID"));
|
||||
}
|
||||
|
||||
int mask = rs.getInt("mask");
|
||||
Permission permission = convertMaskIntoPermission(mask);
|
||||
boolean granting = rs.getBoolean("granting");
|
||||
boolean auditSuccess = rs.getBoolean("audit_success");
|
||||
boolean auditFailure = rs.getBoolean("audit_failure");
|
||||
Permission permission = BasePermission.buildFromMask(rs.getInt("MASK"));
|
||||
boolean granting = rs.getBoolean("GRANTING");
|
||||
boolean auditSuccess = rs.getBoolean("AUDIT_SUCCESS");
|
||||
boolean auditFailure = rs.getBoolean("AUDIT_FAILURE");
|
||||
|
||||
AccessControlEntryImpl ace = new AccessControlEntryImpl(aceId, acl, recipient, permission, granting,
|
||||
auditSuccess, auditFailure);
|
||||
@@ -266,10 +259,6 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
protected Permission convertMaskIntoPermission(int mask) {
|
||||
return BasePermission.buildFromMask(mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a batch of <code>ObjectIdentity</code>s directly from the database.<p>The caller is responsible
|
||||
* for optimization issues, such as selecting the identities to lookup, ensuring the cache doesn't contain them
|
||||
@@ -289,20 +278,20 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
|
||||
// Make the "acls" map contain all requested objectIdentities
|
||||
// (including markers to each parent in the hierarchy)
|
||||
String sql = computeRepeatingSql("(acl_object_identity.object_id_identity = ? and acl_class.class = ?)",
|
||||
String sql = computeRepeatingSql("(ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY = ? and ACL_CLASS.CLASS = ?)",
|
||||
objectIdentities.length);
|
||||
|
||||
Set parentsToLookup = (Set) jdbcTemplate.query(sql,
|
||||
jdbcTemplate.query(sql,
|
||||
new PreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps)
|
||||
throws SQLException {
|
||||
for (int i = 0; i < objectIdentities.length; i++) {
|
||||
// Determine prepared statement values for this iteration
|
||||
String javaType = objectIdentities[i].getJavaType().getName();
|
||||
Assert.isInstanceOf(Long.class, objectIdentities[i].getIdentifier(),
|
||||
"This class requires ObjectIdentity.getIdentifier() to be a Long");
|
||||
|
||||
// No need to check for nulls, as guaranteed non-null by ObjectIdentity.getIdentifier() interface contract
|
||||
String identifier = objectIdentities[i].getIdentifier().toString();
|
||||
long id = (Long.valueOf(identifier)).longValue();
|
||||
long id = ((Long) objectIdentities[i].getIdentifier()).longValue();
|
||||
|
||||
// Inject values
|
||||
ps.setLong((2 * i) + 1, id);
|
||||
@@ -310,11 +299,6 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
}
|
||||
}
|
||||
}, new ProcessResultSet(acls, sids));
|
||||
|
||||
// Lookup the parents, now that our JdbcTemplate has released the database connection (SEC-547)
|
||||
if (parentsToLookup.size() > 0) {
|
||||
lookupPrimaryKeys(acls, parentsToLookup, sids);
|
||||
}
|
||||
|
||||
// Finally, convert our "acls" containing StubAclParents into true Acls
|
||||
Map resultMap = new HashMap();
|
||||
@@ -344,9 +328,9 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
Assert.notNull(acls, "ACLs are required");
|
||||
Assert.notEmpty(findNow, "Items to find now required");
|
||||
|
||||
String sql = computeRepeatingSql("(acl_object_identity.id = ?)", findNow.size());
|
||||
String sql = computeRepeatingSql("(ACL_OBJECT_IDENTITY.ID = ?)", findNow.size());
|
||||
|
||||
Set parentsToLookup = (Set) jdbcTemplate.query(sql,
|
||||
jdbcTemplate.query(sql,
|
||||
new PreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps)
|
||||
throws SQLException {
|
||||
@@ -359,29 +343,25 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
}
|
||||
}
|
||||
}, new ProcessResultSet(acls, sids));
|
||||
|
||||
// Lookup the parents, now that our JdbcTemplate has released the database connection (SEC-547)
|
||||
if (parentsToLookup.size() > 0) {
|
||||
lookupPrimaryKeys(acls, parentsToLookup, sids);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main method.<p>WARNING: This implementation completely disregards the "sids" argument! Every item
|
||||
* The main method.<p>WARNING: This implementation completely disregards the "sids" parameter! Every item
|
||||
* in the cache is expected to contain all SIDs. If you have serious performance needs (eg a very large number of
|
||||
* SIDs per object identity), you'll probably want to develop a custom {@link LookupStrategy} implementation
|
||||
* instead.</p>
|
||||
* <p>The implementation works in batch sizes specfied by {@link #batchSize}.</p>
|
||||
*
|
||||
* @param objects the identities to lookup (required)
|
||||
* @param sids the SIDs for which identities are required (ignored by this implementation)
|
||||
* @param objects DOCUMENT ME!
|
||||
* @param sids DOCUMENT ME!
|
||||
*
|
||||
* @return a <tt>Map</tt> where keys represent the {@link ObjectIdentity} of the located {@link Acl} and values
|
||||
* are the located {@link Acl} (never <tt>null</tt> although some entries may be missing; this method
|
||||
* should not throw {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used
|
||||
* to automatically create entries if required)
|
||||
* @return DOCUMENT ME!
|
||||
*
|
||||
* @throws NotFoundException DOCUMENT ME!
|
||||
* @throws IllegalStateException DOCUMENT ME!
|
||||
*/
|
||||
public Map readAclsById(ObjectIdentity[] objects, Sid[] sids) {
|
||||
public Map readAclsById(ObjectIdentity[] objects, Sid[] sids)
|
||||
throws NotFoundException {
|
||||
Assert.isTrue(batchSize >= 1, "BatchSize must be >= 1");
|
||||
Assert.notEmpty(objects, "Objects to lookup required");
|
||||
|
||||
@@ -391,53 +371,56 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
Set currentBatchToLoad = new HashSet(); // contains ObjectIdentitys
|
||||
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
boolean aclFound = false;
|
||||
|
||||
// Check we don't already have this ACL in the results
|
||||
// Check we don't already have this ACL in the results
|
||||
if (result.containsKey(objects[i])) {
|
||||
aclFound = true;
|
||||
continue; // already in results, so move to next element
|
||||
}
|
||||
|
||||
// Check cache for the present ACL entry
|
||||
if (!aclFound) {
|
||||
Acl acl = aclCache.getFromCache(objects[i]);
|
||||
|
||||
// Ensure any cached element supports all the requested SIDs
|
||||
// (they should always, as our base impl doesn't filter on SID)
|
||||
if (acl != null) {
|
||||
if (acl.isSidLoaded(sids)) {
|
||||
result.put(acl.getObjectIdentity(), acl);
|
||||
aclFound = true;
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
"Error: SID-filtered element detected when implementation does not perform SID filtering "
|
||||
+ "- have you added something to the cache manually?");
|
||||
}
|
||||
Acl acl = aclCache.getFromCache(objects[i]);
|
||||
|
||||
// Ensure any cached element supports all the requested SIDs
|
||||
// (they should always, as our base impl doesn't filter on SID)
|
||||
if (acl != null) {
|
||||
if (acl.isSidLoaded(sids)) {
|
||||
result.put(acl.getObjectIdentity(), acl);
|
||||
|
||||
continue; // now in results, so move to next element
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
"Error: SID-filtered element detected when implementation does not perform SID filtering "
|
||||
+ "- have you added something to the cache manually?");
|
||||
}
|
||||
}
|
||||
|
||||
// Load the ACL from the database
|
||||
if (!aclFound) {
|
||||
currentBatchToLoad.add(objects[i]);
|
||||
}
|
||||
|
||||
// To get this far, we have no choice but to retrieve it via JDBC
|
||||
// (although we don't do it until we get a batch of them to load)
|
||||
currentBatchToLoad.add(objects[i]);
|
||||
|
||||
// Is it time to load from JDBC the currentBatchToLoad?
|
||||
if ((currentBatchToLoad.size() == this.batchSize) || ((i + 1) == objects.length)) {
|
||||
if (currentBatchToLoad.size() > 0) {
|
||||
Map loadedBatch = lookupObjectIdentities((ObjectIdentity[]) currentBatchToLoad.toArray(new ObjectIdentity[] {}), sids);
|
||||
Map loadedBatch = lookupObjectIdentities((ObjectIdentity[]) currentBatchToLoad.toArray(
|
||||
new ObjectIdentity[] {}), sids);
|
||||
|
||||
// Add loaded batch (all elements 100% initialized) to results
|
||||
result.putAll(loadedBatch);
|
||||
|
||||
// Add the loaded batch to the cache
|
||||
Iterator loadedAclIterator = loadedBatch.values().iterator();
|
||||
|
||||
while (loadedAclIterator.hasNext()) {
|
||||
aclCache.putInCache((AclImpl) loadedAclIterator.next());
|
||||
}
|
||||
|
||||
currentBatchToLoad.clear();
|
||||
}
|
||||
// Add loaded batch (all elements 100% initialized) to results
|
||||
result.putAll(loadedBatch);
|
||||
|
||||
// Add the loaded batch to the cache
|
||||
Iterator loadedAclIterator = loadedBatch.values().iterator();
|
||||
|
||||
while (loadedAclIterator.hasNext()) {
|
||||
aclCache.putInCache((AclImpl) loadedAclIterator.next());
|
||||
}
|
||||
|
||||
currentBatchToLoad.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Now we're done, check every requested object identity was found (throw NotFoundException if needed)
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
if (!result.containsKey(objects[i])) {
|
||||
throw new NotFoundException("Unable to find ACL information for object identity '"
|
||||
+ objects[i].toString() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,17 +443,6 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
this.sids = sids; // can be null
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of {@link ResultSetExtractor#extractData(ResultSet)}.
|
||||
* Creates an {@link Acl} for each row in the {@link ResultSet} and
|
||||
* ensures it is in member field <tt>acls</tt>. Any {@link Acl} with
|
||||
* a parent will have the parents id returned in a set. The returned
|
||||
* set of ids may requires further processing.
|
||||
* @param rs The {@link ResultSet} to be processed
|
||||
* @return a list of parent IDs remaining to be looked up (may be empty, but never <tt>null</tt>)
|
||||
* @throws SQLException
|
||||
* @throws DataAccessException
|
||||
*/
|
||||
public Object extractData(ResultSet rs) throws SQLException, DataAccessException {
|
||||
Set parentIdsToLookup = new HashSet(); // Set of parent_id Longs
|
||||
|
||||
@@ -479,7 +451,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
convertCurrentResultIntoObject(acls, rs);
|
||||
|
||||
// Figure out if this row means we need to lookup another parent
|
||||
long parentId = rs.getLong("parent_object");
|
||||
long parentId = rs.getLong("PARENT_OBJECT");
|
||||
|
||||
if (parentId != 0) {
|
||||
// See if it's already in the "acls"
|
||||
@@ -500,8 +472,13 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
// Return the parents left to lookup to the calller
|
||||
return parentIdsToLookup;
|
||||
// Lookup parents, adding Acls (with StubAclParents) to "acl" map
|
||||
if (parentIdsToLookup.size() > 0) {
|
||||
lookupPrimaryKeys(acls, parentIdsToLookup, sids);
|
||||
}
|
||||
|
||||
// Return null to meet ResultSetExtractor method contract
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,28 +14,20 @@
|
||||
*/
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import net.sf.ehcache.CacheException;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.Element;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
|
||||
import org.springframework.security.acls.domain.AclImpl;
|
||||
import org.springframework.security.acls.domain.AuditLogger;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* Simple implementation of {@link AclCache} that delegates to EH-CACHE.
|
||||
*
|
||||
* <p>
|
||||
* Designed to handle the transient fields in {@link AclImpl}. Note that this implementation assumes all
|
||||
* {@link AclImpl} instances share the same {@link AuditLogger} and {@link AclAuthorizationStrategy} instance.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
@@ -44,8 +36,6 @@ public class EhCacheBasedAclCache implements AclCache {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private Ehcache cache;
|
||||
private AuditLogger auditLogger;
|
||||
private AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
@@ -91,10 +81,10 @@ public class EhCacheBasedAclCache implements AclCache {
|
||||
return null;
|
||||
}
|
||||
|
||||
return initializeTransientFields((MutableAcl)element.getValue());
|
||||
return (MutableAcl) element.getValue();
|
||||
}
|
||||
|
||||
public MutableAcl getFromCache(Serializable pk) {
|
||||
public MutableAcl getFromCache(Serializable pk) {
|
||||
Assert.notNull(pk, "Primary key (identifier) required");
|
||||
|
||||
Element element = null;
|
||||
@@ -107,7 +97,7 @@ public class EhCacheBasedAclCache implements AclCache {
|
||||
return null;
|
||||
}
|
||||
|
||||
return initializeTransientFields((MutableAcl) element.getValue());
|
||||
return (MutableAcl) element.getValue();
|
||||
}
|
||||
|
||||
public void putInCache(MutableAcl acl) {
|
||||
@@ -115,13 +105,6 @@ public class EhCacheBasedAclCache implements AclCache {
|
||||
Assert.notNull(acl.getObjectIdentity(), "ObjectIdentity required");
|
||||
Assert.notNull(acl.getId(), "ID required");
|
||||
|
||||
if (this.aclAuthorizationStrategy == null) {
|
||||
if (acl instanceof AclImpl) {
|
||||
this.aclAuthorizationStrategy = (AclAuthorizationStrategy) FieldUtils.getProtectedFieldValue("aclAuthorizationStrategy", acl);
|
||||
this.auditLogger = (AuditLogger) FieldUtils.getProtectedFieldValue("auditLogger", acl);
|
||||
}
|
||||
}
|
||||
|
||||
if ((acl.getParentAcl() != null) && (acl.getParentAcl() instanceof MutableAcl)) {
|
||||
putInCache((MutableAcl) acl.getParentAcl());
|
||||
}
|
||||
@@ -129,12 +112,4 @@ public class EhCacheBasedAclCache implements AclCache {
|
||||
cache.put(new Element(acl.getObjectIdentity(), acl));
|
||||
cache.put(new Element(acl.getId(), acl));
|
||||
}
|
||||
|
||||
private MutableAcl initializeTransientFields(MutableAcl value) {
|
||||
if (value instanceof AclImpl) {
|
||||
FieldUtils.setProtectedFieldValue("aclAuthorizationStrategy", value, this.aclAuthorizationStrategy);
|
||||
FieldUtils.setProtectedFieldValue("auditLogger", value, this.auditLogger);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
@@ -53,11 +52,11 @@ 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 as obj_id, class.class as 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 = ?)";
|
||||
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 ================================================================================================
|
||||
|
||||
@@ -82,22 +81,21 @@ public class JdbcAclService implements AclService {
|
||||
public Object mapRow(ResultSet rs, int rowNum)
|
||||
throws SQLException {
|
||||
String javaType = rs.getString("class");
|
||||
Long identifier = new Long(rs.getLong("obj_id"));
|
||||
String identifier = rs.getString("obj_id");
|
||||
|
||||
return new ObjectIdentityImpl(javaType, identifier);
|
||||
}
|
||||
});
|
||||
|
||||
if (objects.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (ObjectIdentityImpl[]) objects.toArray(new ObjectIdentityImpl[objects.size()]);
|
||||
return (ObjectIdentityImpl[]) objects.toArray(new ObjectIdentityImpl[] {});
|
||||
}
|
||||
|
||||
public Acl readAclById(ObjectIdentity object, Sid[] sids) throws NotFoundException {
|
||||
Map map = readAclsById(new ObjectIdentity[] {object}, sids);
|
||||
Assert.isTrue(map.containsKey(object), "There should have been an Acl entry for ObjectIdentity " + object);
|
||||
|
||||
if (map.size() == 0) {
|
||||
throw new NotFoundException("Could not find ACL");
|
||||
}
|
||||
|
||||
return (Acl) map.get(object);
|
||||
}
|
||||
@@ -106,21 +104,11 @@ public class JdbcAclService implements AclService {
|
||||
return readAclById(object, null);
|
||||
}
|
||||
|
||||
public Map readAclsById(ObjectIdentity[] objects) throws NotFoundException {
|
||||
public Map readAclsById(ObjectIdentity[] objects) {
|
||||
return readAclsById(objects, null);
|
||||
}
|
||||
|
||||
public Map readAclsById(ObjectIdentity[] objects, Sid[] sids) throws NotFoundException {
|
||||
Map result = lookupStrategy.readAclsById(objects, sids);
|
||||
|
||||
// Check every requested object identity was found (throw NotFoundException if needed)
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
if (!result.containsKey(objects[i])) {
|
||||
throw new NotFoundException("Unable to find ACL information for object identity '"
|
||||
+ objects[i].toString() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return lookupStrategy.readAclsById(objects, sids);
|
||||
}
|
||||
}
|
||||
|
||||
+55
-84
@@ -60,25 +60,26 @@ import javax.sql.DataSource;
|
||||
public class JdbcMutableAclService extends JdbcAclService implements MutableAclService {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private boolean foreignKeysInDatabase = true;
|
||||
private AclCache aclCache;
|
||||
private String deleteEntryByObjectIdentityForeignKey = "delete from acl_entry where acl_object_identity=?";
|
||||
private String deleteObjectIdentityByPrimaryKey = "delete from acl_object_identity where id=?";
|
||||
private String classIdentityQuery = "call identity()"; // should be overridden for postgres : select currval('acl_class_seq')
|
||||
private String sidIdentityQuery = "call identity()"; // should be overridden for postgres : select currval('acl_siq_seq')
|
||||
private String insertClass = "insert into acl_class (class) values (?)";
|
||||
private String insertEntry = "insert into acl_entry "
|
||||
+ "(acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure)"
|
||||
+ "values (?, ?, ?, ?, ?, ?, ?)";
|
||||
private String insertObjectIdentity = "insert into acl_object_identity "
|
||||
+ "(object_id_class, object_id_identity, owner_sid, entries_inheriting) " + "values (?, ?, ?, ?)";
|
||||
private String insertSid = "insert into acl_sid (principal, sid) values (?, ?)";
|
||||
private String selectClassPrimaryKey = "select id from acl_class where 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=? "
|
||||
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 "
|
||||
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 ===================================================================================================
|
||||
@@ -177,7 +178,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
jdbcTemplate.update(insertClass, new Object[] {clazz.getName()});
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
|
||||
"Transaction must be running");
|
||||
classId = new Long(jdbcTemplate.queryForLong(classIdentityQuery));
|
||||
classId = new Long(jdbcTemplate.queryForLong(identityQuery));
|
||||
}
|
||||
} else {
|
||||
classId = (Long) classIds.iterator().next();
|
||||
@@ -222,7 +223,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
jdbcTemplate.update(insertSid, new Object[] {new Boolean(principal), sidName});
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
|
||||
"Transaction must be running");
|
||||
sidId = new Long(jdbcTemplate.queryForLong(sidIdentityQuery));
|
||||
sidId = new Long(jdbcTemplate.queryForLong(identityQuery));
|
||||
}
|
||||
} else {
|
||||
sidId = (Long) sidIds.iterator().next();
|
||||
@@ -236,60 +237,58 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
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) {
|
||||
ObjectIdentity[] children = findChildren(objectIdentity);
|
||||
if (children != null) {
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
deleteAcl(children[i], true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!foreignKeysInDatabase) {
|
||||
// We need to perform a manual verification for what a FK would normally do
|
||||
// We generally don't do this, in the interests of deadlock management
|
||||
ObjectIdentity[] children = findChildren(objectIdentity);
|
||||
if (children != null) {
|
||||
throw new ChildrenExistException("Cannot delete '" + objectIdentity + "' (has " + children.length
|
||||
+ " children)");
|
||||
}
|
||||
}
|
||||
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)");
|
||||
}
|
||||
|
||||
Long oidPrimaryKey = retrieveObjectIdentityPrimaryKey(objectIdentity);
|
||||
|
||||
// Delete this ACL's ACEs in the acl_entry table
|
||||
deleteEntries(oidPrimaryKey);
|
||||
deleteEntries(objectIdentity);
|
||||
|
||||
// Delete this ACL's acl_object_identity row
|
||||
deleteObjectIdentity(oidPrimaryKey);
|
||||
deleteObjectIdentityAndOptionallyClass(objectIdentity);
|
||||
|
||||
// Clear the cache
|
||||
aclCache.evictFromCache(objectIdentity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all ACEs defined in the acl_entry table belonging to the presented ObjectIdentity primary key.
|
||||
* Deletes all ACEs defined in the acl_entry table belonging to the presented ObjectIdentity
|
||||
*
|
||||
* @param oidPrimaryKey the rows in acl_entry to delete
|
||||
* @param oid the rows in acl_entry to delete
|
||||
*/
|
||||
protected void deleteEntries(Long oidPrimaryKey) {
|
||||
jdbcTemplate.update(deleteEntryByObjectIdentityForeignKey,
|
||||
new Object[] {oidPrimaryKey});
|
||||
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 primary key.
|
||||
*
|
||||
* <p>
|
||||
* We do not delete any entries from acl_class, even if no classes are using that class any longer. This is a
|
||||
* deadlock avoidance approach.
|
||||
* </p>
|
||||
* 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 oidPrimaryKey to delete the acl_object_identity
|
||||
* @param oid to delete the acl_object_identity (and clean up acl_class for that class name if appropriate)
|
||||
*/
|
||||
protected void deleteObjectIdentity(Long oidPrimaryKey) {
|
||||
protected void deleteObjectIdentityAndOptionallyClass(ObjectIdentity oid) {
|
||||
// Delete the acl_object_identity row
|
||||
jdbcTemplate.update(deleteObjectIdentityByPrimaryKey, new Object[] {oidPrimaryKey});
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -325,7 +324,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
Assert.notNull(acl.getId(), "Object Identity doesn't provide an identifier");
|
||||
|
||||
// Delete this ACL's ACEs in the acl_entry table
|
||||
deleteEntries(retrieveObjectIdentityPrimaryKey(acl.getObjectIdentity()));
|
||||
deleteEntries(acl.getObjectIdentity());
|
||||
|
||||
// Create this ACL's ACEs in the acl_entry table
|
||||
createEntries(acl);
|
||||
@@ -333,23 +332,12 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
// Change the mutable columns in acl_object_identity
|
||||
updateObjectIdentity(acl);
|
||||
|
||||
// Clear the cache, including children
|
||||
clearCacheIncludingChildren(acl.getObjectIdentity());
|
||||
// Clear the cache
|
||||
aclCache.evictFromCache(acl.getObjectIdentity());
|
||||
|
||||
// Retrieve the ACL via superclass (ensures cache registration, proper retrieval etc)
|
||||
return (MutableAcl) super.readAclById(acl.getObjectIdentity());
|
||||
}
|
||||
|
||||
private void clearCacheIncludingChildren(ObjectIdentity objectIdentity) {
|
||||
Assert.notNull(objectIdentity, "ObjectIdentity required");
|
||||
ObjectIdentity[] children = findChildren(objectIdentity);
|
||||
if (children != null) {
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
clearCacheIncludingChildren(children[i]);
|
||||
}
|
||||
}
|
||||
aclCache.evictFromCache(objectIdentity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing acl_object_identity row, with new information presented in the passed MutableAcl
|
||||
@@ -380,21 +368,4 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
throw new NotFoundException("Unable to locate ACL to update");
|
||||
}
|
||||
}
|
||||
|
||||
public void setClassIdentityQuery(String identityQuery) {
|
||||
Assert.hasText(identityQuery, "New identity query is required");
|
||||
this.classIdentityQuery = identityQuery;
|
||||
}
|
||||
|
||||
public void setSidIdentityQuery(String identityQuery) {
|
||||
Assert.hasText(identityQuery, "New identity query is required");
|
||||
this.sidIdentityQuery = identityQuery;
|
||||
}
|
||||
/**
|
||||
* @param foreignKeysInDatabase if false this class will perform additional FK constrain checking, which may
|
||||
* cause deadlocks (the default is true, so deadlocks are avoided but the database is expected to enforce FKs)
|
||||
*/
|
||||
public void setForeignKeysInDatabase(boolean foreignKeysInDatabase) {
|
||||
this.foreignKeysInDatabase = foreignKeysInDatabase;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
*/
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
@@ -23,7 +22,7 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* Performs lookups for {@link org.springframework.security.acls.AclService}.
|
||||
*
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
@@ -34,13 +33,11 @@ public interface LookupStrategy {
|
||||
* Perform database-specific optimized lookup.
|
||||
*
|
||||
* @param objects the identities to lookup (required)
|
||||
* @param sids the SIDs for which identities are required (may be <tt>null</tt> - implementations may elect not
|
||||
* @param sids the SIDs for which identities are required (may be <code>null</code> - implementations may elect not
|
||||
* to provide SID optimisations)
|
||||
*
|
||||
* @return a <tt>Map</tt> where keys represent the {@link ObjectIdentity} of the located {@link Acl} and values
|
||||
* are the located {@link Acl} (never <tt>null</tt> although some entries may be missing; this method
|
||||
* should not throw {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used
|
||||
* to automatically create entries if required)
|
||||
* @return the <code>Map</code> pursuant to the interface contract for {@link
|
||||
* org.springframework.security.acls.AclService#readAclsById(ObjectIdentity[], Sid[])}
|
||||
*/
|
||||
Map readAclsById(ObjectIdentity[] objects, Sid[] sids);
|
||||
}
|
||||
|
||||
+19
-21
@@ -18,15 +18,15 @@ import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* Represents the identity of an individual domain object instance.
|
||||
* Interface representing the identity of an individual domain object instance.
|
||||
*
|
||||
* <p>
|
||||
* As implementations of <tt>ObjectIdentity</tt> are used as the key to represent
|
||||
* domain objects in the ACL subsystem, it is essential that implementations provide
|
||||
* methods so that object-equality rather than reference-equality can be relied upon
|
||||
* reliably. In other words, the ACL subsystem can consider two
|
||||
* <tt>ObjectIdentity</tt>s equal if <tt>identity1.equals(identity2)</tt>, rather than
|
||||
* reference-equality of <tt>identity1==identity2</tt>.
|
||||
* <P>
|
||||
* As implementations are used as the key for caching and lookup, it is
|
||||
* essential that implementations provide methods so that object-equality
|
||||
* rather than reference-equality can be relied upon by caches. In other
|
||||
* words, a cache can consider two <code>ObjectIdentity</code>s equal if
|
||||
* <code>identity1.equals(identity2)</code>, rather than reference-equality of
|
||||
* <code>identity1==identity2</code>.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
@@ -36,37 +36,35 @@ 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 <tt>true</tt> if the objects are equal, <tt>false</tt> otherwise
|
||||
* @see Object#equals(Object)
|
||||
* @return <code>true</code> if the objects are equal, <code>false</code> otherwise
|
||||
*/
|
||||
boolean equals(Object obj);
|
||||
|
||||
/**
|
||||
* Obtains the actual identifier. This identifier must not be reused to represent other domain objects with
|
||||
* the same <tt>javaType</tt>.
|
||||
*
|
||||
* <p>Because ACLs are largely immutable, it is strongly recommended to use
|
||||
* 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 in the future such change will cascade to the ACL
|
||||
* subsystem data.</p>
|
||||
* business meaning, as that business meaning may change.</p>
|
||||
*
|
||||
* @return the identifier (unique within this <tt>javaType</tt>; never <tt>null</tt>)
|
||||
* @return the identifier (unique within this <code>javaType</code>
|
||||
*/
|
||||
Serializable getIdentifier();
|
||||
|
||||
/**
|
||||
* Obtains the Java type represented by the domain object. The Java type can be an interface or a class, but is
|
||||
* most often the domain object implementation class.
|
||||
* Obtains the Java type represented by the domain object.
|
||||
*
|
||||
* @return the Java type of the domain object (never <tt>null</tt>)
|
||||
* @return the Java type of the domain object
|
||||
*/
|
||||
Class getJavaType();
|
||||
|
||||
/**
|
||||
* @return a hash code representation of the <tt>ObjectIdentity</tt>
|
||||
* @see Object#hashCode()
|
||||
* Refer to the <code>java.lang.Object</code> documentation for the interface contract.
|
||||
*
|
||||
* @return a hash code representation of this object
|
||||
*/
|
||||
int hashCode();
|
||||
}
|
||||
|
||||
+3
-11
@@ -15,10 +15,8 @@
|
||||
package org.springframework.security.acls.objectidentity;
|
||||
|
||||
import org.springframework.security.acls.IdentityUnavailableException;
|
||||
import org.springframework.security.acls.jdbc.LookupStrategy;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -77,7 +75,7 @@ public class ObjectIdentityImpl implements ObjectIdentity {
|
||||
public ObjectIdentityImpl(Object object) throws IdentityUnavailableException {
|
||||
Assert.notNull(object, "object cannot be null");
|
||||
|
||||
this.javaType = ClassUtils.getUserClass(object.getClass());
|
||||
this.javaType = object.getClass();
|
||||
|
||||
Object result;
|
||||
|
||||
@@ -98,12 +96,6 @@ public class ObjectIdentityImpl implements ObjectIdentity {
|
||||
/**
|
||||
* 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>
|
||||
*
|
||||
* <p>
|
||||
* Note that this class uses string equality for the identifier field, which ensures it better supports
|
||||
* differences between {@link LookupStrategy} requirements and the domain object represented by this
|
||||
* <code>ObjectIdentityImpl</code>.
|
||||
* </p>
|
||||
*
|
||||
* @param arg0 object to compare
|
||||
*
|
||||
@@ -120,7 +112,7 @@ public class ObjectIdentityImpl implements ObjectIdentity {
|
||||
|
||||
ObjectIdentityImpl other = (ObjectIdentityImpl) arg0;
|
||||
|
||||
if (this.getIdentifier().toString().equals(other.getIdentifier().toString()) && this.getJavaType().equals(other.getJavaType())) {
|
||||
if (this.getIdentifier().equals(other.getIdentifier()) && this.getJavaType().equals(other.getJavaType())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -151,7 +143,7 @@ public class ObjectIdentityImpl implements ObjectIdentity {
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(this.getClass().getName()).append("[");
|
||||
sb.append("Java Type: ").append(this.javaType.getName());
|
||||
sb.append("Java Type: ").append(this.javaType);
|
||||
sb.append("; Identifier: ").append(this.identifier).append("]");
|
||||
|
||||
return sb.toString();
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
*/
|
||||
package org.springframework.security.acls.sid;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* A security identity recognised by the ACL system.
|
||||
*
|
||||
@@ -31,7 +29,7 @@ import java.io.Serializable;
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface Sid extends Serializable {
|
||||
public interface Sid {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
|
||||
+9
-9
@@ -34,20 +34,20 @@ import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Abstract {@link AfterInvocationProvider} which provides commonly-used ACL-related services.
|
||||
* DOCUMENT ME!
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @author $author$
|
||||
* @version $Revision$
|
||||
*/
|
||||
public abstract class AbstractAclProvider implements AfterInvocationProvider {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
protected AclService aclService;
|
||||
protected Class processDomainObjectClass = Object.class;
|
||||
protected ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||
protected SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||
protected String processConfigAttribute;
|
||||
protected Permission[] requirePermission = {BasePermission.READ};
|
||||
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 ===================================================================================================
|
||||
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@
|
||||
</bean>
|
||||
|
||||
<bean id="dataSource" class="org.springframework.security.TestDataSource">
|
||||
<constructor-arg value="acltest" />
|
||||
<constructor-arg value="test" />
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
||||
+2
@@ -86,6 +86,8 @@ public class AccessControlEntryTests extends TestCase {
|
||||
BasePermission.ADMINISTRATION, true, true, true)));
|
||||
Assert.assertFalse(ace.equals(new AccessControlEntryImpl(new Long(2), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, true, true, true)));
|
||||
Assert.assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), new MockAcl(), sid,
|
||||
BasePermission.ADMINISTRATION, true, true, true)));
|
||||
Assert.assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, new PrincipalSid("scott"),
|
||||
BasePermission.ADMINISTRATION, true, true, true)));
|
||||
Assert.assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid, BasePermission.WRITE, true,
|
||||
|
||||
@@ -138,14 +138,14 @@ public class AclImplTests extends TestCase {
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
try {
|
||||
acl.insertAce(0, null, new GrantedAuthoritySid("ROLE_IGNORED"), true);
|
||||
acl.insertAce(new Long(1), null, new GrantedAuthoritySid("ROLE_IGNORED"), true);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
acl.insertAce(0, BasePermission.READ, null, true);
|
||||
acl.insertAce(new Long(1), BasePermission.READ, null, true);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
@@ -168,7 +168,7 @@ public class AclImplTests extends TestCase {
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
// Insert one permission
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST1"), true);
|
||||
acl.insertAce(null, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST1"), true);
|
||||
service.updateAcl(acl);
|
||||
// Check it was successfully added
|
||||
assertEquals(1, acl.getEntries().length);
|
||||
@@ -177,7 +177,7 @@ public class AclImplTests extends TestCase {
|
||||
assertEquals(acl.getEntries()[0].getSid(), new GrantedAuthoritySid("ROLE_TEST1"));
|
||||
|
||||
// Add a second permission
|
||||
acl.insertAce(1, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST2"), true);
|
||||
acl.insertAce(null, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST2"), true);
|
||||
service.updateAcl(acl);
|
||||
// Check it was added on the last position
|
||||
assertEquals(2, acl.getEntries().length);
|
||||
@@ -186,7 +186,7 @@ public class AclImplTests extends TestCase {
|
||||
assertEquals(acl.getEntries()[1].getSid(), new GrantedAuthoritySid("ROLE_TEST2"));
|
||||
|
||||
// Add a third permission, after the first one
|
||||
acl.insertAce(1, BasePermission.WRITE, new GrantedAuthoritySid("ROLE_TEST3"), false);
|
||||
acl.insertAce(acl.getEntries()[0].getId(), BasePermission.WRITE, new GrantedAuthoritySid("ROLE_TEST3"), false);
|
||||
service.updateAcl(acl);
|
||||
assertEquals(3, acl.getEntries().length);
|
||||
// Check the third entry was added between the two existent ones
|
||||
@@ -213,11 +213,11 @@ public class AclImplTests extends TestCase {
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
// Insert one permission
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST1"), true);
|
||||
acl.insertAce(null, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST1"), true);
|
||||
service.updateAcl(acl);
|
||||
|
||||
try {
|
||||
acl.insertAce(55, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST2"), true);
|
||||
acl.insertAce(new Long(5), BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST2"), true);
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
@@ -240,28 +240,28 @@ public class AclImplTests extends TestCase {
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
// Add several permissions
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST1"), true);
|
||||
acl.insertAce(1, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST2"), true);
|
||||
acl.insertAce(2, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST3"), true);
|
||||
acl.insertAce(null, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST1"), true);
|
||||
acl.insertAce(null, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST2"), true);
|
||||
acl.insertAce(null, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST3"), true);
|
||||
service.updateAcl(acl);
|
||||
|
||||
// Delete first permission and check the order of the remaining permissions is kept
|
||||
acl.deleteAce(0);
|
||||
acl.deleteAce(new Long(1));
|
||||
assertEquals(2, acl.getEntries().length);
|
||||
assertEquals(acl.getEntries()[0].getSid(), new GrantedAuthoritySid("ROLE_TEST2"));
|
||||
assertEquals(acl.getEntries()[1].getSid(), new GrantedAuthoritySid("ROLE_TEST3"));
|
||||
|
||||
// Add one more permission and remove the permission in the middle
|
||||
acl.insertAce(2, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST4"), true);
|
||||
acl.insertAce(null, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST4"), true);
|
||||
service.updateAcl(acl);
|
||||
acl.deleteAce(1);
|
||||
acl.deleteAce(new Long(2));
|
||||
assertEquals(2, acl.getEntries().length);
|
||||
assertEquals(acl.getEntries()[0].getSid(), new GrantedAuthoritySid("ROLE_TEST2"));
|
||||
assertEquals(acl.getEntries()[1].getSid(), new GrantedAuthoritySid("ROLE_TEST4"));
|
||||
|
||||
// Remove remaining permissions
|
||||
acl.deleteAce(1);
|
||||
acl.deleteAce(0);
|
||||
acl.deleteAce(new Long(1));
|
||||
acl.deleteAce(new Long(3));
|
||||
assertEquals(0, acl.getEntries().length);
|
||||
}
|
||||
|
||||
@@ -278,7 +278,7 @@ public class AclImplTests extends TestCase {
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
try {
|
||||
acl.deleteAce(99);
|
||||
acl.deleteAce(new Long(1));
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
@@ -327,10 +327,10 @@ public class AclImplTests extends TestCase {
|
||||
"johndoe"));
|
||||
|
||||
// Grant some permissions
|
||||
rootAcl.insertAce(0, BasePermission.READ, new PrincipalSid("ben"), false);
|
||||
rootAcl.insertAce(1, BasePermission.WRITE, new PrincipalSid("scott"), true);
|
||||
rootAcl.insertAce(2, BasePermission.WRITE, new PrincipalSid("rod"), false);
|
||||
rootAcl.insertAce(3, BasePermission.WRITE, new GrantedAuthoritySid("WRITE_ACCESS_ROLE"), true);
|
||||
rootAcl.insertAce(null, BasePermission.READ, new PrincipalSid("ben"), false);
|
||||
rootAcl.insertAce(null, BasePermission.WRITE, new PrincipalSid("scott"), true);
|
||||
rootAcl.insertAce(null, BasePermission.WRITE, new PrincipalSid("rod"), false);
|
||||
rootAcl.insertAce(null, BasePermission.WRITE, new GrantedAuthoritySid("WRITE_ACCESS_ROLE"), true);
|
||||
|
||||
// Check permissions granting
|
||||
Permission[] permissions = new Permission[] { BasePermission.READ, BasePermission.CREATE };
|
||||
@@ -394,14 +394,14 @@ public class AclImplTests extends TestCase {
|
||||
parentAcl1.setParent(grandParentAcl);
|
||||
|
||||
// Add some permissions
|
||||
grandParentAcl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
grandParentAcl.insertAce(1, BasePermission.WRITE, new PrincipalSid("ben"), true);
|
||||
grandParentAcl.insertAce(2, BasePermission.DELETE, new PrincipalSid("ben"), false);
|
||||
grandParentAcl.insertAce(3, BasePermission.DELETE, new PrincipalSid("scott"), true);
|
||||
parentAcl1.insertAce(0, BasePermission.READ, new PrincipalSid("scott"), true);
|
||||
parentAcl1.insertAce(1, BasePermission.DELETE, new PrincipalSid("scott"), false);
|
||||
parentAcl2.insertAce(0, BasePermission.CREATE, new PrincipalSid("ben"), true);
|
||||
childAcl1.insertAce(0, BasePermission.CREATE, new PrincipalSid("scott"), true);
|
||||
grandParentAcl.insertAce(null, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
grandParentAcl.insertAce(null, BasePermission.WRITE, new PrincipalSid("ben"), true);
|
||||
grandParentAcl.insertAce(null, BasePermission.DELETE, new PrincipalSid("ben"), false);
|
||||
grandParentAcl.insertAce(null, BasePermission.DELETE, new PrincipalSid("scott"), true);
|
||||
parentAcl1.insertAce(null, BasePermission.READ, new PrincipalSid("scott"), true);
|
||||
parentAcl1.insertAce(null, BasePermission.DELETE, new PrincipalSid("scott"), false);
|
||||
parentAcl2.insertAce(null, BasePermission.CREATE, new PrincipalSid("ben"), true);
|
||||
childAcl1.insertAce(null, BasePermission.CREATE, new PrincipalSid("scott"), true);
|
||||
|
||||
// Check granting process for parent1
|
||||
assertTrue(parentAcl1.isGranted(new Permission[] { BasePermission.READ }, new Sid[] { new PrincipalSid("scott") },
|
||||
@@ -464,9 +464,9 @@ public class AclImplTests extends TestCase {
|
||||
"johndoe"));
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
acl.insertAce(1, BasePermission.WRITE, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
acl.insertAce(2, BasePermission.CREATE, new PrincipalSid("ben"), true);
|
||||
acl.insertAce(null, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
acl.insertAce(null, BasePermission.WRITE, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
acl.insertAce(null, BasePermission.CREATE, new PrincipalSid("ben"), true);
|
||||
service.updateAcl(acl);
|
||||
|
||||
assertEquals(acl.getEntries()[0].getPermission(), BasePermission.READ);
|
||||
@@ -474,9 +474,9 @@ public class AclImplTests extends TestCase {
|
||||
assertEquals(acl.getEntries()[2].getPermission(), BasePermission.CREATE);
|
||||
|
||||
// Change each permission
|
||||
acl.updateAce(0, BasePermission.CREATE);
|
||||
acl.updateAce(1, BasePermission.DELETE);
|
||||
acl.updateAce(2, BasePermission.READ);
|
||||
acl.updateAce(new Long(1), BasePermission.CREATE);
|
||||
acl.updateAce(new Long(2), BasePermission.DELETE);
|
||||
acl.updateAce(new Long(3), BasePermission.READ);
|
||||
|
||||
// Check the change was successfuly made
|
||||
assertEquals(acl.getEntries()[0].getPermission(), BasePermission.CREATE);
|
||||
@@ -498,8 +498,8 @@ public class AclImplTests extends TestCase {
|
||||
"johndoe"));
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
acl.insertAce(1, BasePermission.WRITE, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
acl.insertAce(null, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
acl.insertAce(null, BasePermission.WRITE, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
service.updateAcl(acl);
|
||||
|
||||
assertFalse(((AuditableAccessControlEntry) acl.getEntries()[0]).isAuditFailure());
|
||||
@@ -508,8 +508,8 @@ public class AclImplTests extends TestCase {
|
||||
assertFalse(((AuditableAccessControlEntry) acl.getEntries()[1]).isAuditSuccess());
|
||||
|
||||
// Change each permission
|
||||
((AuditableAcl) acl).updateAuditing(0, true, true);
|
||||
((AuditableAcl) acl).updateAuditing(1, true, true);
|
||||
((AuditableAcl) acl).updateAuditing(new Long(1), true, true);
|
||||
((AuditableAcl) acl).updateAuditing(new Long(2), true, true);
|
||||
|
||||
// Check the change was successfuly made
|
||||
assertTrue(((AuditableAccessControlEntry) acl.getEntries()[0]).isAuditFailure());
|
||||
@@ -534,8 +534,8 @@ public class AclImplTests extends TestCase {
|
||||
MutableAcl parentAcl = new AclImpl(identity2, new Long(2), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
MockAclService service = new MockAclService();
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
acl.insertAce(1, BasePermission.WRITE, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
acl.insertAce(null, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
acl.insertAce(null, BasePermission.WRITE, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
service.updateAcl(acl);
|
||||
|
||||
assertEquals(acl.getId(), new Long(1));
|
||||
|
||||
+7
-7
@@ -114,7 +114,7 @@ public class AclImplementationSecurityCheckTests extends TestCase {
|
||||
// Let's give the principal the ADMINISTRATION permission, without
|
||||
// granting access
|
||||
MutableAcl aclFirstDeny = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
aclFirstDeny.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), false);
|
||||
aclFirstDeny.insertAce(null, BasePermission.ADMINISTRATION, new PrincipalSid(auth), false);
|
||||
|
||||
// The CHANGE_GENERAL test should pass as the principal has ROLE_GENERAL
|
||||
try {
|
||||
@@ -143,7 +143,7 @@ public class AclImplementationSecurityCheckTests extends TestCase {
|
||||
}
|
||||
|
||||
// Add granting access to this principal
|
||||
aclFirstDeny.insertAce(1, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
aclFirstDeny.insertAce(null, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
// and try again for CHANGE_AUDITING - the first ACE's granting flag
|
||||
// (false) will deny this access
|
||||
try {
|
||||
@@ -158,7 +158,7 @@ public class AclImplementationSecurityCheckTests extends TestCase {
|
||||
// permission, with granting access
|
||||
MutableAcl aclFirstAllow = new AclImpl(identity, new Long(1), aclAuthorizationStrategy,
|
||||
new ConsoleAuditLogger());
|
||||
aclFirstAllow.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
aclFirstAllow.insertAce(null, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
|
||||
// The CHANGE_AUDITING test should pass as there is one ACE with
|
||||
// granting access
|
||||
@@ -171,7 +171,7 @@ public class AclImplementationSecurityCheckTests extends TestCase {
|
||||
}
|
||||
|
||||
// Add a deny ACE and test again for CHANGE_AUDITING
|
||||
aclFirstAllow.insertAce(1, BasePermission.ADMINISTRATION, new PrincipalSid(auth), false);
|
||||
aclFirstAllow.insertAce(null, BasePermission.ADMINISTRATION, new PrincipalSid(auth), false);
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstAllow, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.assertTrue(true);
|
||||
@@ -215,8 +215,8 @@ public class AclImplementationSecurityCheckTests extends TestCase {
|
||||
// Let's give the principal an ADMINISTRATION permission, with granting
|
||||
// access
|
||||
MutableAcl parentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
parentAcl.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
MutableAcl childAcl = new AclImpl(identity, new Long(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
parentAcl.insertAce(null, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
MutableAcl childAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
|
||||
// Check against the 'child' acl, which doesn't offer any authorization
|
||||
// rights on CHANGE_OWNERSHIP
|
||||
@@ -244,7 +244,7 @@ public class AclImplementationSecurityCheckTests extends TestCase {
|
||||
MutableAcl rootParentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy,
|
||||
new ConsoleAuditLogger());
|
||||
parentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
rootParentAcl.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
rootParentAcl.insertAce(null, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
parentAcl.setEntriesInheriting(true);
|
||||
parentAcl.setParent(rootParentAcl);
|
||||
childAcl.setParent(parentAcl);
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.springframework.security.acls.Permission;
|
||||
|
||||
|
||||
/**
|
||||
* Tests classes associated with Permission.
|
||||
* Tests BasePermission and CumulativePermission.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id${date}
|
||||
@@ -63,9 +63,9 @@ public class PermissionTests {
|
||||
assertEquals("CumulativePermission[...............................R=1]",
|
||||
new CumulativePermission().set(BasePermission.READ).toString());
|
||||
|
||||
System.out.println("A = " + new CumulativePermission().set(SpecialPermission.ENTER).set(BasePermission.ADMINISTRATION).toString());
|
||||
assertEquals("CumulativePermission[..........................EA....=48]",
|
||||
new CumulativePermission().set(SpecialPermission.ENTER).set(BasePermission.ADMINISTRATION).toString());
|
||||
System.out.println("A = " + new CumulativePermission().set(BasePermission.ADMINISTRATION).toString());
|
||||
assertEquals("CumulativePermission[...........................A....=16]",
|
||||
new CumulativePermission().set(BasePermission.ADMINISTRATION).toString());
|
||||
|
||||
System.out.println("RA = "
|
||||
+ new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ).toString());
|
||||
|
||||
-209
@@ -1,209 +0,0 @@
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
|
||||
import org.springframework.cache.ehcache.EhCacheFactoryBean;
|
||||
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
|
||||
import org.springframework.security.acls.domain.AclImpl;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.domain.ConsoleAuditLogger;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.sid.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.DefaultTransactionDefinition;
|
||||
|
||||
public class AclPermissionInheritanceTests extends TestCase {
|
||||
|
||||
private JdbcMutableAclService aclService;
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
private DriverManagerDataSource dataSource;
|
||||
private DataSourceTransactionManager txManager;
|
||||
private TransactionStatus txStatus;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
|
||||
dataSource = new DriverManagerDataSource();
|
||||
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
dataSource.setUrl("jdbc:hsqldb:mem:permissiontest");
|
||||
dataSource.setUsername("sa");
|
||||
dataSource.setPassword("");
|
||||
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
|
||||
txManager = new DataSourceTransactionManager();
|
||||
txManager.setDataSource(dataSource);
|
||||
|
||||
txStatus = txManager.getTransaction(new DefaultTransactionDefinition());
|
||||
|
||||
aclService = createAclService(dataSource);
|
||||
|
||||
Authentication auth = new UsernamePasswordAuthenticationToken(
|
||||
"system", "secret", new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_IGNORED")});
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
txManager.rollback(txStatus);
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
public void test1() throws Exception {
|
||||
|
||||
createAclSchema(jdbcTemplate);
|
||||
|
||||
ObjectIdentityImpl rootObject =
|
||||
new ObjectIdentityImpl(TestDomainObject.class, new Long(1));
|
||||
|
||||
MutableAcl parent = aclService.createAcl(rootObject);
|
||||
MutableAcl child = aclService.createAcl(new ObjectIdentityImpl(TestDomainObject.class, new Long(2)));
|
||||
child.setParent(parent);
|
||||
aclService.updateAcl(child);
|
||||
|
||||
parent = (AclImpl) aclService.readAclById(rootObject);
|
||||
parent.insertAce(0, BasePermission.READ,
|
||||
new PrincipalSid("john"), true);
|
||||
aclService.updateAcl(parent);
|
||||
|
||||
parent = (AclImpl) aclService.readAclById(rootObject);
|
||||
parent.insertAce(1, BasePermission.READ,
|
||||
new PrincipalSid("joe"), true);
|
||||
aclService.updateAcl(parent);
|
||||
|
||||
child = (MutableAcl) aclService.readAclById(
|
||||
new ObjectIdentityImpl(TestDomainObject.class, new Long(2)));
|
||||
|
||||
parent = (MutableAcl) child.getParentAcl();
|
||||
|
||||
assertEquals("Fails because child has a stale reference to its parent",
|
||||
2, parent.getEntries().length);
|
||||
assertEquals(1, parent.getEntries()[0].getPermission().getMask());
|
||||
assertEquals(new PrincipalSid("john"), parent.getEntries()[0].getSid());
|
||||
assertEquals(1, parent.getEntries()[1].getPermission().getMask());
|
||||
assertEquals(new PrincipalSid("joe"), parent.getEntries()[1].getSid());
|
||||
|
||||
}
|
||||
public void test2() throws Exception {
|
||||
|
||||
createAclSchema(jdbcTemplate);
|
||||
|
||||
ObjectIdentityImpl rootObject =
|
||||
new ObjectIdentityImpl(TestDomainObject.class, new Long(1));
|
||||
|
||||
MutableAcl parent = aclService.createAcl(rootObject);
|
||||
MutableAcl child = aclService.createAcl(new ObjectIdentityImpl(TestDomainObject.class, new Long(2)));
|
||||
child.setParent(parent);
|
||||
aclService.updateAcl(child);
|
||||
|
||||
parent.insertAce(0, BasePermission.ADMINISTRATION,
|
||||
new GrantedAuthoritySid("ROLE_ADMINISTRATOR"), true);
|
||||
aclService.updateAcl(parent);
|
||||
|
||||
parent.insertAce(1, BasePermission.DELETE, new PrincipalSid("terry"), true);
|
||||
aclService.updateAcl(parent);
|
||||
|
||||
child = (MutableAcl) aclService.readAclById(
|
||||
new ObjectIdentityImpl(TestDomainObject.class, new Long(2)));
|
||||
|
||||
parent = (MutableAcl) child.getParentAcl();
|
||||
|
||||
assertEquals(2, parent.getEntries().length);
|
||||
assertEquals(16, parent.getEntries()[0].getPermission().getMask());
|
||||
assertEquals(new GrantedAuthoritySid("ROLE_ADMINISTRATOR"), parent.getEntries()[0].getSid());
|
||||
assertEquals(8, parent.getEntries()[1].getPermission().getMask());
|
||||
assertEquals(new PrincipalSid("terry"), parent.getEntries()[1].getSid());
|
||||
|
||||
}
|
||||
|
||||
private JdbcMutableAclService createAclService(DriverManagerDataSource ds)
|
||||
throws IOException {
|
||||
|
||||
GrantedAuthorityImpl adminAuthority = new GrantedAuthorityImpl("ROLE_ADMINISTRATOR");
|
||||
AclAuthorizationStrategyImpl authStrategy = new AclAuthorizationStrategyImpl(
|
||||
new GrantedAuthorityImpl[]{adminAuthority,adminAuthority,adminAuthority});
|
||||
|
||||
EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();
|
||||
ehCacheManagerFactoryBean.afterPropertiesSet();
|
||||
CacheManager cacheManager = (CacheManager) ehCacheManagerFactoryBean.getObject();
|
||||
|
||||
EhCacheFactoryBean ehCacheFactoryBean = new EhCacheFactoryBean();
|
||||
ehCacheFactoryBean.setCacheName("aclAche");
|
||||
ehCacheFactoryBean.setCacheManager(cacheManager);
|
||||
ehCacheFactoryBean.afterPropertiesSet();
|
||||
Ehcache ehCache = (Ehcache) ehCacheFactoryBean.getObject();
|
||||
|
||||
AclCache aclAche = new EhCacheBasedAclCache(ehCache);
|
||||
|
||||
BasicLookupStrategy lookupStrategy =
|
||||
new BasicLookupStrategy(ds, aclAche, authStrategy, new ConsoleAuditLogger());
|
||||
|
||||
return new JdbcMutableAclService(ds,lookupStrategy, aclAche);
|
||||
}
|
||||
|
||||
private void createAclSchema(JdbcTemplate jdbcTemplate) {
|
||||
|
||||
jdbcTemplate.execute("DROP TABLE ACL_ENTRY IF EXISTS;");
|
||||
jdbcTemplate.execute("DROP TABLE ACL_OBJECT_IDENTITY IF EXISTS;");
|
||||
jdbcTemplate.execute("DROP TABLE ACL_CLASS IF EXISTS");
|
||||
jdbcTemplate.execute("DROP TABLE ACL_SID IF EXISTS");
|
||||
|
||||
jdbcTemplate.execute(
|
||||
"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));");
|
||||
jdbcTemplate.execute(
|
||||
"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));");
|
||||
jdbcTemplate.execute(
|
||||
"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));");
|
||||
jdbcTemplate.execute(
|
||||
"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));");
|
||||
}
|
||||
|
||||
public static class TestDomainObject {
|
||||
|
||||
private Long id;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
-13
@@ -3,9 +3,9 @@ package org.springframework.security.acls.jdbc;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import net.sf.ehcache.Cache;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.Cache;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
@@ -21,8 +21,6 @@ import org.springframework.security.TestDataSource;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
@@ -120,8 +118,7 @@ public class BasicLookupStrategyTests {
|
||||
public void testAclsRetrievalWithDefaultBatchSize() throws Exception {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
// Deliberately use an integer for the child, to reproduce bug report in SEC-819
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(102));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
|
||||
Map map = this.strategy.readAclsById(new ObjectIdentity[] { topParentOid, middleParentOid, childOid }, null);
|
||||
checkEntries(topParentOid, middleParentOid, childOid, map);
|
||||
@@ -129,7 +126,7 @@ public class BasicLookupStrategyTests {
|
||||
|
||||
@Test
|
||||
public void testAclsRetrievalFromCacheOnly() throws Exception {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(100));
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
|
||||
@@ -146,7 +143,7 @@ public class BasicLookupStrategyTests {
|
||||
@Test
|
||||
public void testAclsRetrievalWithCustomBatchSize() throws Exception {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(101));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
|
||||
// Set a batch size to allow multiple database queries in order to retrieve all acls
|
||||
@@ -228,7 +225,7 @@ public class BasicLookupStrategyTests {
|
||||
jdbcTemplate.execute(query);
|
||||
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(101));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
ObjectIdentity middleParent2Oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(103));
|
||||
|
||||
@@ -250,7 +247,7 @@ public class BasicLookupStrategyTests {
|
||||
/**
|
||||
* Test created from SEC-590.
|
||||
*/
|
||||
@Test
|
||||
/* @Test
|
||||
public void testReadAllObjectIdentitiesWhenLastElementIsAlreadyCached() throws Exception {
|
||||
String query = "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (4,2,104,null,1,1);"
|
||||
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (5,2,105,4,1,1);"
|
||||
@@ -261,8 +258,8 @@ public class BasicLookupStrategyTests {
|
||||
|
||||
ObjectIdentity grandParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(104));
|
||||
ObjectIdentity parent1Oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(105));
|
||||
ObjectIdentity parent2Oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(106));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(107));
|
||||
ObjectIdentity parent2Oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(106));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(107));
|
||||
|
||||
// First lookup only child, thus populating the cache with grandParent, parent1 and child
|
||||
Permission[] checkPermission = new Permission[] { BasePermission.READ };
|
||||
@@ -289,6 +286,23 @@ public class BasicLookupStrategyTests {
|
||||
Acl foundParent2Acl = (Acl) foundAcls.get(parent2Oid);
|
||||
Assert.assertNotNull(foundParent2Acl);
|
||||
Assert.assertTrue(foundParent2Acl.isGranted(checkPermission, sids, false));
|
||||
}
|
||||
}*/
|
||||
|
||||
@Test
|
||||
public void testAclsWithDifferentSerializableTypesAsObjectIdentities() throws Exception {
|
||||
String query = "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (4,2,104,null,1,1);"
|
||||
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (5,4,0,1,1,1,0,0)";
|
||||
jdbcTemplate.execute(query);
|
||||
|
||||
ObjectIdentity oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(104));
|
||||
Sid[] sids = new Sid[] { new PrincipalSid("ben") };
|
||||
ObjectIdentity[] childOids = new ObjectIdentity[] { oid };
|
||||
|
||||
try {
|
||||
Map foundAcls = strategy.readAclsById(childOids, sids);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
} catch(IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-60
@@ -1,25 +1,11 @@
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
import net.sf.ehcache.Cache;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
@@ -32,7 +18,12 @@ import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.TestingAuthenticationToken;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Tests {@link EhCacheBasedAclCache}
|
||||
@@ -47,8 +38,7 @@ public class EhCacheBasedAclCacheTests {
|
||||
@BeforeClass
|
||||
public static void initCacheManaer() {
|
||||
cacheManager = new CacheManager();
|
||||
// Use disk caching immediately (to test for serialization issue reported in SEC-527)
|
||||
cacheManager.addCache(new Cache("ehcachebasedacltests", 0, true, false, 30, 30));
|
||||
cacheManager.addCache(new Cache("ehcachebasedacltests", 500, false, false, 30, 30));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
@@ -125,36 +115,6 @@ public class EhCacheBasedAclCacheTests {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
// SEC-527
|
||||
@Test
|
||||
public void testDiskSerializationOfMutableAclObjectInstance() throws Exception {
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
|
||||
// Serialization test
|
||||
File file = File.createTempFile("SEC_TEST", ".object");
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
ObjectOutputStream oos = new ObjectOutputStream(fos);
|
||||
oos.writeObject(acl);
|
||||
oos.close();
|
||||
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
ObjectInputStream ois = new ObjectInputStream(fis);
|
||||
MutableAcl retrieved = (MutableAcl) ois.readObject();
|
||||
ois.close();
|
||||
|
||||
assertEquals(acl, retrieved);
|
||||
|
||||
Object retrieved1 = FieldUtils.getProtectedFieldValue("aclAuthorizationStrategy", retrieved);
|
||||
assertEquals(null, retrieved1);
|
||||
|
||||
Object retrieved2 = FieldUtils.getProtectedFieldValue("auditLogger", retrieved);
|
||||
assertEquals(null, retrieved2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheOperationsAclWithoutParent() throws Exception {
|
||||
@@ -167,13 +127,9 @@ public class EhCacheBasedAclCacheTests {
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
|
||||
assertEquals(0, cache.getDiskStoreSize());
|
||||
myCache.putInCache(acl);
|
||||
assertEquals(cache.getSize(), 2);
|
||||
assertEquals(2, cache.getDiskStoreSize());
|
||||
assertTrue(cache.isElementOnDisk(acl.getObjectIdentity()));
|
||||
assertFalse(cache.isElementInMemory(acl.getObjectIdentity()));
|
||||
|
||||
|
||||
// Check we can get from cache the same objects we put in
|
||||
assertEquals(myCache.getFromCache(new Long(1)), acl);
|
||||
assertEquals(myCache.getFromCache(identity), acl);
|
||||
@@ -184,17 +140,14 @@ public class EhCacheBasedAclCacheTests {
|
||||
|
||||
myCache.putInCache(acl2);
|
||||
assertEquals(cache.getSize(), 4);
|
||||
assertEquals(4, cache.getDiskStoreSize());
|
||||
|
||||
// Try to evict an entry that doesn't exist
|
||||
myCache.evictFromCache(new Long(3));
|
||||
myCache.evictFromCache(new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102)));
|
||||
assertEquals(cache.getSize(), 4);
|
||||
assertEquals(4, cache.getDiskStoreSize());
|
||||
|
||||
myCache.evictFromCache(new Long(1));
|
||||
assertEquals(cache.getSize(), 2);
|
||||
assertEquals(2, cache.getDiskStoreSize());
|
||||
|
||||
// Check the second object inserted
|
||||
assertEquals(myCache.getFromCache(new Long(2)), acl2);
|
||||
@@ -224,12 +177,8 @@ public class EhCacheBasedAclCacheTests {
|
||||
|
||||
acl.setParent(parentAcl);
|
||||
|
||||
assertEquals(0, cache.getDiskStoreSize());
|
||||
myCache.putInCache(acl);
|
||||
assertEquals(cache.getSize(), 4);
|
||||
assertEquals(4, cache.getDiskStoreSize());
|
||||
assertTrue(cache.isElementOnDisk(acl.getObjectIdentity()));
|
||||
assertFalse(cache.isElementInMemory(acl.getObjectIdentity()));
|
||||
|
||||
// Check we can get from cache the same objects we put in
|
||||
assertEquals(myCache.getFromCache(new Long(1)), acl);
|
||||
|
||||
@@ -20,12 +20,12 @@ import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AlreadyExistsException;
|
||||
import org.springframework.security.acls.ChildrenExistException;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.domain.AclImpl;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
@@ -97,7 +97,7 @@ public class JdbcAclServiceTests extends AbstractTransactionalDataSourceSpringCo
|
||||
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(102));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
|
||||
MutableAcl topParent = jdbcMutableAclService.createAcl(topParentOid);
|
||||
MutableAcl middleParent = jdbcMutableAclService.createAcl(middleParentOid);
|
||||
@@ -108,10 +108,10 @@ public class JdbcAclServiceTests extends AbstractTransactionalDataSourceSpringCo
|
||||
child.setParent(middleParent);
|
||||
|
||||
// Now let's add a couple of permissions
|
||||
topParent.insertAce(0, BasePermission.READ, new PrincipalSid(auth), true);
|
||||
topParent.insertAce(1, BasePermission.WRITE, new PrincipalSid(auth), false);
|
||||
middleParent.insertAce(0, BasePermission.DELETE, new PrincipalSid(auth), true);
|
||||
child.insertAce(0, BasePermission.DELETE, new PrincipalSid(auth), false);
|
||||
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);
|
||||
@@ -144,8 +144,10 @@ public class JdbcAclServiceTests extends AbstractTransactionalDataSourceSpringCo
|
||||
|
||||
// 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(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 {
|
||||
@@ -184,10 +186,10 @@ public class JdbcAclServiceTests extends AbstractTransactionalDataSourceSpringCo
|
||||
}
|
||||
|
||||
// Let's add an identical permission to the child, but it'll appear AFTER the current permission, so has no impact
|
||||
child.insertAce(1, BasePermission.DELETE, new PrincipalSid(auth), true);
|
||||
child.insertAce(null, BasePermission.DELETE, new PrincipalSid(auth), true);
|
||||
|
||||
// Let's also add another permission to the child
|
||||
child.insertAce(2, BasePermission.CREATE, new PrincipalSid(auth), true);
|
||||
child.insertAce(null, BasePermission.CREATE, new PrincipalSid(auth), true);
|
||||
|
||||
// Save the changed child
|
||||
jdbcMutableAclService.updateAcl(child);
|
||||
@@ -211,7 +213,7 @@ public class JdbcAclServiceTests extends AbstractTransactionalDataSourceSpringCo
|
||||
assertNotNull(entry.getId());
|
||||
|
||||
// Now delete that first ACE
|
||||
child.deleteAce(0);
|
||||
child.deleteAce(entry.getId());
|
||||
|
||||
// Save and check it worked
|
||||
child = jdbcMutableAclService.updateAcl(child);
|
||||
@@ -224,15 +226,11 @@ public class JdbcAclServiceTests extends AbstractTransactionalDataSourceSpringCo
|
||||
/**
|
||||
* Test method that demonstrates eviction failure from cache - SEC-676
|
||||
*/
|
||||
public void testDeleteAclAlsoDeletesChildren() throws Exception {
|
||||
/* public void testDeleteAclAlsoDeletesChildren() throws Exception {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
|
||||
// Check the childOid really is a child of middleParentOid
|
||||
Acl childAcl = jdbcMutableAclService.readAclById(childOid);
|
||||
assertEquals(middleParentOid, childAcl.getParentAcl().getObjectIdentity());
|
||||
|
||||
// Delete the mid-parent and test if the child was deleted, as well
|
||||
jdbcMutableAclService.deleteAcl(middleParentOid, true);
|
||||
|
||||
@@ -254,7 +252,7 @@ public class JdbcAclServiceTests extends AbstractTransactionalDataSourceSpringCo
|
||||
Acl acl = jdbcMutableAclService.readAclById(topParentOid);
|
||||
assertNotNull(acl);
|
||||
assertEquals(((MutableAcl) acl).getObjectIdentity(), topParentOid);
|
||||
}
|
||||
}*/
|
||||
|
||||
public void testConstructorRejectsNullParameters() throws Exception {
|
||||
try {
|
||||
@@ -318,17 +316,29 @@ public class JdbcAclServiceTests extends AbstractTransactionalDataSourceSpringCo
|
||||
public void testDeleteAclWithChildrenThrowsException() throws Exception {
|
||||
try {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
jdbcMutableAclService.setForeignKeysInDatabase(false); // switch on FK checking in the class, not database
|
||||
jdbcMutableAclService.deleteAcl(topParentOid, false);
|
||||
fail("It should have thrown ChildrenExistException");
|
||||
}
|
||||
catch (ChildrenExistException expected) {
|
||||
assertTrue(true);
|
||||
} finally {
|
||||
jdbcMutableAclService.setForeignKeysInDatabase(true); // restore to the default
|
||||
}
|
||||
}
|
||||
|
||||
public void testDeleteAllAclsRemovesAclClassRecord() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ADMINISTRATOR")});
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
|
||||
// Remove all acls associated with a certain class type
|
||||
jdbcMutableAclService.deleteAcl(topParentOid, true);
|
||||
|
||||
// Check the acl_class table is empty
|
||||
assertEquals(0, getJdbcTemplate().queryForList(SELECT_ALL_CLASSES, new Object[] {"org.springframework.security.TargetObject"} ).size());
|
||||
}
|
||||
|
||||
public void testDeleteAclRemovesRowsFromDatabase() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ADMINISTRATOR")});
|
||||
@@ -337,7 +347,7 @@ public class JdbcAclServiceTests extends AbstractTransactionalDataSourceSpringCo
|
||||
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(102));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
|
||||
// Remove the child and check all related database rows were removed accordingly
|
||||
jdbcMutableAclService.deleteAcl(childOid, false);
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
target
|
||||
.settings
|
||||
.classpath
|
||||
.project
|
||||
.wtpmodules
|
||||
@@ -0,0 +1,31 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0-M2</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-cas-adapter</artifactId>
|
||||
<name>Spring Security - CAS adapter</name>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cas</groupId>
|
||||
<artifactId>cas-server</artifactId>
|
||||
<version>3.0.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cas</groupId>
|
||||
<artifactId>cas</artifactId>
|
||||
<version>2.0.12</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/* 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.springframework.security.adapters.cas;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthenticationException;
|
||||
import org.springframework.security.AuthenticationManager;
|
||||
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
|
||||
|
||||
/**
|
||||
* Provides actual CAS authentication by delegation to an <code>AuthenticationManager</code>.<P>Do not use this
|
||||
* class directly. Instead configure CAS to use the {@link CasPasswordHandlerProxy}.</p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public final class CasPasswordHandler implements InitializingBean {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(CasPasswordHandler.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (this.authenticationManager == null) {
|
||||
throw new IllegalArgumentException("An AuthenticationManager is required");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by <code>CasPasswordHandlerProxy</code> for individual authentication requests.<P>Delegates to
|
||||
* the configured <code>AuthenticationManager</code>.</p>
|
||||
*
|
||||
* @param servletRequest as provided by CAS
|
||||
* @param username provided to CAS
|
||||
* @param password provided to CAS
|
||||
*
|
||||
* @return whether authentication was successful or not
|
||||
*/
|
||||
public boolean authenticate(ServletRequest servletRequest, String username, String password) {
|
||||
if ((username == null) || "".equals(username)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (password == null) {
|
||||
password = "";
|
||||
}
|
||||
|
||||
Authentication request = new UsernamePasswordAuthenticationToken(username.toString(), password.toString());
|
||||
Authentication response = null;
|
||||
|
||||
try {
|
||||
response = authenticationManager.authenticate(request);
|
||||
} catch (AuthenticationException failed) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication request for user: " + username + " failed: " + failed.toString());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication request for user: " + username + " successful");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public AuthenticationManager getAuthenticationManager() {
|
||||
return authenticationManager;
|
||||
}
|
||||
|
||||
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
|
||||
this.authenticationManager = authenticationManager;
|
||||
}
|
||||
}
|
||||
+114
@@ -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.springframework.security.adapters.cas;
|
||||
|
||||
import edu.yale.its.tp.cas.auth.PasswordHandler;
|
||||
|
||||
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 java.util.Map;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
|
||||
/**
|
||||
* Enables CAS to use the Spring Security for authentication.<P>This class works along with {@link
|
||||
* CasPasswordHandler} to enable users to easily migrate from stand-alone Spring Security deployments to
|
||||
* enterprise-wide CAS deployments.</p>
|
||||
* <p>It should be noted that Spring Security will operate as a CAS client irrespective of the
|
||||
* <code>PasswordHandler</code> used on the CAS server. In other words, this class need <B>not</B> be used on the CAS
|
||||
* server if not desired. It exists solely for the convenience of users wishing have CAS delegate to a Spring Security-based
|
||||
* <code>AuthenticationManager</code>.</p>
|
||||
* <p>This class works requires a properly configured <code>CasPasswordHandler</code>. On the first authentication
|
||||
* request, the class will use Spring's {@link WebApplicationContextUtils#getRequiredWebApplicationContext(ServletContext)}
|
||||
* method to obtain an <code>ApplicationContext</code> instance, inside which must be a configured
|
||||
* <code>CasPasswordHandler</code> instance. The <code>CasPasswordHandlerProxy</code> will then delegate
|
||||
* authentication requests to that instance.</p>
|
||||
* <p>To configure CAS to use this class, edit CAS' <code>web.xml</code> and define the
|
||||
* <code>edu.yale.its.tp.cas.authHandler</code> context parameter with the value
|
||||
* <code>org.springframework.security.adapters.cas.CasPasswordHandlerProxy</code>.</p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id:CasPasswordHandlerProxy.java 2151 2007-09-22 11:54:13Z luke_t $
|
||||
*/
|
||||
public class CasPasswordHandlerProxy implements PasswordHandler {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(CasPasswordHandlerProxy.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private ApplicationContext ctx;
|
||||
private CasPasswordHandler handler;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Called by CAS when authentication is required.<P>Delegates to the <code>CasPasswordHandler</code>.</p>
|
||||
*
|
||||
* @param request as provided by CAS
|
||||
* @param username provided to CAS
|
||||
* @param password provided to CAS
|
||||
*
|
||||
* @return whether authentication was successful or not
|
||||
*
|
||||
* @throws IllegalArgumentException if the application context does not contain a <code>CasPasswordHandler</code>
|
||||
* or the <code>ServletRequest</code> was not of type <code>HttpServletRequest</code>
|
||||
*/
|
||||
public boolean authenticate(ServletRequest request, String username, String password) {
|
||||
if (ctx == null) {
|
||||
if (!(request instanceof HttpServletRequest)) {
|
||||
throw new IllegalArgumentException("Can only process HttpServletRequest");
|
||||
}
|
||||
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
|
||||
ctx = this.getContext(httpRequest);
|
||||
}
|
||||
|
||||
if (handler == null) {
|
||||
Map beans = ctx.getBeansOfType(CasPasswordHandler.class, true, true);
|
||||
|
||||
if (beans.size() == 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Bean context must contain at least one bean of type CasPasswordHandler");
|
||||
}
|
||||
|
||||
String beanName = (String) beans.keySet().iterator().next();
|
||||
handler = (CasPasswordHandler) beans.get(beanName);
|
||||
}
|
||||
|
||||
return handler.authenticate(request, username, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows test cases to override where application context obtained from.
|
||||
*
|
||||
* @param httpRequest which can be used to find the <code>ServletContext</code>
|
||||
*
|
||||
* @return the Spring application context
|
||||
*/
|
||||
protected ApplicationContext getContext(HttpServletRequest httpRequest) {
|
||||
return WebApplicationContextUtils.getRequiredWebApplicationContext(httpRequest.getSession().getServletContext());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
Adapter to Yale Central Authentication Service (CAS).
|
||||
<p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/* 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.springframework.security.adapters.cas3;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthenticationManager;
|
||||
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.jasig.cas.authentication.handler.AuthenticationException;
|
||||
import org.jasig.cas.authentication.handler.AuthenticationHandler;
|
||||
import org.jasig.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;
|
||||
import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Provides JA-SIG CAS 3 authentication by delegating to the Spring Security <code>AuthenticationManager</code>.</p>
|
||||
* <p>This class would be configured in the <code>webapp/WEB-INF/deployerConfigContext.xml</code> file in the CAS
|
||||
* distribution.</p>
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Id:CasAuthenticationHandler.java 2151 2007-09-22 11:54:13Z luke_t $
|
||||
*
|
||||
* @see AuthenticationHandler
|
||||
* @see AuthenticationManager
|
||||
*/
|
||||
public final class CasAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
private Log log = LogFactory.getLog(this.getClass());
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
protected void afterPropertiesSetInternal() throws Exception {
|
||||
Assert.notNull(this.authenticationManager, "authenticationManager cannot be null.");
|
||||
}
|
||||
|
||||
protected boolean authenticateUsernamePasswordInternal(final UsernamePasswordCredentials credentials)
|
||||
throws AuthenticationException {
|
||||
final Authentication authenticationRequest = new UsernamePasswordAuthenticationToken(credentials.getUsername(),
|
||||
credentials.getPassword());
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Attempting to authenticate for user: " + credentials.getUsername());
|
||||
}
|
||||
|
||||
try {
|
||||
this.authenticationManager.authenticate(authenticationRequest);
|
||||
} catch (final org.springframework.security.AuthenticationException e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Authentication request for " + credentials.getUsername() + " failed: " + e.toString(), e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Authentication request for " + credentials.getUsername() + " successful.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to set the Spring Security <code>AuthenticationManager</code> to delegate to.
|
||||
*
|
||||
* @param authenticationManager the Spring Security AuthenticationManager that knows how to authenticate users.
|
||||
*/
|
||||
public void setAuthenticationManager(final AuthenticationManager authenticationManager) {
|
||||
this.authenticationManager = authenticationManager;
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
|
||||
<!--
|
||||
* Copyright 2004 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.
|
||||
*
|
||||
* Demonstration of the applicationContext.xml that should be placed in
|
||||
* CAS' WEB-INF directory. Note the CasPasswordHandler bean.
|
||||
*
|
||||
* $Id$
|
||||
-->
|
||||
|
||||
<beans>
|
||||
|
||||
<!-- Data access object which stores authentication information -->
|
||||
<bean id="inMemoryDaoImpl" class="org.springframework.security.userdetails.memory.InMemoryDaoImpl">
|
||||
<property name="userMap">
|
||||
<value>
|
||||
rod=koala,ROLES_IGNORED_BY_CAS
|
||||
dianne=emu,ROLES_IGNORED_BY_CAS
|
||||
scott=wombat,ROLES_IGNORED_BY_CAS
|
||||
peter=opal,disabled,ROLES_IGNORED_BY_CAS
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="daoAuthenticationProvider" class="org.springframework.security.providers.dao.DaoAuthenticationProvider">
|
||||
<property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property>
|
||||
</bean>
|
||||
|
||||
<bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">
|
||||
<property name="providers">
|
||||
<list>
|
||||
<ref bean="daoAuthenticationProvider"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="casPasswordHandler" class="org.springframework.security.adapters.cas.CasPasswordHandler">
|
||||
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
|
||||
</bean>
|
||||
</beans>
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
|
||||
<!--
|
||||
* Copyright 2004 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.
|
||||
*
|
||||
* Demonstration of the applicationContext.xml that should be copied into
|
||||
* JA-SIG CAS's webapp/WEB-INF/deployerConfigContext.xml
|
||||
* The example CAS AuthenticationHandler should be placed within CAS's
|
||||
* AuthenticationManager's authenticationHandler list property.
|
||||
*
|
||||
* The Spring Security-specific beans can just be placed in the context file.
|
||||
*
|
||||
* $Id:applicationContext.xml 2151 2007-09-22 11:54:13Z luke_t $
|
||||
-->
|
||||
<beans>
|
||||
|
||||
<!-- Data access object which stores authentication information -->
|
||||
<bean id="inMemoryDaoImpl" class="org.springframework.security.userdetails.memory.InMemoryDaoImpl">
|
||||
<property name="userMap">
|
||||
<value>
|
||||
rod=koala,ROLES_IGNORED_BY_CAS
|
||||
dianne=emu,ROLES_IGNORED_BY_CAS
|
||||
scott=wombat,ROLES_IGNORED_BY_CAS
|
||||
peter=opal,disabled,ROLES_IGNORED_BY_CAS
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="daoAuthenticationProvider" class="org.springframework.security.providers.dao.DaoAuthenticationProvider">
|
||||
<property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property>
|
||||
</bean>
|
||||
|
||||
<bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">
|
||||
<property name="providers">
|
||||
<list>
|
||||
<ref bean="daoAuthenticationProvider"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="casAuthenticationHandler" class="org.springframework.security.adapters.cas3.CasAuthenticationHandler">
|
||||
<property name="authenticationManager" ref="authenticationManager" />
|
||||
</bean>
|
||||
</beans>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
|
||||
<project name="Spring Security CAS Adapter">
|
||||
<body>
|
||||
<menu ref="parent"/>
|
||||
<menu ref="reports"/>
|
||||
</body>
|
||||
|
||||
</project>
|
||||
|
||||
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
/* 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.springframework.security.adapters.cas;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link CasPasswordHandlerProxy}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class CasPasswordHandlerProxyTests extends TestCase {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public CasPasswordHandlerProxyTests() {
|
||||
super();
|
||||
}
|
||||
|
||||
public CasPasswordHandlerProxyTests(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(CasPasswordHandlerProxyTests.class);
|
||||
}
|
||||
|
||||
public final void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
public void testDetectsIfHttpServletRequestNotPassed() {
|
||||
CasPasswordHandlerProxy proxy = new MockCasPasswordHandlerProxy(
|
||||
"org/springframework/security/adapters/cas/applicationContext-valid.xml");
|
||||
|
||||
try {
|
||||
proxy.authenticate(null, "x", "y");
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertEquals("Can only process HttpServletRequest", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testDetectsMissingDelegate() {
|
||||
CasPasswordHandlerProxy proxy = new MockCasPasswordHandlerProxy(
|
||||
"org/springframework/security/adapters/cas/applicationContext-invalid.xml");
|
||||
|
||||
try {
|
||||
proxy.authenticate(new MockHttpServletRequest(), "x", "y");
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertEquals("Bean context must contain at least one bean of type CasPasswordHandler", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testNormalOperation() {
|
||||
CasPasswordHandlerProxy proxy = new MockCasPasswordHandlerProxy(
|
||||
"org/springframework/security/adapters/cas/applicationContext-valid.xml");
|
||||
assertTrue(proxy.authenticate(new MockHttpServletRequest(), "rod", "koala"));
|
||||
assertFalse(proxy.authenticate(new MockHttpServletRequest(), "rod", "WRONG_PASSWORD"));
|
||||
assertFalse(proxy.authenticate(new MockHttpServletRequest(), "INVALID_USER_NAME", "WRONG_PASSWORD"));
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
/**
|
||||
* Mock object so that application context source can be specified.
|
||||
*/
|
||||
private class MockCasPasswordHandlerProxy extends CasPasswordHandlerProxy {
|
||||
private ApplicationContext ctx;
|
||||
|
||||
public MockCasPasswordHandlerProxy(String appContextLocation) {
|
||||
ctx = new ClassPathXmlApplicationContext(appContextLocation);
|
||||
}
|
||||
|
||||
private MockCasPasswordHandlerProxy() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected ApplicationContext getContext(HttpServletRequest httpRequest) {
|
||||
return ctx;
|
||||
}
|
||||
}
|
||||
}
|
||||
+101
@@ -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.springframework.security.adapters.cas;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.MockAuthenticationManager;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link CasPasswordHandler}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class CasPasswordHandlerTests extends TestCase {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public CasPasswordHandlerTests() {
|
||||
super();
|
||||
}
|
||||
|
||||
public CasPasswordHandlerTests(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(CasPasswordHandlerTests.class);
|
||||
}
|
||||
|
||||
public final void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
public void testDeniesAccessWhenAuthenticationManagerThrowsException()
|
||||
throws Exception {
|
||||
CasPasswordHandler handler = new CasPasswordHandler();
|
||||
handler.setAuthenticationManager(new MockAuthenticationManager(false));
|
||||
handler.afterPropertiesSet();
|
||||
|
||||
assertFalse(handler.authenticate(new MockHttpServletRequest(), "username", "password"));
|
||||
}
|
||||
|
||||
public void testDetectsEmptyAuthenticationManager()
|
||||
throws Exception {
|
||||
CasPasswordHandler handler = new CasPasswordHandler();
|
||||
|
||||
try {
|
||||
handler.afterPropertiesSet();
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertEquals("An AuthenticationManager is required", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testGettersSetters() {
|
||||
CasPasswordHandler handler = new CasPasswordHandler();
|
||||
handler.setAuthenticationManager(new MockAuthenticationManager(false));
|
||||
assertTrue(handler.getAuthenticationManager() != null);
|
||||
}
|
||||
|
||||
public void testGracefullyHandlesEmptyUsernamesAndPassword()
|
||||
throws Exception {
|
||||
CasPasswordHandler handler = new CasPasswordHandler();
|
||||
handler.setAuthenticationManager(new MockAuthenticationManager(true));
|
||||
handler.afterPropertiesSet();
|
||||
|
||||
// If empty or null username we return false
|
||||
assertFalse(handler.authenticate(new MockHttpServletRequest(), "", "password"));
|
||||
assertFalse(handler.authenticate(new MockHttpServletRequest(), null, "password"));
|
||||
|
||||
// We authenticate with null passwords (they might not have one)
|
||||
assertTrue(handler.authenticate(new MockHttpServletRequest(), "user", null));
|
||||
assertTrue(handler.authenticate(new MockHttpServletRequest(), "user", ""));
|
||||
}
|
||||
|
||||
public void testNormalOperation() throws Exception {
|
||||
CasPasswordHandler handler = new CasPasswordHandler();
|
||||
handler.setAuthenticationManager(new MockAuthenticationManager(true));
|
||||
handler.afterPropertiesSet();
|
||||
|
||||
assertTrue(handler.authenticate(new MockHttpServletRequest(), "username", "password"));
|
||||
}
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/* 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.springframework.security.adapters.cas3;
|
||||
|
||||
import org.springframework.security.AuthenticationManager;
|
||||
|
||||
import org.jasig.cas.authentication.handler.AuthenticationException;
|
||||
import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;
|
||||
|
||||
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link CasAuthenticationHandler}
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @version $Id$
|
||||
*/
|
||||
public class CasAuthenticationHandlerTests extends AbstractDependencyInjectionSpringContextTests {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
private CasAuthenticationHandler casAuthenticationHandler;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
protected String[] getConfigLocations() {
|
||||
return new String[] {"/org/springframework/security/adapters/cas/applicationContext-valid.xml"};
|
||||
}
|
||||
|
||||
private UsernamePasswordCredentials getCredentialsFor(final String username, final String password) {
|
||||
final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials();
|
||||
credentials.setUsername(username);
|
||||
credentials.setPassword(password);
|
||||
|
||||
return credentials;
|
||||
}
|
||||
|
||||
protected void onSetUp() throws Exception {
|
||||
this.casAuthenticationHandler = new CasAuthenticationHandler();
|
||||
this.casAuthenticationHandler.setAuthenticationManager(authenticationManager);
|
||||
this.casAuthenticationHandler.afterPropertiesSet();
|
||||
}
|
||||
|
||||
public void setAuthenticationManager(final AuthenticationManager authenticationManager) {
|
||||
this.authenticationManager = authenticationManager;
|
||||
}
|
||||
|
||||
public void testAfterPropertiesSet() throws Exception {
|
||||
this.casAuthenticationHandler.setAuthenticationManager(null);
|
||||
|
||||
try {
|
||||
this.casAuthenticationHandler.afterPropertiesSet();
|
||||
fail("IllegalArgumenException expected when no AuthenticationManager is set.");
|
||||
} catch (final IllegalArgumentException e) {
|
||||
// this is okay
|
||||
}
|
||||
}
|
||||
|
||||
public void testGracefullyHandlesInvalidInput() {
|
||||
try {
|
||||
assertFalse(this.casAuthenticationHandler.authenticate(getCredentialsFor("", "")));
|
||||
assertFalse(this.casAuthenticationHandler.authenticate(getCredentialsFor(null, null)));
|
||||
} catch (final AuthenticationException e) {
|
||||
fail("AuthenticationException not expected.");
|
||||
}
|
||||
}
|
||||
|
||||
public void testInvalidUsernamePasswordCombination() {
|
||||
try {
|
||||
assertFalse(this.casAuthenticationHandler.authenticate(getCredentialsFor("scott", "scott")));
|
||||
} catch (final AuthenticationException e) {
|
||||
fail("AuthenticationException not expected.");
|
||||
}
|
||||
}
|
||||
|
||||
public void testValidUsernamePasswordCombination() {
|
||||
try {
|
||||
assertTrue(this.casAuthenticationHandler.authenticate(getCredentialsFor("scott", "wombat")));
|
||||
} catch (final AuthenticationException e) {
|
||||
fail("AuthenticationException not expected.");
|
||||
}
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
|
||||
<!--
|
||||
* Copyright 2004 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.
|
||||
*
|
||||
* $Id$
|
||||
-->
|
||||
|
||||
<beans>
|
||||
|
||||
<bean id="inMemoryDaoImpl" class="org.springframework.security.userdetails.memory.InMemoryDaoImpl">
|
||||
<property name="userMap">
|
||||
<value>
|
||||
rod=koala,ROLE_TELLER,ROLE_SUPERVISOR
|
||||
dianne=emu,ROLE_TELLER
|
||||
scott=wombat,ROLE_TELLER
|
||||
peter=opal,disabled,ROLE_TELLER
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="daoAuthenticationProvider" class="org.springframework.security.providers.dao.DaoAuthenticationProvider">
|
||||
<property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property>
|
||||
</bean>
|
||||
|
||||
<bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">
|
||||
<property name="providers">
|
||||
<list>
|
||||
<ref bean="daoAuthenticationProvider"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- No CasPasswordHandler -->
|
||||
</beans>
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
|
||||
<!--
|
||||
* Copyright 2004 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.
|
||||
*
|
||||
* $Id$
|
||||
-->
|
||||
|
||||
<beans>
|
||||
|
||||
<bean id="inMemoryDaoImpl" class="org.springframework.security.userdetails.memory.InMemoryDaoImpl">
|
||||
<property name="userMap">
|
||||
<value>
|
||||
rod=koala,ROLE_TELLER,ROLE_SUPERVISOR
|
||||
dianne=emu,ROLE_TELLER
|
||||
scott=wombat,ROLE_TELLER
|
||||
peter=opal,disabled,ROLE_TELLER
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="daoAuthenticationProvider" class="org.springframework.security.providers.dao.DaoAuthenticationProvider">
|
||||
<property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property>
|
||||
</bean>
|
||||
|
||||
<bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">
|
||||
<property name="providers">
|
||||
<list>
|
||||
<ref bean="daoAuthenticationProvider"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="casPasswordHandler" class="org.springframework.security.adapters.cas.CasPasswordHandler">
|
||||
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
|
||||
</bean>
|
||||
</beans>
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.3</version>
|
||||
<version>2.0-M2</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-catalina</artifactId>
|
||||
<name>Spring Security - Catalina adapter</name>
|
||||
|
||||
+4
-4
@@ -197,8 +197,8 @@ public class CatalinaSpringSecurityUserRealmTests extends TestCase {
|
||||
PrincipalSpringSecurityUserToken castResult = (PrincipalSpringSecurityUserToken) result;
|
||||
assertEquals("rod", castResult.getPrincipal());
|
||||
assertEquals("koala", castResult.getCredentials());
|
||||
assertEquals("ROLE_TELLER", castResult.getAuthorities()[1].getAuthority());
|
||||
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[0].getAuthority());
|
||||
assertEquals("ROLE_TELLER", castResult.getAuthorities()[0].getAuthority());
|
||||
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[1].getAuthority());
|
||||
assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
|
||||
}
|
||||
|
||||
@@ -214,8 +214,8 @@ public class CatalinaSpringSecurityUserRealmTests extends TestCase {
|
||||
PrincipalSpringSecurityUserToken castResult = (PrincipalSpringSecurityUserToken) result;
|
||||
assertEquals("rod", castResult.getPrincipal());
|
||||
assertEquals("koala", castResult.getCredentials());
|
||||
assertEquals("ROLE_TELLER", castResult.getAuthorities()[1].getAuthority());
|
||||
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[0].getAuthority());
|
||||
assertEquals("ROLE_TELLER", castResult.getAuthorities()[0].getAuthority());
|
||||
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[1].getAuthority());
|
||||
assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.3</version>
|
||||
<version>2.0-M2</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-jboss</artifactId>
|
||||
<name>Spring Security - JBoss adapter</name>
|
||||
@@ -14,9 +14,11 @@
|
||||
<version>3.2.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
</dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ import javax.security.auth.login.LoginException;
|
||||
* which is subsequently available from <code>java:comp/env/security/subject</code>.</p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Sergio Bern
|
||||
* @author Sergio Bern�
|
||||
* @version $Id:JbossSpringSecurityLoginModule.java 2151 2007-09-22 11:54:13Z luke_t $
|
||||
*/
|
||||
public class JbossSpringSecurityLoginModule extends AbstractServerLoginModule {
|
||||
|
||||
+2
-2
@@ -240,8 +240,8 @@ public class JbossSpringSecurityLoginModuleTests extends TestCase {
|
||||
PrincipalSpringSecurityUserToken castResult = (PrincipalSpringSecurityUserToken) result;
|
||||
assertEquals("rod", castResult.getPrincipal());
|
||||
assertEquals("koala", castResult.getCredentials());
|
||||
assertEquals("ROLE_TELLER", castResult.getAuthorities()[1].getAuthority());
|
||||
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[0].getAuthority());
|
||||
assertEquals("ROLE_TELLER", castResult.getAuthorities()[0].getAuthority());
|
||||
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[1].getAuthority());
|
||||
assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -29,7 +29,7 @@ import javax.naming.NamingException;
|
||||
* <code>java:comp/env/security/subject</code>.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id:MockInitialContext.java 2151 2007-09-22 11:54:13Z luke_t $
|
||||
* @version $Id$
|
||||
*/
|
||||
public class MockInitialContext implements Context {
|
||||
//~ Instance fields ================================================================================================
|
||||
@@ -42,6 +42,10 @@ public class MockInitialContext implements Context {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
private MockInitialContext() {
|
||||
super();
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public Object addToEnvironment(String propName, Object propVal)
|
||||
|
||||
+5
-1
@@ -24,7 +24,7 @@ import javax.naming.NamingException;
|
||||
* constructor.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id:MockJbossIntegrationFilter.java 2151 2007-09-22 11:54:13Z luke_t $
|
||||
* @version $Id$
|
||||
*/
|
||||
public class MockJbossIntegrationFilter extends JbossIntegrationFilter {
|
||||
//~ Instance fields ================================================================================================
|
||||
@@ -37,6 +37,10 @@ public class MockJbossIntegrationFilter extends JbossIntegrationFilter {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
private MockJbossIntegrationFilter() {
|
||||
super();
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
protected Context getLookupContext() throws NamingException {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.3</version>
|
||||
<version>2.0-M2</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-jetty</artifactId>
|
||||
<name>Spring Security - Jetty adapter</name>
|
||||
|
||||
+2
-2
@@ -164,8 +164,8 @@ public class JettyAcegiUserRealmTests extends TestCase {
|
||||
JettySpringSecurityUserToken castResult = (JettySpringSecurityUserToken) result;
|
||||
assertEquals("rod", castResult.getPrincipal());
|
||||
assertEquals("koala", castResult.getCredentials());
|
||||
assertEquals("ROLE_TELLER", castResult.getAuthorities()[1].getAuthority());
|
||||
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[0].getAuthority());
|
||||
assertEquals("ROLE_TELLER", castResult.getAuthorities()[0].getAuthority());
|
||||
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[1].getAuthority());
|
||||
assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>2.0.3</version>
|
||||
<version>2.0-M2</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<name>Spring Security - Adapters</name>
|
||||
@@ -21,6 +21,7 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<modules>
|
||||
<module>cas</module>
|
||||
<module>catalina</module>
|
||||
<module>jboss</module>
|
||||
<module>jetty</module>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.3</version>
|
||||
<version>2.0-M2</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-resin</artifactId>
|
||||
<name>Spring Security - Resin adapter</name>
|
||||
@@ -14,9 +14,11 @@
|
||||
<version>3.0.9</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
</dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
|
||||
+4
-4
@@ -171,8 +171,8 @@ public class ResinAcegiAuthenticatorTests extends TestCase {
|
||||
PrincipalSpringSecurityUserToken castResult = (PrincipalSpringSecurityUserToken) result;
|
||||
assertEquals("rod", castResult.getPrincipal());
|
||||
assertEquals("koala", castResult.getCredentials());
|
||||
assertEquals("ROLE_TELLER", castResult.getAuthorities()[1].getAuthority());
|
||||
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[0].getAuthority());
|
||||
assertEquals("ROLE_TELLER", castResult.getAuthorities()[0].getAuthority());
|
||||
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[1].getAuthority());
|
||||
assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
|
||||
}
|
||||
|
||||
@@ -192,8 +192,8 @@ public class ResinAcegiAuthenticatorTests extends TestCase {
|
||||
PrincipalSpringSecurityUserToken castResult = (PrincipalSpringSecurityUserToken) result;
|
||||
assertEquals("rod", castResult.getPrincipal());
|
||||
assertEquals("koala", castResult.getCredentials());
|
||||
assertEquals("ROLE_TELLER", castResult.getAuthorities()[1].getAuthority());
|
||||
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[0].getAuthority());
|
||||
assertEquals("ROLE_TELLER", castResult.getAuthorities()[0].getAuthority());
|
||||
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[1].getAuthority());
|
||||
assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
|
||||
}
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
<parent>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<version>2.0.2-SNAPSHOT</version>
|
||||
<version>2.0-M2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-captcha</artifactId>
|
||||
<name>Spring Security - Captcha module</name>
|
||||
<version>2.0.2-SNAPSHOT</version>
|
||||
<name>Spring Security - Catptcha Module</name>
|
||||
<version>2.0-M2</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -23,10 +23,6 @@
|
||||
<version>${project.version}</version>
|
||||
<classifier>tests</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
@@ -34,4 +30,4 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
+9
-6
@@ -19,11 +19,8 @@
|
||||
package org.springframework.security.captcha;
|
||||
|
||||
/**
|
||||
* Return false if the number of requests for captcha protcted URLs for the user
|
||||
* exceeds the threshold value.
|
||||
*
|
||||
* <br/>
|
||||
* Default keyword : <tt>REQUIRES_CAPTCHA_ABOVE_THRESHOLD_REQUESTS</tt>
|
||||
* <p>return false if ny CaptchaChannelProcessorTemplate of mapped urls has been requested more than thresold; <br>
|
||||
* Default keyword : REQUIRES_CAPTCHA_ABOVE_THRESOLD_REQUESTS</p>
|
||||
*
|
||||
* @author Marc-Antoine Garrigue
|
||||
* @version $Id$
|
||||
@@ -36,6 +33,9 @@ public class AlwaysTestAfterMaxRequestsCaptchaChannelProcessor extends CaptchaCh
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public AlwaysTestAfterMaxRequestsCaptchaChannelProcessor() {
|
||||
this.setKeyword(DEFAULT_KEYWORD);
|
||||
}
|
||||
@@ -43,8 +43,11 @@ public class AlwaysTestAfterMaxRequestsCaptchaChannelProcessor extends CaptchaCh
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Verify whether the context is valid concerning humanity
|
||||
*
|
||||
* @return false if the number of requests for captcha protected URLs exceeds the threshold.
|
||||
* @param context
|
||||
*
|
||||
* @return true if valid, false otherwise
|
||||
*/
|
||||
boolean isContextValidConcerningHumanity(CaptchaSecurityContext context) {
|
||||
if (context.getHumanRestrictedResourcesRequestsCount() < getThreshold()) {
|
||||
+9
-6
@@ -16,8 +16,8 @@
|
||||
package org.springframework.security.captcha;
|
||||
|
||||
/**
|
||||
* Return false if the time in millis since the last captcha test is less than the threshold;<br/>
|
||||
* Default keyword : <tt>REQUIRES_CAPTCHA_AFTER_THRESHOLD_IN_MILLIS</tt>.
|
||||
* <p>return false if thresold is greater than millis since last captcha test has occured;<br>
|
||||
* Default keyword : REQUIRES_CAPTCHA_AFTER_THRESOLD_IN_MILLIS</p>
|
||||
*
|
||||
* @author Marc-Antoine Garrigue
|
||||
* @version $Id$
|
||||
@@ -30,6 +30,9 @@ public class AlwaysTestAfterTimeInMillisCaptchaChannelProcessor extends CaptchaC
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public AlwaysTestAfterTimeInMillisCaptchaChannelProcessor() {
|
||||
|
||||
this.setKeyword(DEFAULT_KEYWORD);
|
||||
@@ -38,19 +41,19 @@ public class AlwaysTestAfterTimeInMillisCaptchaChannelProcessor extends CaptchaC
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Returns false if the time (in milliseconds) since the last captcha validation is greater than the
|
||||
* threshold value.
|
||||
* Verify wheter the context is valid concerning humanity
|
||||
*
|
||||
* @param context the CaptchaSecurityContext
|
||||
*
|
||||
* @return true if valid, false otherwise
|
||||
*/
|
||||
boolean isContextValidConcerningHumanity(CaptchaSecurityContext context) {
|
||||
if ((System.currentTimeMillis() - context.getLastPassedCaptchaDateInMillis()) < getThreshold()) {
|
||||
logger.debug("context is valid : current time - last passed captcha date < threshold");
|
||||
logger.debug("context is valid : last passed captcha date - current time < thresold");
|
||||
|
||||
return true;
|
||||
} else {
|
||||
logger.debug("context is not valid : current time - last passed captcha date > threshold");
|
||||
logger.debug("context is not valid : last passed captcha date - current time > thresold");
|
||||
|
||||
return false;
|
||||
}
|
||||
+15
-8
@@ -19,10 +19,10 @@ import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Return false if the average time in millis between any CaptchaChannelProcessorTemplate mapped
|
||||
* urls requests is greater than the threshold value or the context is not human;<br />
|
||||
* Default keyword : <tt>REQUIRES_CAPTCHA_BELOW_AVERAGE_TIME_IN_MILLIS_REQUESTS</tt> <br>
|
||||
* Note : before first humanity check
|
||||
* <p>return false if thresold is lower than average time millis between any CaptchaChannelProcessorTemplate mapped
|
||||
* urls requests and is human;<br>
|
||||
* Default keyword : REQUIRES_CAPTCHA_BELOW_AVERAGE_TIME_IN_MILLIS_REQUESTS <br>
|
||||
* Note : before first humanity check</p>
|
||||
*
|
||||
* @author Marc-Antoine Garrigue
|
||||
* @version $Id$
|
||||
@@ -35,6 +35,9 @@ public class AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor e
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor() {
|
||||
this.setKeyword(DEFAULT_KEYWORD);
|
||||
}
|
||||
@@ -42,7 +45,7 @@ public class AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor e
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Verify that threshold is > 0
|
||||
* Verify if thresold is > 0
|
||||
*
|
||||
* @throws Exception if false
|
||||
*/
|
||||
@@ -52,7 +55,11 @@ public class AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor e
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Verify wheter the context is valid concerning humanity
|
||||
*
|
||||
* @param context
|
||||
*
|
||||
* @return true if valid, false otherwise
|
||||
*/
|
||||
boolean isContextValidConcerningHumanity(CaptchaSecurityContext context) {
|
||||
int req = context.getHumanRestrictedResourcesRequestsCount();
|
||||
@@ -67,11 +74,11 @@ public class AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor e
|
||||
}
|
||||
|
||||
if (context.isHuman() && (average > thresold)) {
|
||||
logger.debug("context is valid : average time between requests < threshold && is human");
|
||||
logger.debug("context is valid : average time between requests < thresold && is human");
|
||||
|
||||
return true;
|
||||
} else {
|
||||
logger.debug("context is not valid : average time between requests > threshold or is not human");
|
||||
logger.debug("context is not valid : request count > thresold or is not human");
|
||||
|
||||
return false;
|
||||
}
|
||||
+5
-5
@@ -40,21 +40,21 @@ import javax.servlet.ServletException;
|
||||
|
||||
|
||||
/**
|
||||
* CaptchaChannel template : Ensures the user has enough human privileges by review of the {@link
|
||||
* <p>CaptchaChannel template : Ensures the user has enough human privileges by review of the {@link
|
||||
* CaptchaSecurityContext} and using an abstract routine {@link
|
||||
* #isContextValidConcerningHumanity(CaptchaSecurityContext)} (implemented by sub classes)
|
||||
* <p>The component uses 2 main parameters for its configuration :
|
||||
* #isContextValidConcerningHumanity(CaptchaSecurityContext)} (implemented by sub classes)</p>
|
||||
* <P>The component uses 2 main parameters for its configuration :
|
||||
* <ul>
|
||||
* <li>a keyword to be mapped to urls in the {@link
|
||||
* org.springframework.security.securechannel.ChannelProcessingFilter} configuration<br>
|
||||
* default value provided by sub classes.</li>
|
||||
* <li>and a threshold : used by the routine {@link
|
||||
* <li>and a thresold : used by the routine {@link
|
||||
* #isContextValidConcerningHumanity(CaptchaSecurityContext)} to evaluate whether the {@link
|
||||
* CaptchaSecurityContext} is valid default value = 0</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @author Marc-Antoine Garrigue
|
||||
* @author marc antoine Garrigue
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class CaptchaChannelProcessorTemplate implements ChannelProcessor, InitializingBean {
|
||||
+5
-2
@@ -47,6 +47,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
* The captcha entry point : redirect to the captcha test page.
|
||||
* <p>
|
||||
* This entry point can force the use of SSL : see {@link #getForceHttps()}
|
||||
* </p>
|
||||
* <p>
|
||||
* This entry point allows internal OR external redirect : see {@link #setOutsideWebApp(boolean)}<br />
|
||||
* / Original request can be added to the redirect path using a custom translation : see
|
||||
@@ -81,7 +82,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
* @author Marc-Antoine Garrigue
|
||||
* @author marc antoine Garrigue
|
||||
* @version $Id$
|
||||
*/
|
||||
public class CaptchaEntryPoint implements ChannelEntryPoint, InitializingBean {
|
||||
@@ -325,8 +326,10 @@ public class CaptchaEntryPoint implements ChannelEntryPoint, InitializingBean {
|
||||
this.captchaFormUrl = captchaFormUrl;
|
||||
}
|
||||
|
||||
// ~ Methods
|
||||
// ================================================================
|
||||
/**
|
||||
* Set to true to force captcha form access to be via https. If this value is true (the default is false),
|
||||
* Set to true to force captcha form access to be via https. If this value is ture (the default is false),
|
||||
* and the incoming request for the protected resource which triggered the interceptor was not already
|
||||
* <code>https</code>, then
|
||||
*
|
||||
+8
-6
@@ -19,39 +19,41 @@ import org.springframework.security.context.SecurityContext;
|
||||
|
||||
|
||||
/**
|
||||
* Interface that adds humanity concerns to the SecurityContext
|
||||
* Interface that add humanity concerns to the SecurityContext
|
||||
*
|
||||
* @author Marc-Antoine Garrigue
|
||||
* @version $Id$
|
||||
* @author marc antoine garrigue
|
||||
*/
|
||||
public interface CaptchaSecurityContext extends SecurityContext {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* DOCUMENT ME!
|
||||
*
|
||||
* @return the number of human restricted resources requested since the last passed captcha.
|
||||
* @return number of human restricted resources requests since the last passed captcha.
|
||||
*/
|
||||
int getHumanRestrictedResourcesRequestsCount();
|
||||
|
||||
/**
|
||||
* DOCUMENT ME!
|
||||
*
|
||||
* @return the date of the last passed Captcha in millis, 0 if the user never passed captcha.
|
||||
*/
|
||||
long getLastPassedCaptchaDateInMillis();
|
||||
|
||||
/**
|
||||
* Increments the human Restricted Resources Requests Count.
|
||||
* Method to increment the human Restricted Resrouces Requests Count;
|
||||
*/
|
||||
void incrementHumanRestrictedResourcesRequestsCount();
|
||||
|
||||
/**
|
||||
* DOCUMENT ME!
|
||||
*
|
||||
* @return true if the current user has already passed a captcha.
|
||||
*/
|
||||
boolean isHuman();
|
||||
|
||||
/**
|
||||
* set human attribute, should be called after captcha validation.
|
||||
* set human attribute, should called after captcha validation.
|
||||
*/
|
||||
void setHuman();
|
||||
}
|
||||
+3
-3
@@ -21,8 +21,7 @@ import org.springframework.security.context.SecurityContextImpl;
|
||||
/**
|
||||
* Default CaptchaSecurityContext implementation
|
||||
*
|
||||
* @author Marc-Antoine Garrigue
|
||||
* @version $Id$
|
||||
* @author mag
|
||||
*/
|
||||
public class CaptchaSecurityContextImpl extends SecurityContextImpl implements CaptchaSecurityContext {
|
||||
//~ Instance fields ================================================================================================
|
||||
@@ -34,6 +33,7 @@ public class CaptchaSecurityContextImpl extends SecurityContextImpl implements C
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public CaptchaSecurityContextImpl() {
|
||||
super();
|
||||
human = false;
|
||||
lastPassedCaptchaDate = 0;
|
||||
humanRestrictedResourcesRequestsCount = 0;
|
||||
@@ -84,7 +84,7 @@ public class CaptchaSecurityContextImpl extends SecurityContextImpl implements C
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to increment the human Restricted Resources Requests Count;
|
||||
* Method to increment the human Restricted Resrouces Requests Count;
|
||||
*/
|
||||
public void incrementHumanRestrictedResourcesRequestsCount() {
|
||||
humanRestrictedResourcesRequestsCount++;
|
||||
+2
-1
@@ -18,13 +18,14 @@ package org.springframework.security.captcha;
|
||||
/**
|
||||
* Provide a common interface for captcha validation.
|
||||
*
|
||||
* @author Marc-Antoine Garrigue
|
||||
* @author marc antoine Garrigue
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface CaptchaServiceProxy {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* DOCUMENT ME!
|
||||
*
|
||||
* @param id the id token
|
||||
* @param captchaResponse the user response
|
||||
+4
-7
@@ -30,15 +30,12 @@ import javax.servlet.http.HttpSession;
|
||||
|
||||
|
||||
/**
|
||||
* Filter for web integration of the {@link CaptchaServiceProxy}.
|
||||
* <p>
|
||||
* It basically intercept calls containing the specific validation parameter, uses the {@link CaptchaServiceProxy} to
|
||||
* validate the request, and update the {@link CaptchaSecurityContext} if the request passed the validation.
|
||||
* <p>
|
||||
* Filter for web integration of the {@link CaptchaServiceProxy}. <br>
|
||||
* It basically intercept calls containing the specific validation parameter, use the {@link CaptchaServiceProxy} to
|
||||
* validate the request, and update the {@link CaptchaSecurityContext} if the request passed the validation. <br>
|
||||
* This Filter should be placed after the ContextIntegration filter and before the {@link
|
||||
* CaptchaChannelProcessorTemplate} filter in the filter stack in order to update the {@link CaptchaSecurityContext}
|
||||
* before the humanity verification routine occurs.
|
||||
* <p>
|
||||
* before the humanity verification routine occurs. <br>
|
||||
* This filter should only be used in conjunction with the {@link CaptchaSecurityContext}<br>
|
||||
*
|
||||
* @author marc antoine Garrigue
|
||||
+5
-5
@@ -16,9 +16,9 @@
|
||||
package org.springframework.security.captcha;
|
||||
|
||||
/**
|
||||
* Return false if any CaptchaChannelProcessorTemplate mapped urls have been requested more than threshold and
|
||||
* <p>return false if ny CaptchaChannelProcessorTemplate mapped urls has been requested more than thresold and
|
||||
* humanity is false; <br>
|
||||
* Default keyword : REQUIRES_CAPTCHA_ONCE_ABOVE_THRESHOLD_REQUESTS</p>
|
||||
* Default keyword : REQUIRES_CAPTCHA_ONCE_ABOVE_THRESOLD_REQUESTS</p>
|
||||
*
|
||||
* @author Marc-Antoine Garrigue
|
||||
* @version $Id$
|
||||
@@ -26,7 +26,7 @@ package org.springframework.security.captcha;
|
||||
public class TestOnceAfterMaxRequestsCaptchaChannelProcessor extends CaptchaChannelProcessorTemplate {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
public static final String DEFAULT_KEYWORD = "REQUIRES_CAPTCHA_ONCE_ABOVE_THRESHOLD_REQUESTS";
|
||||
public static final String DEFAULT_KEYWORD = "REQUIRES_CAPTCHA_ONCE_ABOVE_THRESOLD_REQUESTS";
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
@@ -38,11 +38,11 @@ public class TestOnceAfterMaxRequestsCaptchaChannelProcessor extends CaptchaChan
|
||||
|
||||
boolean isContextValidConcerningHumanity(CaptchaSecurityContext context) {
|
||||
if (context.isHuman() || (context.getHumanRestrictedResourcesRequestsCount() < getThreshold())) {
|
||||
logger.debug("context is valid concerning humanity or request count < threshold");
|
||||
logger.debug("context is valid concerning humanity or request count < thresold");
|
||||
|
||||
return true;
|
||||
} else {
|
||||
logger.debug("context is not valid concerning humanity and request count > threshold");
|
||||
logger.debug("context is not valid concerning humanity and request count > thresold");
|
||||
|
||||
return false;
|
||||
}
|
||||
+3
-1
@@ -19,7 +19,9 @@ import junit.framework.TestCase;
|
||||
|
||||
|
||||
/**
|
||||
* @author Marc-Antoine Garrigue
|
||||
*
|
||||
* @author $author$
|
||||
* @version $Revision: 2142 $
|
||||
*/
|
||||
public class AlwaysTestAfterMaxRequestsCaptchaChannelProcessorTests extends TestCase {
|
||||
//~ Instance fields ================================================================================================
|
||||
+1
@@ -18,6 +18,7 @@ package org.springframework.security.captcha;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
import org.springframework.security.MockFilterChain;
|
||||
import org.springframework.security.SecurityConfig;
|
||||
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
+3
-1
@@ -16,7 +16,9 @@
|
||||
package org.springframework.security.captcha;
|
||||
|
||||
/**
|
||||
* @author Marc-Antoine Garrigue
|
||||
* DOCUMENT ME!
|
||||
*
|
||||
* @author marc antoine Garrigue
|
||||
* @version $Id$
|
||||
*/
|
||||
public class MockCaptchaServiceProxy implements CaptchaServiceProxy {
|
||||
+2
-1
@@ -21,8 +21,9 @@ import org.springframework.security.captcha.TestOnceAfterMaxRequestsCaptchaChann
|
||||
|
||||
|
||||
/**
|
||||
* DOCUMENT ME!
|
||||
*
|
||||
* @author Marc-Antoine Garrigue
|
||||
* @author $author$
|
||||
* @version $Revision: 2142 $
|
||||
*/
|
||||
public class TestOnceAfterMaxRequestsCaptchaChannelProcessorTests extends TestCase {
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>spring-security-cas</artifactId>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<version>2.0-M2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-cas-client</artifactId>
|
||||
<name>Spring Security - CAS Client Integration</name>
|
||||
<version>2.0-M2</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-mock</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+23
-20
@@ -15,9 +15,6 @@
|
||||
|
||||
package org.springframework.security.providers.cas;
|
||||
|
||||
import org.jasig.cas.client.validation.Assertion;
|
||||
import org.jasig.cas.client.validation.TicketValidationException;
|
||||
import org.jasig.cas.client.validation.TicketValidator;
|
||||
import org.springframework.security.SpringSecurityMessageSource;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthenticationException;
|
||||
@@ -28,7 +25,6 @@ import org.springframework.security.providers.UsernamePasswordAuthenticationToke
|
||||
import org.springframework.security.providers.cas.cache.NullStatelessTicketCache;
|
||||
|
||||
import org.springframework.security.ui.cas.CasProcessingFilter;
|
||||
import org.springframework.security.ui.cas.ServiceProperties;
|
||||
|
||||
import org.springframework.security.userdetails.UserDetails;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
@@ -68,21 +64,21 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
|
||||
|
||||
private UserDetailsService userDetailsService;
|
||||
private UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
|
||||
private CasProxyDecider casProxyDecider;
|
||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
private StatelessTicketCache statelessTicketCache = new NullStatelessTicketCache();
|
||||
private String key;
|
||||
private TicketValidator ticketValidator;
|
||||
private ServiceProperties serviceProperties;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(this.userDetailsService, "A userDetailsService must be set");
|
||||
Assert.notNull(this.ticketValidator, "A ticketValidator must be set");
|
||||
Assert.notNull(this.casProxyDecider, "A casProxyDecider must be set");
|
||||
Assert.notNull(this.statelessTicketCache, "A statelessTicketCache must be set");
|
||||
Assert.hasText(this.key, "A Key is required so CasAuthenticationProvider can identify tokens it previously authenticated");
|
||||
Assert.notNull(this.messages, "A message source must be set");
|
||||
Assert.notNull(this.serviceProperties, "serviceProperties is a required field.");
|
||||
}
|
||||
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
@@ -141,16 +137,19 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
|
||||
}
|
||||
|
||||
private CasAuthenticationToken authenticateNow(Authentication authentication) throws AuthenticationException {
|
||||
try {
|
||||
final Assertion assertion = this.ticketValidator.validate(authentication.getCredentials().toString(), serviceProperties.getService());
|
||||
final UserDetails userDetails = userDetailsService.loadUserByUsername(assertion.getPrincipal().getName());
|
||||
userDetailsChecker.check(userDetails);
|
||||
return new CasAuthenticationToken(this.key, userDetails, authentication.getCredentials(),
|
||||
userDetails.getAuthorities(), userDetails, assertion);
|
||||
} catch (final TicketValidationException e) {
|
||||
// TODO get error message
|
||||
throw new BadCredentialsException("", e);
|
||||
}
|
||||
// Validate
|
||||
TicketResponse response = ticketValidator.confirmTicketValid(authentication.getCredentials().toString());
|
||||
|
||||
// Check proxy list is trusted
|
||||
this.casProxyDecider.confirmProxyListTrusted(response.getProxyList());
|
||||
|
||||
// Lookup user details
|
||||
UserDetails userDetails = userDetailsService.loadUserByUsername(response.getUser());
|
||||
userDetailsChecker.check(userDetails);
|
||||
|
||||
// Construct CasAuthenticationToken
|
||||
return new CasAuthenticationToken(this.key, userDetails, authentication.getCredentials(),
|
||||
userDetails.getAuthorities(), userDetails, response.getProxyList(), response.getProxyGrantingTicketIou());
|
||||
}
|
||||
|
||||
protected UserDetailsService getUserDetailsService() {
|
||||
@@ -160,9 +159,13 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
|
||||
public void setUserDetailsService(UserDetailsService userDetailsService) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
public void setServiceProperties(final ServiceProperties serviceProperties) {
|
||||
this.serviceProperties = serviceProperties;
|
||||
|
||||
public CasProxyDecider getCasProxyDecider() {
|
||||
return casProxyDecider;
|
||||
}
|
||||
|
||||
public void setCasProxyDecider(CasProxyDecider casProxyDecider) {
|
||||
this.casProxyDecider = casProxyDecider;
|
||||
}
|
||||
|
||||
protected String getKey() {
|
||||
@@ -193,7 +196,7 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
|
||||
this.ticketValidator = ticketValidator;
|
||||
}
|
||||
|
||||
public boolean supports(final Class authentication) {
|
||||
public boolean supports(Class authentication) {
|
||||
if (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)) {
|
||||
return true;
|
||||
} else if (CasAuthenticationToken.class.isAssignableFrom(authentication)) {
|
||||
+40
-15
@@ -15,7 +15,6 @@
|
||||
|
||||
package org.springframework.security.providers.cas;
|
||||
|
||||
import org.jasig.cas.client.validation.Assertion;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
|
||||
import org.springframework.security.providers.AbstractAuthenticationToken;
|
||||
@@ -24,22 +23,25 @@ import org.springframework.security.userdetails.UserDetails;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a successful CAS <code>Authentication</code>.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Scott Battaglia
|
||||
* @version $Id$
|
||||
*/
|
||||
public class CasAuthenticationToken extends AbstractAuthenticationToken implements Serializable {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final List proxyList;
|
||||
private final Object credentials;
|
||||
private final Object principal;
|
||||
private final String proxyGrantingTicketIou;
|
||||
private final UserDetails userDetails;
|
||||
private final int keyHash;
|
||||
private final Assertion assertion;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
@@ -55,17 +57,22 @@ public class CasAuthenticationToken extends AbstractAuthenticationToken implemen
|
||||
* org.springframework.security.userdetails.UserDetailsService}) (cannot be <code>null</code>)
|
||||
* @param userDetails the user details (from the {@link
|
||||
* org.springframework.security.userdetails.UserDetailsService}) (cannot be <code>null</code>)
|
||||
* @param assertion the assertion returned from the CAS servers. It contains the principal and how to obtain a
|
||||
* proxy ticket for the user.
|
||||
* @param proxyList the list of proxies from CAS (cannot be
|
||||
* <code>null</code>)
|
||||
* @param proxyGrantingTicketIou the PGT-IOU ID from CAS (cannot be
|
||||
* <code>null</code>, but may be an empty <code>String</code> if no
|
||||
* PGT-IOU ID was provided)
|
||||
*
|
||||
* @throws IllegalArgumentException if a <code>null</code> was passed
|
||||
*/
|
||||
public CasAuthenticationToken(final String key, final Object principal, final Object credentials,
|
||||
final GrantedAuthority[] authorities, final UserDetails userDetails, final Assertion assertion) {
|
||||
final GrantedAuthority[] authorities, final UserDetails userDetails, final List proxyList,
|
||||
final String proxyGrantingTicketIou) {
|
||||
super(authorities);
|
||||
|
||||
if ((key == null) || ("".equals(key)) || (principal == null) || "".equals(principal) || (credentials == null)
|
||||
|| "".equals(credentials) || (authorities == null) || (userDetails == null) || (assertion == null)) {
|
||||
|| "".equals(credentials) || (authorities == null) || (userDetails == null) || (proxyList == null)
|
||||
|| (proxyGrantingTicketIou == null)) {
|
||||
throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
|
||||
}
|
||||
|
||||
@@ -73,7 +80,8 @@ public class CasAuthenticationToken extends AbstractAuthenticationToken implemen
|
||||
this.principal = principal;
|
||||
this.credentials = credentials;
|
||||
this.userDetails = userDetails;
|
||||
this.assertion = assertion;
|
||||
this.proxyList = proxyList;
|
||||
this.proxyGrantingTicketIou = proxyGrantingTicketIou;
|
||||
setAuthenticated(true);
|
||||
}
|
||||
|
||||
@@ -86,9 +94,15 @@ public class CasAuthenticationToken extends AbstractAuthenticationToken implemen
|
||||
|
||||
if (obj instanceof CasAuthenticationToken) {
|
||||
CasAuthenticationToken test = (CasAuthenticationToken) obj;
|
||||
|
||||
if (!this.assertion.equals(test.getAssertion())) {
|
||||
return false;
|
||||
|
||||
// proxyGrantingTicketIou is never null due to constructor
|
||||
if (!this.getProxyGrantingTicketIou().equals(test.getProxyGrantingTicketIou())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// proxyList is never null due to constructor
|
||||
if (!this.getProxyList().equals(test.getProxyList())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.getKeyHash() != test.getKeyHash()) {
|
||||
@@ -113,8 +127,18 @@ public class CasAuthenticationToken extends AbstractAuthenticationToken implemen
|
||||
return this.principal;
|
||||
}
|
||||
|
||||
public Assertion getAssertion() {
|
||||
return this.assertion;
|
||||
/**
|
||||
* Obtains the proxy granting ticket IOU.
|
||||
*
|
||||
* @return the PGT IOU-ID or an empty <code>String</code> if no proxy callback was requested when validating the
|
||||
* service ticket
|
||||
*/
|
||||
public String getProxyGrantingTicketIou() {
|
||||
return proxyGrantingTicketIou;
|
||||
}
|
||||
|
||||
public List getProxyList() {
|
||||
return proxyList;
|
||||
}
|
||||
|
||||
public UserDetails getUserDetails() {
|
||||
@@ -124,8 +148,9 @@ public class CasAuthenticationToken extends AbstractAuthenticationToken implemen
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(super.toString());
|
||||
sb.append(" Assertion: ").append(this.assertion);
|
||||
sb.append(" Credentials (Service/Proxy Ticket): ").append(this.credentials);
|
||||
sb.append("; Credentials (Service/Proxy Ticket): ").append(this.credentials);
|
||||
sb.append("; Proxy-Granting Ticket IOU: ").append(this.proxyGrantingTicketIou);
|
||||
sb.append("; Proxy List: ").append(this.proxyList);
|
||||
|
||||
return (sb.toString());
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/* 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.springframework.security.providers.cas;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Decides whether a proxy list presented via CAS is trusted or not.
|
||||
*
|
||||
* <p>
|
||||
* CAS 1.0 allowed services to receive a service ticket and then validate it.
|
||||
* CAS 2.0 allows services to receive a service ticket and then validate it
|
||||
* with a proxy callback URL. The callback will enable the CAS server to
|
||||
* authenticate the service. In doing so the service will receive a
|
||||
* proxy-granting ticket and a proxy-granting ticket IOU. The IOU is just an
|
||||
* internal record that a proxy-granting ticket is due to be received via the
|
||||
* callback URL.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* With a proxy-granting ticket, a service can request the CAS server provides
|
||||
* it with a proxy ticket. A proxy ticket is just a service ticket, but the
|
||||
* CAS server internally tracks the list (chain) of services used to build the
|
||||
* proxy ticket. The proxy ticket is then presented to the target service.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If this application is a target service of a proxy ticket, the
|
||||
* <code>CasProxyDecider</code> resolves whether or not the proxy list is
|
||||
* trusted. Applications should only trust services they allow to impersonate
|
||||
* an end user.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If this application is a service that should never accept proxy-granting
|
||||
* tickets, the implementation should reject tickets that present a proxy list
|
||||
* with any members. If the list has no members, it indicates the CAS server
|
||||
* directly authenticated the user (ie there are no services which proxied the
|
||||
* user authentication).
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface CasProxyDecider {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Decides whether the proxy list is trusted.
|
||||
* <p>Must throw any <code>ProxyUntrustedException</code> if the
|
||||
* proxy list is untrusted.</p>
|
||||
*
|
||||
* @param proxyList the list of proxies to be checked.
|
||||
*
|
||||
* @throws ProxyUntrustedException DOCUMENT ME!
|
||||
*/
|
||||
void confirmProxyListTrusted(List proxyList)
|
||||
throws ProxyUntrustedException;
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/* 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.springframework.security.providers.cas;
|
||||
|
||||
import org.springframework.security.AuthenticationException;
|
||||
|
||||
|
||||
/**
|
||||
* Thrown if a CAS proxy ticket is presented from an untrusted proxy.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class ProxyUntrustedException extends AuthenticationException {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructs a <code>ProxyUntrustedException</code> with the specified
|
||||
* message.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
*/
|
||||
public ProxyUntrustedException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>ProxyUntrustedException</code> with the specified
|
||||
* message and root cause.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
* @param t root cause
|
||||
*/
|
||||
public ProxyUntrustedException(String msg, Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/* 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.springframework.security.providers.cas;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a CAS service ticket in native CAS form.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class TicketResponse {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private List proxyList;
|
||||
private String proxyGrantingTicketIou;
|
||||
private String user;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* <P>
|
||||
* If <code>null</code> is passed into the <code>proxyList</code> or
|
||||
* <code>proxyGrantingTicketIou</code>, suitable defaults are established.
|
||||
* However, <code>null</code> cannot be passed for the <code>user</code>
|
||||
* argument.
|
||||
* </p>
|
||||
*
|
||||
* @param user the user as indicated by CAS (cannot be <code>null</code> or
|
||||
* an empty <code>String</code>)
|
||||
* @param proxyList as provided by CAS (may be <code>null</code>)
|
||||
* @param proxyGrantingTicketIou as provided by CAS (may be
|
||||
* <code>null</code>)
|
||||
*
|
||||
* @throws IllegalArgumentException DOCUMENT ME!
|
||||
*/
|
||||
public TicketResponse(String user, List proxyList, String proxyGrantingTicketIou) {
|
||||
if (proxyList == null) {
|
||||
proxyList = new Vector();
|
||||
}
|
||||
|
||||
if (proxyGrantingTicketIou == null) {
|
||||
proxyGrantingTicketIou = "";
|
||||
}
|
||||
|
||||
if ((user == null) || "".equals(user)) {
|
||||
throw new IllegalArgumentException("Cannot pass null or empty String for User");
|
||||
}
|
||||
|
||||
this.user = user;
|
||||
this.proxyList = proxyList;
|
||||
this.proxyGrantingTicketIou = proxyGrantingTicketIou;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public String getProxyGrantingTicketIou() {
|
||||
return proxyGrantingTicketIou;
|
||||
}
|
||||
|
||||
public List getProxyList() {
|
||||
return proxyList;
|
||||
}
|
||||
|
||||
public String getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(super.toString());
|
||||
sb.append(": User: " + this.user);
|
||||
sb.append("; Proxy-Granting Ticket IOU: " + this.proxyGrantingTicketIou);
|
||||
sb.append("; Proxy List: " + this.proxyList.toString());
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/* 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.springframework.security.providers.cas;
|
||||
|
||||
import org.springframework.security.AuthenticationException;
|
||||
|
||||
|
||||
/**
|
||||
* Validates a CAS service ticket.
|
||||
*
|
||||
* <p>
|
||||
* Implementations must accept CAS proxy tickets, in addition to CAS service
|
||||
* tickets. If proxy tickets should be rejected, this is resolved by a {@link
|
||||
* CasProxyDecider} implementation (not by the <code>TicketValidator</code>).
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Implementations may request a proxy granting ticket if wish, although this
|
||||
* behaviour is not mandatory.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface TicketValidator {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Returns information about the ticket, if it is valid for this service.<P>Must throw an
|
||||
* <code>AuthenticationException</code> if the ticket is not valid for this service.</p>
|
||||
*
|
||||
* @param serviceTicket DOCUMENT ME!
|
||||
*
|
||||
* @return details of the CAS service ticket
|
||||
*
|
||||
* @throws AuthenticationException DOCUMENT ME!
|
||||
*/
|
||||
TicketResponse confirmTicketValid(String serviceTicket)
|
||||
throws AuthenticationException;
|
||||
}
|
||||
+51
@@ -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.springframework.security.providers.cas.proxy;
|
||||
|
||||
import org.springframework.security.providers.cas.CasProxyDecider;
|
||||
import org.springframework.security.providers.cas.ProxyUntrustedException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Accepts a proxied request from any other service.<P>Also accepts the request if there was no proxy (ie the user
|
||||
* directly authenticated against this service).</p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class AcceptAnyCasProxy implements CasProxyDecider {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AcceptAnyCasProxy.class);
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void confirmProxyListTrusted(List proxyList)
|
||||
throws ProxyUntrustedException {
|
||||
Assert.notNull(proxyList, "proxyList cannot be null");
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Always accepting proxy list: " + proxyList.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/* 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.springframework.security.providers.cas.proxy;
|
||||
|
||||
import org.springframework.security.SpringSecurityMessageSource;
|
||||
|
||||
import org.springframework.security.providers.cas.CasProxyDecider;
|
||||
import org.springframework.security.providers.cas.ProxyUntrustedException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Accepts proxied requests if the closest proxy is named in the <code>validProxies</code> list.<P>Also accepts the
|
||||
* request if there was no proxy (ie the user directly authenticated against this service).</p>
|
||||
*/
|
||||
public class NamedCasProxyDecider implements CasProxyDecider, InitializingBean, MessageSourceAware {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(NamedCasProxyDecider.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private List validProxies;
|
||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(this.validProxies, "A validProxies list must be set");
|
||||
Assert.notNull(this.messages, "A message source must be set");
|
||||
}
|
||||
|
||||
public void confirmProxyListTrusted(List proxyList)
|
||||
throws ProxyUntrustedException {
|
||||
Assert.notNull(proxyList, "proxyList cannot be null");
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Proxy list: " + proxyList.toString());
|
||||
}
|
||||
|
||||
if (proxyList.size() == 0) {
|
||||
// A Service Ticket (not a Proxy Ticket)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validProxies.contains(proxyList.get(0))) {
|
||||
throw new ProxyUntrustedException(messages.getMessage("NamedCasProxyDecider.untrusted",
|
||||
new Object[] {proxyList.get(0)}, "Nearest proxy {0} is untrusted"));
|
||||
}
|
||||
}
|
||||
|
||||
public List getValidProxies() {
|
||||
return validProxies;
|
||||
}
|
||||
|
||||
public void setMessageSource(MessageSource messageSource) {
|
||||
this.messages = new MessageSourceAccessor(messageSource);
|
||||
}
|
||||
|
||||
public void setValidProxies(List validProxies) {
|
||||
this.validProxies = validProxies;
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/* 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.springframework.security.providers.cas.proxy;
|
||||
|
||||
import org.springframework.security.SpringSecurityMessageSource;
|
||||
|
||||
import org.springframework.security.providers.cas.CasProxyDecider;
|
||||
import org.springframework.security.providers.cas.ProxyUntrustedException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Accepts no proxied requests.<P>This class should be used if only service tickets wish to be accepted (ie no
|
||||
* proxy tickets at all).</p>
|
||||
*/
|
||||
public class RejectProxyTickets implements CasProxyDecider, MessageSourceAware, InitializingBean {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(RejectProxyTickets.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(this.messages, "A message source must be set");
|
||||
}
|
||||
|
||||
public void confirmProxyListTrusted(List proxyList)
|
||||
throws ProxyUntrustedException {
|
||||
Assert.notNull(proxyList, "proxyList cannot be null");
|
||||
|
||||
if (proxyList.size() == 0) {
|
||||
// A Service Ticket (not a Proxy Ticket)
|
||||
return;
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Proxies are unacceptable; proxy list provided: " + proxyList.toString());
|
||||
}
|
||||
|
||||
throw new ProxyUntrustedException(
|
||||
messages.getMessage("RejectProxyTickets.reject", "Proxy tickets are rejected"));
|
||||
}
|
||||
|
||||
public void setMessageSource(MessageSource messageSource) {
|
||||
this.messages = new MessageSourceAccessor(messageSource);
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<body>
|
||||
Implementations that decide whether proxy lists of
|
||||
CAS authentications are trusted.
|
||||
</body>
|
||||
</html>
|
||||
+114
@@ -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.springframework.security.providers.cas.ticketvalidator;
|
||||
|
||||
import org.springframework.security.providers.cas.TicketValidator;
|
||||
import org.springframework.security.ui.cas.ServiceProperties;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
||||
/**
|
||||
* Convenience abstract base for <code>TicketValidator</code>s.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class AbstractTicketValidator implements TicketValidator, InitializingBean {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AbstractTicketValidator.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private ServiceProperties serviceProperties;
|
||||
private String casValidate;
|
||||
private String trustStore;
|
||||
private String trustPassword;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.hasLength(casValidate, "A casValidate URL must be set");
|
||||
Assert.notNull(serviceProperties, "serviceProperties must be specified");
|
||||
|
||||
if (StringUtils.hasLength(trustStore)) {
|
||||
logger.info("Setting system property 'javax.net.ssl.trustStore' to value [" + trustStore + "]");
|
||||
|
||||
if (! (new File(trustStore)).exists()) {
|
||||
throw new IllegalArgumentException("Parameter 'trustStore' file does not exist at " + trustStore);
|
||||
}
|
||||
|
||||
System.setProperty("javax.net.ssl.trustStore", trustStore);
|
||||
}
|
||||
|
||||
if (StringUtils.hasLength(trustPassword)) {
|
||||
System.setProperty("javax.net.ssl.trustStorePassword", trustPassword);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mandatory URL to CAS' proxy ticket valiation service.<P>This is usually something like
|
||||
* <code>https://www.mycompany.com/cas/proxyValidate</code>.</p>
|
||||
*
|
||||
* @return the CAS proxy ticket validation URL
|
||||
*/
|
||||
public String getCasValidate() {
|
||||
return casValidate;
|
||||
}
|
||||
|
||||
public ServiceProperties getServiceProperties() {
|
||||
return serviceProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional property which will be used to set the system property <code>javax.net.ssl.trustStore</code>.
|
||||
*
|
||||
* @return the <code>javax.net.ssl.trustStore</code> that will be set during bean initialization, or
|
||||
* <code>null</code> to leave the system property unchanged
|
||||
*/
|
||||
public String getTrustStore() {
|
||||
return trustStore;
|
||||
}
|
||||
|
||||
public void setCasValidate(String casValidate) {
|
||||
this.casValidate = casValidate;
|
||||
}
|
||||
|
||||
public void setServiceProperties(ServiceProperties serviceProperties) {
|
||||
this.serviceProperties = serviceProperties;
|
||||
}
|
||||
|
||||
public void setTrustStore(String trustStore) {
|
||||
this.trustStore = trustStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional property which causes the system property <tt>javax.net.ssl.trustStorePassword</tt> to be set.
|
||||
*
|
||||
* @param trustPassword
|
||||
*/
|
||||
public void setTrustPassword(String trustPassword) {
|
||||
this.trustPassword = trustPassword;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user