Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 99e3a5d715 | |||
| ea414140e2 | |||
| fd04adf2f3 |
+2
-28
@@ -3,14 +3,13 @@
|
||||
<parent>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<version>2.0.2</version>
|
||||
<version>2.0.0-RC1</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.2</version>
|
||||
<packaging>bundle</packaging>
|
||||
<version>2.0.0-RC1</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -45,29 +44,4 @@
|
||||
<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
-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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+114
-131
@@ -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,32 @@ 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 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;
|
||||
|
||||
|
||||
/**
|
||||
* Performs lookups in a manner that is compatible with ANSI SQL.<p>NB: This implementation does attempt to provide
|
||||
@@ -73,7 +79,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructor accepting mandatory arguments
|
||||
*
|
||||
* @param dataSource to access the database
|
||||
@@ -97,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);
|
||||
@@ -196,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,
|
||||
@@ -229,20 +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"));
|
||||
}
|
||||
|
||||
Permission permission = BasePermission.buildFromMask(rs.getInt("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);
|
||||
@@ -283,10 +278,10 @@ 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 {
|
||||
@@ -304,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();
|
||||
@@ -338,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 {
|
||||
@@ -353,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");
|
||||
|
||||
@@ -385,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() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,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
|
||||
|
||||
@@ -473,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"
|
||||
@@ -494,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 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 = ?)";
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
+52
-76
@@ -60,24 +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 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 (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 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 ===================================================================================================
|
||||
@@ -235,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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,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);
|
||||
@@ -332,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
|
||||
@@ -379,17 +368,4 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
throw new NotFoundException("Unable to locate ACL to update");
|
||||
}
|
||||
}
|
||||
|
||||
public void setIdentityQuery(String identityQuery) {
|
||||
Assert.hasText(identityQuery, "New identity query is required");
|
||||
this.identityQuery = 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();
|
||||
}
|
||||
|
||||
+2
-3
@@ -17,7 +17,6 @@ package org.springframework.security.acls.objectidentity;
|
||||
import org.springframework.security.acls.IdentityUnavailableException;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -76,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;
|
||||
|
||||
@@ -144,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 ========================================================================================================
|
||||
|
||||
/**
|
||||
|
||||
+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);
|
||||
|
||||
-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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-6
@@ -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;
|
||||
@@ -249,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);"
|
||||
@@ -288,7 +286,7 @@ 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 {
|
||||
|
||||
+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,7 +20,6 @@ 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;
|
||||
@@ -108,10 +107,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 +143,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 +185,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 +212,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 +225,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 +251,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 +315,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")});
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.2</version>
|
||||
<version>2.0.0-RC1</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-catalina</artifactId>
|
||||
<name>Spring Security - Catalina adapter</name>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.2</version>
|
||||
<version>2.0.0-RC1</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 {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.2</version>
|
||||
<version>2.0.0-RC1</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-jetty</artifactId>
|
||||
<name>Spring Security - Jetty adapter</name>
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>2.0.2</version>
|
||||
<version>2.0.0-RC1</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<name>Spring Security - Adapters</name>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.2</version>
|
||||
<version>2.0.0-RC1</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>
|
||||
|
||||
+2
-27
@@ -3,11 +3,11 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>2.0.2</version>
|
||||
<version>2.0.0-RC1</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-cas-client</artifactId>
|
||||
<name>Spring Security - CAS support</name>
|
||||
<packaging>bundle</packaging>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -39,29 +39,4 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring.osgi.export>
|
||||
org.springframework.security.*;version=${pom.version.osgi}
|
||||
</spring.osgi.export>
|
||||
|
||||
<spring.osgi.import>
|
||||
org.springframework.security.*;version="[${pom.version.osgi},${pom.version.osgi}]",
|
||||
org.springframework.beans.*;version="${spring.version.osgi}",
|
||||
org.springframework.context.*;version="${spring.version.osgi}",
|
||||
org.springframework.dao.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.util.*;version="${spring.version.osgi}",
|
||||
javax.servlet.*;version="[2.4.0, 3.0.0)";resolution:=optional,
|
||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
|
||||
org.jasig.cas.client.*;version="[3.1.1, 4.0.0)"
|
||||
</spring.osgi.import>
|
||||
|
||||
<spring.osgi.private.pkg>
|
||||
!org.springframework.security.*
|
||||
</spring.osgi.private.pkg>
|
||||
|
||||
<spring.osgi.symbolic.name>org.springframework.security.cas</spring.osgi.symbolic.name>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
+6
-8
@@ -30,14 +30,12 @@ import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Used by the <code>ExceptionTranslationFilter</code> to commence authentication via the JA-SIG Central
|
||||
* Authentication Service (CAS).
|
||||
* <p>
|
||||
* The user's browser will be redirected to the JA-SIG CAS enterprise-wide login page.
|
||||
* This page is specified by the <code>loginUrl</code> property. Once login is complete, the CAS login page will
|
||||
* Used by the <code>SecurityEnforcementFilter</code> to commence authentication via the JA-SIG Central
|
||||
* Authentication Service (CAS).<P>The user's browser will be redirected to the JA-SIG CAS enterprise-wide login
|
||||
* page. This page is specified by the <code>loginUrl</code> property. Once login is complete, the CAS login page will
|
||||
* redirect to the page indicated by the <code>service</code> property. The <code>service</code> is a HTTP URL
|
||||
* belonging to the current application. The <code>service</code> URL is monitored by the {@link CasProcessingFilter},
|
||||
* which will validate the CAS login was successful.
|
||||
* which will validate the CAS login was successful.</p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Scott Battaglia
|
||||
@@ -67,8 +65,8 @@ public class CasProcessingFilterEntryPoint implements AuthenticationEntryPoint,
|
||||
}
|
||||
|
||||
public void commence(final ServletRequest servletRequest, final ServletResponse servletResponse,
|
||||
final AuthenticationException authenticationException) throws IOException, ServletException {
|
||||
|
||||
final AuthenticationException authenticationException)
|
||||
throws IOException, ServletException {
|
||||
final HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
final String urlEncodedService = CommonUtils.constructServiceUrl(null, response, this.serviceProperties.getService(), null, "ticket", this.encodeServiceUrlWithSessionId);
|
||||
final String redirectUrl = CommonUtils.constructRedirectUrl(this.loginUrl, "service", urlEncodedService, this.serviceProperties.isSendRenew(), false);
|
||||
|
||||
@@ -21,10 +21,9 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Stores properties related to this CAS service.
|
||||
* <p>
|
||||
* Each web application capable of processing CAS tickets is known as a service.
|
||||
* <p>Each web application capable of processing CAS tickets is known as a service.
|
||||
* This class stores the properties that are relevant to the local CAS service, being the application
|
||||
* that is being secured by Spring Security.
|
||||
* that is being secured by Spring Security.</p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
@@ -43,8 +42,7 @@ public class ServiceProperties implements InitializingBean {
|
||||
|
||||
/**
|
||||
* Represents the service the user is authenticating to.
|
||||
* <p>
|
||||
* This service is the callback URL belonging to the local Spring Security System for Spring secured application.
|
||||
* <p>This service is the callback URL belonging to the local Spring Security System for Spring secured application.
|
||||
* For example,
|
||||
* <pre>
|
||||
* https://www.mycompany.com/application/j_spring_cas_security_check
|
||||
@@ -58,12 +56,10 @@ public class ServiceProperties implements InitializingBean {
|
||||
|
||||
/**
|
||||
* Indicates whether the <code>renew</code> parameter should be sent to the CAS login URL and CAS
|
||||
* validation URL.
|
||||
* <p>
|
||||
* If <code>true</code>, it will force CAS to authenticate the user again (even if the
|
||||
* validation URL.<p>If <code>true</code>, it will force CAS to authenticate the user again (even if the
|
||||
* user has previously authenticated). During ticket validation it will require the ticket was generated as a
|
||||
* consequence of an explicit login. High security applications would probably set this to <code>true</code>.
|
||||
* Defaults to <code>false</code>, providing automated single sign on.
|
||||
* Defaults to <code>false</code>, providing automated single sign on.</p>
|
||||
*
|
||||
* @return whether to send the <code>renew</code> parameter to CAS
|
||||
*/
|
||||
|
||||
+22
-31
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>2.0.2</version>
|
||||
<version>2.0.0-RC1</version>
|
||||
</parent>
|
||||
<packaging>bundle</packaging>
|
||||
<artifactId>spring-security-core-tiger</artifactId>
|
||||
@@ -16,14 +16,7 @@
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>tests</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<groupId>aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
@@ -68,6 +61,26 @@
|
||||
<target>1.5</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<version>${felix.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>org.springframework.security.core-tiger</Bundle-SymbolicName>
|
||||
<Export-Package>org.springframework.security.*;version=${pom.version}</Export-Package>
|
||||
<Private-Package>!org.springframework.security.*</Private-Package>
|
||||
<Implementation-Title>${pom.name}</Implementation-Title>
|
||||
<Implementation-Version>${pom.version}</Implementation-Version>
|
||||
<Import-Package>
|
||||
org.springframework*;resolution:=optional;version="[2.0,2.5]",
|
||||
*;resolution:=optional
|
||||
</Import-Package>
|
||||
</instructions>
|
||||
<excludeDependencies>true</excludeDependencies>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<reporting>
|
||||
@@ -81,26 +94,4 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
|
||||
<properties>
|
||||
<spring.osgi.export>
|
||||
org.springframework.security.*;version=${pom.version}
|
||||
</spring.osgi.export>
|
||||
|
||||
<spring.osgi.import>
|
||||
javax.annotation.*;version="[1.0.0, 2.0.0)",
|
||||
org.springframework.security.*;version="[${pom.version.osgi},${pom.version.osgi}]",
|
||||
org.springframework.core.*;version="${spring.version.osgi}"
|
||||
</spring.osgi.import>
|
||||
|
||||
<spring.osgi.private.pkg>
|
||||
!org.springframework.security.*
|
||||
</spring.osgi.private.pkg>
|
||||
|
||||
<spring.osgi.include.res>
|
||||
src/main/resources
|
||||
</spring.osgi.include.res>
|
||||
|
||||
<spring.osgi.symbolic.name>org.springframework.security.annotation</spring.osgi.symbolic.name>
|
||||
</properties>
|
||||
</project>
|
||||
|
||||
+2
-36
@@ -1,12 +1,8 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.context.support.AbstractXmlApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.AuthenticationCredentialsNotFoundException;
|
||||
@@ -15,17 +11,17 @@ import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.annotation.BusinessService;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
private ClassPathXmlApplicationContext appContext;
|
||||
|
||||
private BusinessService target;
|
||||
|
||||
@Before
|
||||
public void loadContext() {
|
||||
appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/global-method-security.xml");
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
@@ -41,13 +37,11 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
|
||||
@Test(expected=AuthenticationCredentialsNotFoundException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
|
||||
loadContext();
|
||||
target.someUserMethod1();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
|
||||
loadContext();
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_USER")});
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
@@ -57,38 +51,10 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
|
||||
loadContext();
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_SOMEOTHERROLE")});
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someAdminMethod();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntInterfereWithBeanPostProcessing() {
|
||||
setContext(
|
||||
"<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>" +
|
||||
"<global-method-security />" +
|
||||
// "<http auto-config='true'/>" +
|
||||
"<authentication-provider user-service-ref='myUserService'/>" +
|
||||
"<b:bean id='beanPostProcessor' class='org.springframework.security.config.MockUserServiceBeanPostProcessor'/>"
|
||||
);
|
||||
|
||||
PostProcessedMockUserDetailsService service = (PostProcessedMockUserDetailsService)appContext.getBean("myUserService");
|
||||
|
||||
assertEquals("Hello from the post processor!", service.getPostProcessorWasHere());
|
||||
}
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void duplicateElementCausesError() {
|
||||
setContext(
|
||||
"<global-method-security />" +
|
||||
"<global-method-security />"
|
||||
);
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
# Logging
|
||||
#
|
||||
# $Id: log4j.properties 2385 2007-12-20 20:53:26Z luke_t $
|
||||
|
||||
log4j.rootCategory=DEBUG, stdout
|
||||
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d %p %c - %m%n
|
||||
|
||||
log4j.category.org.springframework.security=DEBUG
|
||||
|
||||
+30
-54
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>2.0.2</version>
|
||||
<version>2.0.0-RC1</version>
|
||||
</parent>
|
||||
<packaging>bundle</packaging>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
@@ -48,7 +48,7 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<groupId>aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
@@ -141,58 +141,34 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring.osgi.export>
|
||||
org.springframework.security.*;version=${pom.version}
|
||||
</spring.osgi.export>
|
||||
|
||||
<spring.osgi.import>
|
||||
!com.ibm.websphere.security,
|
||||
javax.servlet.*;version="[2.4.0, 3.0.0)";resolution:=optional,
|
||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||
org.aopalliance.*;version="[1.0.0, 2.0.0)",
|
||||
org.apache.commons.codec.*;version="[1.3.0, 2.0.0)",
|
||||
org.apache.commons.collections.*;version="[3.2.0, 4.0.0)",
|
||||
org.apache.commons.lang.*;version="[2.1.0, 3.0.0)",
|
||||
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
|
||||
org.apache.directory.server.configuration.*;version="[1.0.2, 2.0.0)";resolution:=optional,
|
||||
org.apache.directory.server.core.*;version="[1.0.2, 2.0.0)";resolution:=optional,
|
||||
org.apache.directory.server.protocol.*;version="[1.0.2, 2.0.0)";resolution:=optional,
|
||||
org.aspectj.*;version="[1.5.4, 2.0.0)";resolution:=optional,
|
||||
org.jaxen.*;version="[1.1.1, 2.0.0)";resolution:=optional,
|
||||
org.springframework.aop.*;version="${spring.version.osgi}",
|
||||
org.springframework.beans.*;version="${spring.version.osgi}",
|
||||
org.springframework.context.*;version="${spring.version.osgi}",
|
||||
org.springframework.core.*;version="${spring.version.osgi}",
|
||||
org.springframework.dao.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.jdbc.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.ldap.*;version="[1.2.1.A, 2.0.0)";resolution:=optional,
|
||||
org.springframework.metadata.*;version="${spring.version.osgi}",
|
||||
org.springframework.mock.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.remoting.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.util.*;version="${spring.version.osgi}",
|
||||
org.springframework.web.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
javax.crypto.*,
|
||||
javax.naming.*,
|
||||
javax.rmi.*,
|
||||
javax.security.*,
|
||||
javax.sql.*,
|
||||
javax.xml.parsers.*,
|
||||
org.w3c.dom.*,
|
||||
org.xml.sax.*,
|
||||
*;resolution:=optional
|
||||
</spring.osgi.import>
|
||||
|
||||
<spring.osgi.private.pkg>
|
||||
!org.springframework.security.*
|
||||
</spring.osgi.private.pkg>
|
||||
<!--
|
||||
<spring.osgi.include.res>
|
||||
src/main/resources
|
||||
</spring.osgi.include.res>
|
||||
-->
|
||||
<spring.osgi.symbolic.name>org.springframework.security.core</spring.osgi.symbolic.name>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<version>${felix.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>org.springframework.security.core</Bundle-SymbolicName>
|
||||
<Export-Package>org.springframework.security.*;version=${pom.version}</Export-Package>
|
||||
<Private-Package>!org.springframework.security.*</Private-Package>
|
||||
<Implementation-Title>${pom.name}</Implementation-Title>
|
||||
<Implementation-Version>${pom.version}</Implementation-Version>
|
||||
<Import-Package>
|
||||
org.springframework*;resolution:=optional;version="[2.0,2.5]",
|
||||
*;resolution:=optional
|
||||
</Import-Package>
|
||||
<!--
|
||||
<Embed-Dependency>
|
||||
*;scope=compile|runtime;inline=true
|
||||
</Embed-Dependency>
|
||||
-->
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -158,7 +158,8 @@ public class ConfigAttributeDefinition implements Serializable {
|
||||
* Allows <code>AccessDecisionManager</code>s and other classes to loop through every configuration attribute
|
||||
* associated with a target secure object.
|
||||
*
|
||||
* @return the configuration attributes stored in this instance.
|
||||
* @return all the configuration attributes stored by the instance, or <code>null</code> if an
|
||||
* <code>Iterator</code> is unavailable
|
||||
*/
|
||||
public Collection getConfigAttributes() {
|
||||
return this.configAttributes;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package org.springframework.security;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Indicates that a object stores GrantedAuthority objects.
|
||||
* <p>
|
||||
@@ -12,6 +10,6 @@ import java.io.Serializable;
|
||||
* @author Luke Taylor
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface GrantedAuthoritiesContainer extends Serializable {
|
||||
public interface GrantedAuthoritiesContainer {
|
||||
GrantedAuthority[] getGrantedAuthorities();
|
||||
}
|
||||
|
||||
@@ -24,6 +24,5 @@ import java.io.Serializable;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public interface AclEntry extends Serializable {}
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.springframework.security.Authentication;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public interface AclManager {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@@ -28,7 +28,6 @@ import org.springframework.security.Authentication;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public interface AclProvider {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@@ -35,7 +35,6 @@ import java.util.List;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public class AclProviderManager implements AclManager, InitializingBean {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
@@ -28,7 +28,6 @@ import java.util.Arrays;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public abstract class AbstractBasicAclEntry implements BasicAclEntry {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
@@ -42,7 +42,6 @@ import java.io.Serializable;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public interface AclObjectIdentity extends Serializable {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@@ -28,7 +28,6 @@ package org.springframework.security.acl.basic;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public interface AclObjectIdentityAware {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@@ -33,7 +33,6 @@ package org.springframework.security.acl.basic;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public interface BasicAclDao {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.springframework.security.acl.AclEntry;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public interface BasicAclEntry extends AclEntry {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@@ -29,7 +29,6 @@ package org.springframework.security.acl.basic;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public interface BasicAclEntryCache {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@@ -29,7 +29,6 @@ import org.springframework.dao.DataAccessException;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public interface BasicAclExtendedDao extends BasicAclDao {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@@ -59,7 +59,6 @@ import java.util.Map;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public class BasicAclProvider implements AclProvider, InitializingBean {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
@@ -44,7 +44,6 @@ import org.springframework.security.acl.AclEntry;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public interface EffectiveAclsResolver {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
-1
@@ -44,7 +44,6 @@ import java.util.Vector;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public class GrantedAuthorityEffectiveAclsResolver implements EffectiveAclsResolver {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
-1
@@ -25,7 +25,6 @@ import java.lang.reflect.Method;
|
||||
/**
|
||||
* Simple implementation of {@link AclObjectIdentity}.<P>Uses <code>String</code>s to store the identity of the
|
||||
* domain object instance. Also offers a constructor that uses reflection to build the identity information.</p>
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public class NamedEntityObjectIdentity implements AclObjectIdentity {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public class SimpleAclEntry extends AbstractBasicAclEntry {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
-1
@@ -30,7 +30,6 @@ import java.io.Serializable;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public class BasicAclEntryHolder implements Serializable {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
Vendored
-1
@@ -39,7 +39,6 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public class EhCacheBasedAclEntryCache implements BasicAclEntryCache, InitializingBean {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
-1
@@ -26,7 +26,6 @@ import org.springframework.security.acl.basic.BasicAclEntryCache;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public class NullAclEntryCache implements BasicAclEntryCache {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@@ -48,7 +48,6 @@ import javax.sql.DataSource;
|
||||
* If this does not provide enough flexibility, another strategy would be to subclass this class and override the
|
||||
* {@link MappingSqlQuery} instance used, via the {@link #initMappingSqlQueries()} extension point.
|
||||
* </p>
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public class JdbcDaoImpl extends JdbcDaoSupport implements BasicAclDao {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
-1
@@ -58,7 +58,6 @@ import javax.sql.DataSource;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public class JdbcExtendedDaoImpl extends JdbcDaoImpl implements BasicAclExtendedDao {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
-1
@@ -65,7 +65,6 @@ import java.util.Iterator;
|
||||
* @author Ben Alex
|
||||
* @author Paulo Neves
|
||||
* @version $Id$
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public class BasicAclEntryAfterInvocationCollectionFilteringProvider implements AfterInvocationProvider,
|
||||
InitializingBean {
|
||||
|
||||
-2
@@ -61,8 +61,6 @@ import java.util.Iterator;
|
||||
* <p>If the provided <code>returnObject</code> is <code>null</code>, permission will always be granted and
|
||||
* <code>null</code> will be returned.</p>
|
||||
* <p>All comparisons and prefixes are case sensitive.</p>
|
||||
*
|
||||
* @deprecated Use new spring-security-acl module instead
|
||||
*/
|
||||
public class BasicAclEntryAfterInvocationProvider implements AfterInvocationProvider, InitializingBean,
|
||||
MessageSourceAware {
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ public class SimpleAttributes2GrantedAuthoritiesMapper implements Attributes2Gra
|
||||
return attributePrefix == null ? "" : attributePrefix;
|
||||
}
|
||||
|
||||
public void setAttributePrefix(String string) {
|
||||
public void seAttributePrefix(String string) {
|
||||
attributePrefix = string;
|
||||
}
|
||||
|
||||
|
||||
-2
@@ -21,7 +21,6 @@ import org.springframework.security.ui.FilterChainOrder;
|
||||
import org.springframework.security.ui.SpringSecurityFilter;
|
||||
import org.springframework.security.ui.logout.LogoutHandler;
|
||||
import org.springframework.security.ui.logout.SecurityContextLogoutHandler;
|
||||
import org.springframework.security.util.UrlUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -61,7 +60,6 @@ public class ConcurrentSessionFilter extends SpringSecurityFilter implements Ini
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(sessionRegistry, "SessionRegistry required");
|
||||
Assert.isTrue(UrlUtils.isValidRedirectUrl(expiredUrl), expiredUrl + " isn't a valid redirect URL");
|
||||
}
|
||||
|
||||
public void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||
|
||||
+2
-2
@@ -23,12 +23,12 @@ public abstract class AbstractUserDetailsServiceBeanDefinitionParser implements
|
||||
/** UserDetailsService bean Id. For use in a stateful context (i.e. in AuthenticationProviderBDP) */
|
||||
private String id;
|
||||
|
||||
protected abstract String getBeanClassName(Element element);
|
||||
protected abstract Class getBeanClass(Element element);
|
||||
|
||||
protected abstract void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder);
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(getBeanClassName(element));
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(getBeanClass(element));
|
||||
|
||||
doParse(element, parserContext, builder);
|
||||
|
||||
|
||||
+1
-6
@@ -3,8 +3,6 @@ package org.springframework.security.config;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
@@ -63,7 +61,6 @@ public class AnonymousBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
RootBeanDefinition provider = new RootBeanDefinition(AnonymousAuthenticationProvider.class);
|
||||
provider.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
provider.setSource(source);
|
||||
provider.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
|
||||
@@ -71,9 +68,7 @@ public class AnonymousBeanDefinitionParser implements BeanDefinitionParser {
|
||||
authMgrProviderList.add(provider);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.ANONYMOUS_PROCESSING_FILTER, filter);
|
||||
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.ANONYMOUS_PROCESSING_FILTER));
|
||||
parserContext.registerComponent(new BeanComponentDefinition(filter, BeanIds.ANONYMOUS_PROCESSING_FILTER));
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-16
@@ -3,40 +3,27 @@ package org.springframework.security.config;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Registers an alias name for the default ProviderManager used by the namespace
|
||||
* Just registers an alias name for the default ProviderManager used by the namespace
|
||||
* configuration, allowing users to reference it in their beans and clearly see where the name is
|
||||
* coming from. Also allows the ConcurrentSessionController to be set on the ProviderManager.
|
||||
* coming from.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class AuthenticationManagerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private static final String ATT_SESSION_CONTROLLER_REF = "session-controller-ref";
|
||||
private static final String ATT_ALIAS = "alias";
|
||||
private static final String ATT_ALIAS = "alias";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
|
||||
String alias = element.getAttribute(ATT_ALIAS);
|
||||
|
||||
if (!StringUtils.hasText(alias)) {
|
||||
parserContext.getReaderContext().error(ATT_ALIAS + " is required.", element );
|
||||
}
|
||||
|
||||
String sessionControllerRef = element.getAttribute(ATT_SESSION_CONTROLLER_REF);
|
||||
|
||||
if (StringUtils.hasText(sessionControllerRef)) {
|
||||
ConfigUtils.setSessionControllerOnAuthenticationManager(parserContext,
|
||||
BeanIds.CONCURRENT_SESSION_CONTROLLER, element);
|
||||
authManager.getPropertyValues().addPropertyValue("sessionController",
|
||||
new RuntimeBeanReference(sessionControllerRef));
|
||||
}
|
||||
|
||||
parserContext.getRegistry().registerAlias(BeanIds.AUTHENTICATION_MANAGER, alias);
|
||||
|
||||
|
||||
+4
-9
@@ -6,7 +6,6 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
@@ -29,7 +28,6 @@ class AuthenticationProviderBeanDefinitionParser implements BeanDefinitionParser
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
RootBeanDefinition authProvider = new RootBeanDefinition(DaoAuthenticationProvider.class);
|
||||
authProvider.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
authProvider.setSource(parserContext.extractSource(element));
|
||||
|
||||
Element passwordEncoderElt = DomUtils.getChildElementByTagName(element, Elements.PASSWORD_ENCODER);
|
||||
@@ -50,8 +48,7 @@ class AuthenticationProviderBeanDefinitionParser implements BeanDefinitionParser
|
||||
// We need to register the provider to access it in the post processor to check if it has a cache
|
||||
final String id = parserContext.getReaderContext().generateBeanName(authProvider);
|
||||
parserContext.getRegistry().registerBeanDefinition(id, authProvider);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(authProvider, id));
|
||||
|
||||
|
||||
String ref = element.getAttribute(ATT_USER_DETAILS_REF);
|
||||
|
||||
if (StringUtils.hasText(ref)) {
|
||||
@@ -89,11 +86,9 @@ class AuthenticationProviderBeanDefinitionParser implements BeanDefinitionParser
|
||||
cacheResolverBldr.addConstructorArg(ref);
|
||||
cacheResolverBldr.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
BeanDefinition cacheResolver = cacheResolverBldr.getBeanDefinition();
|
||||
|
||||
String name = parserContext.getReaderContext().generateBeanName(cacheResolver);
|
||||
parserContext.getRegistry().registerBeanDefinition(name , cacheResolver);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(cacheResolver, name));
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(
|
||||
parserContext.getReaderContext().generateBeanName(cacheResolver), cacheResolver);
|
||||
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(new RuntimeBeanReference(id));
|
||||
|
||||
return null;
|
||||
|
||||
+2
-7
@@ -2,7 +2,6 @@ package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
@@ -29,9 +28,7 @@ public class BasicAuthenticationBeanDefinitionParser implements BeanDefinitionPa
|
||||
public BeanDefinition parse(Element elt, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicProcessingFilter.class);
|
||||
RootBeanDefinition entryPoint = new RootBeanDefinition(BasicProcessingFilterEntryPoint.class);
|
||||
entryPoint.setSource(parserContext.extractSource(elt));
|
||||
entryPoint.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
|
||||
entryPoint.getPropertyValues().addPropertyValue("realmName", realmName);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, entryPoint);
|
||||
@@ -41,9 +38,7 @@ public class BasicAuthenticationBeanDefinitionParser implements BeanDefinitionPa
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.BASIC_AUTHENTICATION_FILTER,
|
||||
filterBuilder.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.BASIC_AUTHENTICATION_FILTER));
|
||||
parserContext.registerComponent(new BeanComponentDefinition(filterBuilder.getBeanDefinition(),
|
||||
BeanIds.BASIC_AUTHENTICATION_FILTER));
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,7 @@ public abstract class BeanIds {
|
||||
/** Package protected as end users shouldn't really be using this BFPP directly */
|
||||
static final String INTERCEPT_METHODS_BEAN_FACTORY_POST_PROCESSOR = "_interceptMethodsBeanfactoryPP";
|
||||
static final String CONTEXT_SOURCE_SETTING_POST_PROCESSOR = "_contextSettingPostProcessor";
|
||||
static final String ENTRY_POINT_INJECTION_POST_PROCESSOR = "_entryPointInjectionBeanPostProcessor";
|
||||
static final String USER_DETAILS_SERVICE_INJECTION_POST_PROCESSOR = "_userServiceInjectionPostProcessor";
|
||||
static final String FILTER_CHAIN_POST_PROCESSOR = "_filterChainProxyPostProcessor";
|
||||
static final String FILTER_LIST = "_filterChainList";
|
||||
static final String HTTP_POST_PROCESSOR = "_httpConfigBeanFactoryPostProcessor";
|
||||
|
||||
public static final String JDBC_USER_DETAILS_MANAGER = "_jdbcUserDetailsManager";
|
||||
public static final String USER_DETAILS_SERVICE = "_userDetailsService";
|
||||
@@ -32,7 +29,6 @@ public abstract class BeanIds {
|
||||
public static final String CONCURRENT_SESSION_CONTROLLER = "_concurrentSessionController";
|
||||
public static final String ACCESS_MANAGER = "_accessManager";
|
||||
public static final String AUTHENTICATION_MANAGER = "_authenticationManager";
|
||||
public static final String AFTER_INVOCATION_MANAGER = "_afterInvocationManager";
|
||||
public static final String FORM_LOGIN_FILTER = "_formLoginFilter";
|
||||
public static final String FORM_LOGIN_ENTRY_POINT = "_formLoginEntryPoint";
|
||||
public static final String OPEN_ID_FILTER = "_openIDFilter";
|
||||
@@ -52,7 +48,6 @@ public abstract class BeanIds {
|
||||
public static final String SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER = "_securityContextHolderAwareRequestFilter";
|
||||
public static final String SESSION_FIXATION_PROTECTION_FILTER = "_sessionFixationProtectionFilter";
|
||||
public static final String METHOD_SECURITY_INTERCEPTOR = "_methodSecurityInterceptor";
|
||||
public static final String METHOD_SECURITY_INTERCEPTOR_POST_PROCESSOR = "_methodSecurityInterceptorPostProcessor";
|
||||
public static final String METHOD_DEFINITION_SOURCE_ADVISOR = "_methodDefinitionSourceAdvisor";
|
||||
public static final String PROTECT_POINTCUT_POST_PROCESSOR = "_protectPointcutPostProcessor";
|
||||
public static final String DELEGATING_METHOD_DEFINITION_SOURCE = "_delegatingMethodDefinitionSource";
|
||||
@@ -62,8 +57,6 @@ public abstract class BeanIds {
|
||||
public static final String CONTEXT_SOURCE = "_securityContextSource";
|
||||
public static final String PORT_MAPPER = "_portMapper";
|
||||
public static final String X509_FILTER = "_x509ProcessingFilter";
|
||||
public static final String X509_AUTH_PROVIDER = "_x509AuthenticationProvider";
|
||||
public static final String X509_AUTH_PROVIDER = "_x509AuthenitcationProvider";
|
||||
public static final String PRE_AUTH_ENTRY_POINT = "_preAuthenticatedProcessingFilterEntryPoint";
|
||||
public static final String REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR = "_rememberMeServicesInjectionBeanPostProcessor";
|
||||
|
||||
}
|
||||
|
||||
+20
-44
@@ -2,8 +2,6 @@ package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
@@ -29,53 +27,28 @@ public class ConcurrentSessionsBeanDefinitionParser implements BeanDefinitionPar
|
||||
static final String ATT_EXPIRY_URL = "expired-url";
|
||||
static final String ATT_MAX_SESSIONS = "max-sessions";
|
||||
static final String ATT_EXCEPTION_IF_MAX_EXCEEDED = "exception-if-maximum-exceeded";
|
||||
static final String ATT_SESSION_REGISTRY_ALIAS = "session-registry-alias";
|
||||
static final String ATT_SESSION_REGISTRY_REF = "session-registry-ref";
|
||||
static final String ATT_SESSION_REGISTRY_ALIAS = "session-registry-alias";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
CompositeComponentDefinition compositeDef =
|
||||
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
|
||||
parserContext.pushContainingComponent(compositeDef);
|
||||
|
||||
BeanDefinitionRegistry beanRegistry = parserContext.getRegistry();
|
||||
|
||||
String sessionRegistryId = element.getAttribute(ATT_SESSION_REGISTRY_REF);
|
||||
|
||||
if (!StringUtils.hasText(sessionRegistryId)) {
|
||||
RootBeanDefinition sessionRegistry = new RootBeanDefinition(SessionRegistryImpl.class);
|
||||
beanRegistry.registerBeanDefinition(BeanIds.SESSION_REGISTRY, sessionRegistry);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(sessionRegistry, BeanIds.SESSION_REGISTRY));
|
||||
sessionRegistryId = BeanIds.SESSION_REGISTRY;
|
||||
} else {
|
||||
// Register the default ID as an alias so that things like session fixation filter can access it
|
||||
beanRegistry.registerAlias(sessionRegistryId, BeanIds.SESSION_REGISTRY);
|
||||
}
|
||||
|
||||
String registryAlias = element.getAttribute(ATT_SESSION_REGISTRY_ALIAS);
|
||||
if (StringUtils.hasText(registryAlias)) {
|
||||
beanRegistry.registerAlias(sessionRegistryId, registryAlias);
|
||||
}
|
||||
BeanDefinitionRegistry beanRegistry = parserContext.getRegistry();
|
||||
|
||||
RootBeanDefinition sessionRegistry = new RootBeanDefinition(SessionRegistryImpl.class);
|
||||
BeanDefinitionBuilder filterBuilder =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(ConcurrentSessionFilter.class);
|
||||
filterBuilder.addPropertyValue("sessionRegistry", new RuntimeBeanReference(sessionRegistryId));
|
||||
BeanDefinitionBuilder controllerBuilder
|
||||
= BeanDefinitionBuilder.rootBeanDefinition(ConcurrentSessionControllerImpl.class);
|
||||
controllerBuilder.addPropertyValue("sessionRegistry", new RuntimeBeanReference(BeanIds.SESSION_REGISTRY));
|
||||
filterBuilder.addPropertyValue("sessionRegistry", new RuntimeBeanReference(BeanIds.SESSION_REGISTRY));
|
||||
|
||||
Object source = parserContext.extractSource(element);
|
||||
filterBuilder.setSource(source);
|
||||
filterBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
controllerBuilder.setSource(source);
|
||||
|
||||
String expiryUrl = element.getAttribute(ATT_EXPIRY_URL);
|
||||
|
||||
if (StringUtils.hasText(expiryUrl)) {
|
||||
ConfigUtils.validateHttpRedirect(expiryUrl, parserContext, source);
|
||||
filterBuilder.addPropertyValue("expiredUrl", expiryUrl);
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder controllerBuilder
|
||||
= BeanDefinitionBuilder.rootBeanDefinition(ConcurrentSessionControllerImpl.class);
|
||||
controllerBuilder.setSource(source);
|
||||
controllerBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
controllerBuilder.addPropertyValue("sessionRegistry", new RuntimeBeanReference(sessionRegistryId));
|
||||
}
|
||||
|
||||
String maxSessions = element.getAttribute(ATT_MAX_SESSIONS);
|
||||
|
||||
@@ -90,17 +63,20 @@ public class ConcurrentSessionsBeanDefinitionParser implements BeanDefinitionPar
|
||||
}
|
||||
|
||||
BeanDefinition controller = controllerBuilder.getBeanDefinition();
|
||||
beanRegistry.registerBeanDefinition(BeanIds.SESSION_REGISTRY, sessionRegistry);
|
||||
|
||||
String registryAlias = element.getAttribute(ATT_SESSION_REGISTRY_ALIAS);
|
||||
if (StringUtils.hasText(registryAlias)) {
|
||||
beanRegistry.registerAlias(BeanIds.SESSION_REGISTRY, registryAlias);
|
||||
}
|
||||
|
||||
beanRegistry.registerBeanDefinition(BeanIds.CONCURRENT_SESSION_CONTROLLER, controller);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(controller, BeanIds.CONCURRENT_SESSION_CONTROLLER));
|
||||
beanRegistry.registerBeanDefinition(BeanIds.CONCURRENT_SESSION_FILTER, filterBuilder.getBeanDefinition());
|
||||
parserContext.registerComponent(new BeanComponentDefinition(filterBuilder.getBeanDefinition(), BeanIds.CONCURRENT_SESSION_FILTER));
|
||||
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.CONCURRENT_SESSION_FILTER));
|
||||
|
||||
ConfigUtils.setSessionControllerOnAuthenticationManager(parserContext, BeanIds.CONCURRENT_SESSION_CONTROLLER, element);
|
||||
|
||||
parserContext.popAndRegisterContainingComponent();
|
||||
|
||||
|
||||
BeanDefinition providerManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
|
||||
providerManager.getPropertyValues().addPropertyValue("sessionController", controller);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,25 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.afterinvocation.AfterInvocationProviderManager;
|
||||
import org.springframework.security.AuthenticationManager;
|
||||
import org.springframework.security.providers.ProviderManager;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.security.util.UrlUtils;
|
||||
import org.springframework.security.vote.AffirmativeBased;
|
||||
import org.springframework.security.vote.AuthenticatedVoter;
|
||||
import org.springframework.security.vote.RoleVoter;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Utility methods used internally by the Spring Security namespace configuration code.
|
||||
* Utitily methods used internally by the Spring Security namespace configuration code.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Ben Alex
|
||||
@@ -50,18 +43,6 @@ public abstract class ConfigUtils {
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.ACCESS_MANAGER, accessMgr);
|
||||
}
|
||||
}
|
||||
|
||||
public static int countNonEmpty(String[] objects) {
|
||||
int nonNulls = 0;
|
||||
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
if (StringUtils.hasText(objects[i])) {
|
||||
nonNulls++;
|
||||
}
|
||||
}
|
||||
|
||||
return nonNulls;
|
||||
}
|
||||
|
||||
public static void addVoter(BeanDefinition voter, ParserContext parserContext) {
|
||||
registerDefaultAccessManagerIfNecessary(parserContext);
|
||||
@@ -92,95 +73,45 @@ public abstract class ConfigUtils {
|
||||
return authManager;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains a user details service for use in RememberMeServices etc. Will return a caching version
|
||||
* if available so should not be used for beans which need to separate the two.
|
||||
*/
|
||||
static UserDetailsService getUserDetailsService(ConfigurableListableBeanFactory bf) {
|
||||
Map services = bf.getBeansOfType(CachingUserDetailsService.class);
|
||||
|
||||
if (services.size() == 0) {
|
||||
services = bf.getBeansOfType(UserDetailsService.class);
|
||||
}
|
||||
|
||||
if (services.size() == 0) {
|
||||
throw new IllegalArgumentException("No UserDetailsService registered.");
|
||||
|
||||
} else if (services.size() > 1) {
|
||||
throw new IllegalArgumentException("More than one UserDetailsService registered. Please" +
|
||||
"use a specific Id in your configuration");
|
||||
}
|
||||
|
||||
return (UserDetailsService) services.values().toArray()[0];
|
||||
}
|
||||
|
||||
private static AuthenticationManager getAuthenticationManager(ConfigurableListableBeanFactory bf) {
|
||||
Map authManagers = bf.getBeansOfType(AuthenticationManager.class);
|
||||
|
||||
if (authManagers.size() == 0) {
|
||||
throw new IllegalArgumentException("No AuthenticationManager registered. " +
|
||||
"Make sure you have configured at least one AuthenticationProvider?");
|
||||
|
||||
} else if (authManagers.size() > 1) {
|
||||
throw new IllegalArgumentException("More than one AuthenticationManager registered.");
|
||||
}
|
||||
|
||||
return (AuthenticationManager) authManagers.values().toArray()[0];
|
||||
}
|
||||
|
||||
static ManagedList getRegisteredProviders(ParserContext parserContext) {
|
||||
BeanDefinition authManager = registerProviderManagerIfNecessary(parserContext);
|
||||
return (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
|
||||
}
|
||||
|
||||
static ManagedList getRegisteredAfterInvocationProviders(ParserContext parserContext) {
|
||||
BeanDefinition manager = registerAfterInvocationProviderManagerIfNecessary(parserContext);
|
||||
return (ManagedList) manager.getPropertyValues().getPropertyValue("providers").getValue();
|
||||
}
|
||||
|
||||
private static BeanDefinition registerAfterInvocationProviderManagerIfNecessary(ParserContext parserContext) {
|
||||
if(parserContext.getRegistry().containsBeanDefinition(BeanIds.AFTER_INVOCATION_MANAGER)) {
|
||||
return parserContext.getRegistry().getBeanDefinition(BeanIds.AFTER_INVOCATION_MANAGER);
|
||||
}
|
||||
|
||||
BeanDefinition manager = new RootBeanDefinition(AfterInvocationProviderManager.class);
|
||||
manager.getPropertyValues().addPropertyValue("providers", new ManagedList());
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.AFTER_INVOCATION_MANAGER, manager);
|
||||
|
||||
return manager;
|
||||
}
|
||||
|
||||
private static void registerFilterChainPostProcessorIfNecessary(ParserContext pc) {
|
||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR)) {
|
||||
return;
|
||||
}
|
||||
// Post processor specifically to assemble and order the filter chain immediately before the FilterChainProxy is initialized.
|
||||
RootBeanDefinition filterChainPostProcessor = new RootBeanDefinition(FilterChainProxyPostProcessor.class);
|
||||
filterChainPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR, filterChainPostProcessor);
|
||||
RootBeanDefinition filterList = new RootBeanDefinition(FilterChainList.class);
|
||||
filterList.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_LIST, filterList);
|
||||
}
|
||||
|
||||
static void addHttpFilter(ParserContext pc, BeanMetadataElement filter) {
|
||||
registerFilterChainPostProcessorIfNecessary(pc);
|
||||
|
||||
RootBeanDefinition filterList = (RootBeanDefinition) pc.getRegistry().getBeanDefinition(BeanIds.FILTER_LIST);
|
||||
|
||||
ManagedList filters;
|
||||
MutablePropertyValues pvs = filterList.getPropertyValues();
|
||||
if (pvs.contains("filters")) {
|
||||
filters = (ManagedList) pvs.getPropertyValue("filters").getValue();
|
||||
} else {
|
||||
filters = new ManagedList();
|
||||
pvs.addPropertyValue("filters", filters);
|
||||
}
|
||||
|
||||
filters.add(filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean which holds the list of filters which are maintained in the context and modified by calls to
|
||||
* addHttpFilter. The post processor retrieves these before injecting the list into the FilterChainProxy.
|
||||
*/
|
||||
public static class FilterChainList {
|
||||
List filters;
|
||||
|
||||
public List getFilters() {
|
||||
return filters;
|
||||
}
|
||||
|
||||
public void setFilters(List filters) {
|
||||
this.filters = filters;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the value of an XML attribute which represents a redirect URL.
|
||||
* If not empty or starting with "$" (potential placeholder), "/" or "http" it will raise an error.
|
||||
*/
|
||||
static void validateHttpRedirect(String url, ParserContext pc, Object source) {
|
||||
if (UrlUtils.isValidRedirectUrl(url) || url.startsWith("$")) {
|
||||
return;
|
||||
}
|
||||
pc.getReaderContext().warning(url + " is not a valid redirect URL (must start with '/' or http(s))", source);
|
||||
}
|
||||
|
||||
static void setSessionControllerOnAuthenticationManager(ParserContext pc, String beanName, Element sourceElt) {
|
||||
BeanDefinition authManager = registerProviderManagerIfNecessary(pc);
|
||||
PropertyValue pv = authManager.getPropertyValues().getPropertyValue("sessionController");
|
||||
|
||||
if (pv != null && pv.getValue() != null) {
|
||||
pc.getReaderContext().error("A session controller has already been set on the authentication manager. " +
|
||||
"The <concurrent-session-control> element isn't compatible with a custom session controller",
|
||||
pc.extractSource(sourceElt));
|
||||
}
|
||||
|
||||
authManager.getPropertyValues().addPropertyValue("sessionController", new RuntimeBeanReference(beanName));
|
||||
}
|
||||
}
|
||||
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* Adds the decorated {@link org.springframework.security.afterinvocation.AfterInvocationProvider} to the
|
||||
* AfterInvocationProviderManager's list.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
*/
|
||||
public class CustomAfterInvocationProviderBeanDefinitionDecorator implements BeanDefinitionDecorator {
|
||||
|
||||
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder holder, ParserContext parserContext) {
|
||||
ConfigUtils.getRegisteredAfterInvocationProviders(parserContext).add(holder.getBeanDefinition());
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
}
|
||||
+1
-2
@@ -3,7 +3,6 @@ package org.springframework.security.config;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
@@ -17,7 +16,7 @@ import org.w3c.dom.Node;
|
||||
*/
|
||||
public class CustomAuthenticationProviderBeanDefinitionDecorator implements BeanDefinitionDecorator {
|
||||
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder holder, ParserContext parserContext) {
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(new RuntimeBeanReference(holder.getBeanName()));
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(holder.getBeanDefinition());
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ abstract class Elements {
|
||||
public static final String JDBC_USER_SERVICE = "jdbc-user-service";
|
||||
public static final String FILTER_CHAIN_MAP = "filter-chain-map";
|
||||
public static final String INTERCEPT_METHODS = "intercept-methods";
|
||||
public static final String INTERCEPT_URL = "intercept-url";
|
||||
public static final String AUTHENTICATION_PROVIDER = "authentication-provider";
|
||||
public static final String HTTP = "http";
|
||||
public static final String LDAP_PROVIDER = "ldap-authentication-provider";
|
||||
@@ -35,8 +34,7 @@ abstract class Elements {
|
||||
public static final String PORT_MAPPINGS = "port-mappings";
|
||||
public static final String PORT_MAPPING = "port-mapping";
|
||||
public static final String CUSTOM_FILTER = "custom-filter";
|
||||
public static final String CUSTOM_AUTH_PROVIDER = "custom-authentication-provider";
|
||||
public static final String CUSTOM_AFTER_INVOCATION_PROVIDER = "custom-after-invocation-provider";
|
||||
public static final String CUSTOM_AUTH_RPOVIDER = "custom-authentication-provider";
|
||||
public static final String X509 = "x509";
|
||||
public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
|
||||
public static final String LDAP_PASSWORD_COMPARE = "password-compare";
|
||||
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.security.ui.AuthenticationEntryPoint;
|
||||
import org.springframework.security.ui.ExceptionTranslationFilter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 2.0.2
|
||||
*/
|
||||
public class EntryPointInjectionBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (!BeanIds.EXCEPTION_TRANSLATION_FILTER.equals(beanName)) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
logger.info("Selecting AuthenticationEntryPoint for use in ExceptionTranslationFilter");
|
||||
|
||||
ExceptionTranslationFilter etf = (ExceptionTranslationFilter) beanFactory.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
|
||||
|
||||
Object entryPoint = null;
|
||||
|
||||
if (beanFactory.containsBean(BeanIds.MAIN_ENTRY_POINT)) {
|
||||
entryPoint = beanFactory.getBean(BeanIds.MAIN_ENTRY_POINT);
|
||||
logger.info("Using main configured AuthenticationEntryPoint.");
|
||||
} else {
|
||||
Map entryPoints = beanFactory.getBeansOfType(AuthenticationEntryPoint.class);
|
||||
Assert.isTrue(entryPoints.size() != 0, "No AuthenticationEntryPoint instances defined");
|
||||
Assert.isTrue(entryPoints.size() == 1, "More than one AuthenticationEntryPoint defined in context");
|
||||
entryPoint = entryPoints.values().toArray()[0];
|
||||
}
|
||||
|
||||
logger.info("Using bean '" + entryPoint + "' as the entry point.");
|
||||
etf.setAuthenticationEntryPoint((AuthenticationEntryPoint) entryPoint);
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
-201
@@ -1,201 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
import org.springframework.security.config.ConfigUtils.FilterChainList;
|
||||
import org.springframework.security.context.HttpSessionContextIntegrationFilter;
|
||||
import org.springframework.security.intercept.web.DefaultFilterInvocationDefinitionSource;
|
||||
import org.springframework.security.intercept.web.FilterSecurityInterceptor;
|
||||
import org.springframework.security.providers.anonymous.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.providers.anonymous.AnonymousProcessingFilter;
|
||||
import org.springframework.security.ui.ExceptionTranslationFilter;
|
||||
import org.springframework.security.ui.SessionFixationProtectionFilter;
|
||||
import org.springframework.security.ui.basicauth.BasicProcessingFilter;
|
||||
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;
|
||||
import org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint;
|
||||
import org.springframework.security.ui.webapp.DefaultLoginPageGeneratingFilter;
|
||||
import org.springframework.security.util.FilterChainProxy;
|
||||
import org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
*/
|
||||
public class FilterChainProxyPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private ListableBeanFactory beanFactory;
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if(!BeanIds.FILTER_CHAIN_PROXY.equals(beanName)) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
FilterChainProxy filterChainProxy = (FilterChainProxy) bean;
|
||||
FilterChainList filterList = (FilterChainList) beanFactory.getBean(BeanIds.FILTER_LIST);
|
||||
|
||||
List filters = new ArrayList(filterList.getFilters());
|
||||
Collections.sort(filters, new OrderComparator());
|
||||
|
||||
logger.info("Checking sorted filter chain: " + filters);
|
||||
|
||||
for(int i=0; i < filters.size(); i++) {
|
||||
Ordered filter = (Ordered)filters.get(i);
|
||||
|
||||
if (i > 0) {
|
||||
Ordered previous = (Ordered)filters.get(i-1);
|
||||
if (filter.getOrder() == previous.getOrder()) {
|
||||
throw new SecurityConfigurationException("Filters '" + unwrapFilter(filter) + "' and '" +
|
||||
unwrapFilter(previous) + "' have the same 'order' value. When using custom filters, " +
|
||||
"please make sure the positions do not conflict with default filters. " +
|
||||
"Alternatively you can disable the default filters by removing the corresponding " +
|
||||
"child elements from <http> and not avoiding the use of <http auto-config='true'>.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Filter chain...");
|
||||
for (int i=0; i < filters.size(); i++) {
|
||||
// Remove the ordered wrapper from the filter and put it back in the chain at the same position.
|
||||
Filter filter = unwrapFilter(filters.get(i));
|
||||
logger.info("[" + i + "] - " + filter);
|
||||
filters.set(i, filter);
|
||||
}
|
||||
|
||||
checkFilterStack(filters);
|
||||
|
||||
// Note that this returns a copy
|
||||
Map filterMap = filterChainProxy.getFilterChainMap();
|
||||
filterMap.put(filterChainProxy.getMatcher().getUniversalMatchPattern(), filters);
|
||||
filterChainProxy.setFilterChainMap(filterMap);
|
||||
|
||||
checkLoginPageIsntProtected(filterChainProxy);
|
||||
|
||||
logger.info("FilterChainProxy: " + filterChainProxy);
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the filter list for possible errors and logs them
|
||||
*/
|
||||
private void checkFilterStack(List filters) {
|
||||
checkForDuplicates(HttpSessionContextIntegrationFilter.class, filters);
|
||||
checkForDuplicates(AuthenticationProcessingFilter.class, filters);
|
||||
checkForDuplicates(SessionFixationProtectionFilter.class, filters);
|
||||
checkForDuplicates(BasicProcessingFilter.class, filters);
|
||||
checkForDuplicates(SecurityContextHolderAwareRequestFilter.class, filters);
|
||||
checkForDuplicates(ExceptionTranslationFilter.class, filters);
|
||||
checkForDuplicates(FilterSecurityInterceptor.class, filters);
|
||||
}
|
||||
|
||||
private void checkForDuplicates(Class clazz, List filters) {
|
||||
for (int i=0; i < filters.size(); i++) {
|
||||
Filter f1 = (Filter)filters.get(i);
|
||||
if (clazz.isAssignableFrom(f1.getClass())) {
|
||||
// Found the first one, check remaining for another
|
||||
for (int j=i+1; j < filters.size(); j++) {
|
||||
Filter f2 = (Filter)filters.get(j);
|
||||
if (clazz.isAssignableFrom(f2.getClass())) {
|
||||
logger.warn("Possible error: Filters at position " + i + " and " + j + " are both " +
|
||||
"instances of " + clazz.getName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Checks for the common error of having a login page URL protected by the security interceptor */
|
||||
private void checkLoginPageIsntProtected(FilterChainProxy fcp) {
|
||||
ExceptionTranslationFilter etf = (ExceptionTranslationFilter) beanFactory.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
|
||||
|
||||
if (etf.getAuthenticationEntryPoint() instanceof AuthenticationProcessingFilterEntryPoint) {
|
||||
String loginPage =
|
||||
((AuthenticationProcessingFilterEntryPoint)etf.getAuthenticationEntryPoint()).getLoginFormUrl();
|
||||
List filters = fcp.getFilters(loginPage);
|
||||
logger.info("Checking whether login URL '" + loginPage + "' is accessible with your configuration");
|
||||
|
||||
if (filters == null || filters.isEmpty()) {
|
||||
logger.debug("Filter chain is empty for the login page");
|
||||
return;
|
||||
}
|
||||
|
||||
if (loginPage.equals(DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL) &&
|
||||
beanFactory.containsBean(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER)) {
|
||||
logger.debug("Default generated login page is in use");
|
||||
return;
|
||||
}
|
||||
|
||||
FilterSecurityInterceptor fsi =
|
||||
((FilterSecurityInterceptor)beanFactory.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR));
|
||||
DefaultFilterInvocationDefinitionSource fids =
|
||||
(DefaultFilterInvocationDefinitionSource) fsi.getObjectDefinitionSource();
|
||||
ConfigAttributeDefinition cad = fids.lookupAttributes(loginPage, "POST");
|
||||
|
||||
if (cad == null) {
|
||||
logger.debug("No access attributes defined for login page URL");
|
||||
if (fsi.isRejectPublicInvocations()) {
|
||||
logger.warn("FilterSecurityInterceptor is configured to reject public invocations." +
|
||||
" Your login page may not be accessible.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!beanFactory.containsBean(BeanIds.ANONYMOUS_PROCESSING_FILTER)) {
|
||||
logger.warn("The login page is being protected by the filter chain, but you don't appear to have" +
|
||||
" anonymous authentication enabled. This is almost certainly an error.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Simulate an anonymous access with the supplied attributes.
|
||||
AnonymousProcessingFilter anonPF = (AnonymousProcessingFilter) beanFactory.getBean(BeanIds.ANONYMOUS_PROCESSING_FILTER);
|
||||
AnonymousAuthenticationToken token =
|
||||
new AnonymousAuthenticationToken("key", anonPF.getUserAttribute().getPassword(),
|
||||
anonPF.getUserAttribute().getAuthorities());
|
||||
try {
|
||||
fsi.getAccessDecisionManager().decide(token, new Object(), cad);
|
||||
} catch (Exception e) {
|
||||
logger.warn("Anonymous access to the login page doesn't appear to be enabled. This is almost certainly " +
|
||||
"an error. Please check your configuration allows unauthenticated access to the configured " +
|
||||
"login page. (Simulated access was rejected: " + e + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the delegate filter of a wrapper, or the unchanged filter if it isn't wrapped.
|
||||
*/
|
||||
private Filter unwrapFilter(Object filter) {
|
||||
if (filter instanceof OrderedFilterBeanDefinitionDecorator.OrderedFilterDecorator) {
|
||||
return ((OrderedFilterBeanDefinitionDecorator.OrderedFilterDecorator)filter).getDelegate();
|
||||
}
|
||||
|
||||
return (Filter) filter;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -44,8 +44,8 @@ public class FilterInvocationDefinitionSourceBeanDefinitionParser extends Abstra
|
||||
UrlMatcher matcher = HttpSecurityBeanDefinitionParser.createUrlMatcher(element);
|
||||
boolean convertPathsToLowerCase = (matcher instanceof AntUrlPathMatcher) && matcher.requiresLowerCaseUrl();
|
||||
|
||||
LinkedHashMap requestMap =
|
||||
HttpSecurityBeanDefinitionParser.parseInterceptUrlsForFilterInvocationRequestMap(interceptUrls,
|
||||
LinkedHashMap requestMap = new LinkedHashMap();
|
||||
HttpSecurityBeanDefinitionParser.parseInterceptUrlsForFilterInvocationRequestMap(interceptUrls, requestMap,
|
||||
convertPathsToLowerCase, parserContext);
|
||||
|
||||
builder.addConstructorArg(matcher);
|
||||
|
||||
+9
-48
@@ -1,6 +1,5 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
@@ -29,7 +28,6 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
|
||||
static final String DEF_LOGIN_PAGE = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL;
|
||||
|
||||
static final String ATT_FORM_LOGIN_TARGET_URL = "default-target-url";
|
||||
static final String ATT_ALWAYS_USE_DEFAULT_TARGET_URL = "always-use-default-target";
|
||||
static final String DEF_FORM_LOGIN_TARGET_URL = "/";
|
||||
|
||||
static final String ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = "authentication-failure-url";
|
||||
@@ -47,90 +45,53 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
|
||||
this.filterClassName = filterClassName;
|
||||
}
|
||||
|
||||
public BeanDefinition parse(Element elt, ParserContext pc) {
|
||||
public BeanDefinition parse(Element elt, ParserContext parserContext) {
|
||||
String loginUrl = null;
|
||||
String defaultTargetUrl = null;
|
||||
String authenticationFailureUrl = null;
|
||||
String alwaysUseDefault = null;
|
||||
|
||||
Object source = null;
|
||||
|
||||
// Copy values from the session fixation protection filter
|
||||
final Boolean sessionFixationProtectionEnabled =
|
||||
new Boolean(pc.getRegistry().containsBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER));
|
||||
Boolean migrateSessionAttributes = Boolean.FALSE;
|
||||
|
||||
if (sessionFixationProtectionEnabled.booleanValue()) {
|
||||
PropertyValue pv =
|
||||
pc.getRegistry().getBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER)
|
||||
.getPropertyValues().getPropertyValue("migrateSessionAttributes");
|
||||
migrateSessionAttributes = (Boolean)pv.getValue();
|
||||
}
|
||||
|
||||
if (elt != null) {
|
||||
source = pc.extractSource(elt);
|
||||
loginUrl = elt.getAttribute(ATT_LOGIN_URL);
|
||||
ConfigUtils.validateHttpRedirect(loginUrl, pc, source);
|
||||
defaultTargetUrl = elt.getAttribute(ATT_FORM_LOGIN_TARGET_URL);
|
||||
ConfigUtils.validateHttpRedirect(defaultTargetUrl, pc, source);
|
||||
authenticationFailureUrl = elt.getAttribute(ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_URL);
|
||||
ConfigUtils.validateHttpRedirect(authenticationFailureUrl, pc, source);
|
||||
alwaysUseDefault = elt.getAttribute(ATT_ALWAYS_USE_DEFAULT_TARGET_URL);
|
||||
loginPage = elt.getAttribute(ATT_LOGIN_PAGE);
|
||||
|
||||
if (!StringUtils.hasText(loginPage)) {
|
||||
loginPage = null;
|
||||
}
|
||||
ConfigUtils.validateHttpRedirect(loginPage, pc, source);
|
||||
|
||||
source = parserContext.extractSource(elt);
|
||||
}
|
||||
|
||||
ConfigUtils.registerProviderManagerIfNecessary(pc);
|
||||
ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
|
||||
filterBean = createFilterBean(loginUrl, defaultTargetUrl, alwaysUseDefault, loginPage, authenticationFailureUrl);
|
||||
filterBean = createFilterBean(loginUrl, defaultTargetUrl, loginPage, authenticationFailureUrl);
|
||||
|
||||
filterBean.setSource(source);
|
||||
filterBean.getPropertyValues().addPropertyValue("authenticationManager",
|
||||
new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
|
||||
filterBean.getPropertyValues().addPropertyValue("invalidateSessionOnSuccessfulAuthentication",
|
||||
sessionFixationProtectionEnabled);
|
||||
filterBean.getPropertyValues().addPropertyValue("migrateInvalidatedSessionAttributes",
|
||||
migrateSessionAttributes);
|
||||
|
||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.REMEMBER_ME_SERVICES)) {
|
||||
filterBean.getPropertyValues().addPropertyValue("rememberMeServices",
|
||||
new RuntimeBeanReference(BeanIds.REMEMBER_ME_SERVICES) );
|
||||
}
|
||||
|
||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.SESSION_REGISTRY)) {
|
||||
filterBean.getPropertyValues().addPropertyValue("sessionRegistry",
|
||||
new RuntimeBeanReference(BeanIds.SESSION_REGISTRY));
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder entryPointBuilder =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(AuthenticationProcessingFilterEntryPoint.class);
|
||||
entryPointBuilder.setSource(source);
|
||||
|
||||
entryPointBuilder.addPropertyValue("loginFormUrl", loginPage != null ? loginPage : DEF_LOGIN_PAGE);
|
||||
|
||||
entryPointBean = (RootBeanDefinition) entryPointBuilder.getBeanDefinition();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private RootBeanDefinition createFilterBean(String loginUrl, String defaultTargetUrl, String alwaysUseDefault,
|
||||
String loginPage, String authenticationFailureUrl) {
|
||||
|
||||
private RootBeanDefinition createFilterBean(String loginUrl, String defaultTargetUrl, String loginPage, String authenticationFailureUrl) {
|
||||
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(filterClassName);
|
||||
|
||||
if (!StringUtils.hasText(loginUrl)) {
|
||||
loginUrl = defaultLoginProcessingUrl;
|
||||
}
|
||||
|
||||
if ("true".equals(alwaysUseDefault)) {
|
||||
filterBuilder.addPropertyValue("alwaysUseDefaultTargetUrl", Boolean.TRUE);
|
||||
}
|
||||
|
||||
filterBuilder.addPropertyValue("filterProcessesUrl", loginUrl);
|
||||
|
||||
|
||||
if (!StringUtils.hasText(defaultTargetUrl)) {
|
||||
defaultTargetUrl = DEF_FORM_LOGIN_TARGET_URL;
|
||||
}
|
||||
|
||||
+71
-114
@@ -8,7 +8,6 @@ import java.util.Map;
|
||||
import org.springframework.aop.config.AopNamespaceUtils;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
@@ -20,6 +19,7 @@ import org.springframework.security.intercept.method.MapBasedMethodDefinitionSou
|
||||
import org.springframework.security.intercept.method.ProtectPointcutPostProcessor;
|
||||
import org.springframework.security.intercept.method.aopalliance.MethodDefinitionSourceAdvisor;
|
||||
import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
@@ -34,6 +34,7 @@ import org.w3c.dom.Element;
|
||||
class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
public static final String SECURED_DEPENDENCY_CLASS = "org.springframework.security.annotation.Secured";
|
||||
public static final String SECURED_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.annotation.SecuredMethodDefinitionSource";
|
||||
public static final String JSR_250_DEPENDENCY_CLASS = "javax.annotation.security.DenyAll";
|
||||
public static final String JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.annotation.Jsr250MethodDefinitionSource";
|
||||
public static final String JSR_250_VOTER_CLASS = "org.springframework.security.annotation.Jsr250Voter";
|
||||
private static final String ATT_ACCESS = "access";
|
||||
@@ -42,144 +43,100 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private static final String ATT_USE_JSR250 = "jsr250-annotations";
|
||||
private static final String ATT_USE_SECURED = "secured-annotations";
|
||||
|
||||
private void validatePresent(String className, Element element, ParserContext parserContext) {
|
||||
if (!ClassUtils.isPresent(className, parserContext.getReaderContext().getBeanClassLoader())) {
|
||||
parserContext.getReaderContext().error("Cannot locate '" + className + "'", element);
|
||||
}
|
||||
private void validatePresent(String className) {
|
||||
Assert.isTrue(ClassUtils.isPresent(className), "Cannot locate '" + className + "'");
|
||||
}
|
||||
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
Object source = parserContext.extractSource(element);
|
||||
// The list of method metadata delegates
|
||||
ManagedList delegates = new ManagedList();
|
||||
|
||||
boolean jsr250Enabled = registerAnnotationBasedMethodDefinitionSources(element, parserContext, delegates);
|
||||
|
||||
MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource = new MapBasedMethodDefinitionSource();
|
||||
delegates.add(mapBasedMethodDefinitionSource);
|
||||
|
||||
// Now create a Map<String, ConfigAttribute> for each <protect-pointcut> sub-element
|
||||
Map pointcutMap = parseProtectPointcuts(parserContext,
|
||||
DomUtils.getChildElementsByTagName(element, Elements.PROTECT_POINTCUT));
|
||||
|
||||
if (pointcutMap.size() > 0) {
|
||||
registerProtectPointcutPostProcessor(parserContext, pointcutMap, mapBasedMethodDefinitionSource, source);
|
||||
boolean useJsr250 = "enabled".equals(element.getAttribute(ATT_USE_JSR250));
|
||||
boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED));
|
||||
|
||||
// Check the required classes are present
|
||||
if (useSecured) {
|
||||
validatePresent(SECURED_METHOD_DEFINITION_SOURCE_CLASS);
|
||||
validatePresent(SECURED_DEPENDENCY_CLASS);
|
||||
}
|
||||
|
||||
if (useJsr250) {
|
||||
validatePresent(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS);
|
||||
validatePresent(JSR_250_VOTER_CLASS);
|
||||
validatePresent(JSR_250_DEPENDENCY_CLASS);
|
||||
}
|
||||
|
||||
registerDelegatingMethodDefinitionSource(parserContext, delegates, source);
|
||||
// Now create a Map<String, ConfigAttribute> for each <protect-pointcut> sub-element
|
||||
Map pointcutMap = new LinkedHashMap();
|
||||
List protect = DomUtils.getChildElementsByTagName(element, Elements.PROTECT_POINTCUT);
|
||||
|
||||
for (Iterator i = protect.iterator(); i.hasNext();) {
|
||||
Element childElt = (Element) i.next();
|
||||
String accessConfig = childElt.getAttribute(ATT_ACCESS);
|
||||
String expression = childElt.getAttribute(ATT_EXPRESSION);
|
||||
Assert.hasText(accessConfig, "Access configuration required for '" + childElt + "'");
|
||||
Assert.hasText(expression, "Expression required for '" + childElt + "'");
|
||||
|
||||
ConfigAttributeDefinition def = new ConfigAttributeDefinition(StringUtils.commaDelimitedListToStringArray(accessConfig));
|
||||
pointcutMap.put(expression, def);
|
||||
}
|
||||
|
||||
MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource = new MapBasedMethodDefinitionSource();
|
||||
|
||||
// Now create and populate our ProtectPointcutBeanPostProcessor, if needed
|
||||
if (pointcutMap.size() > 0) {
|
||||
RootBeanDefinition ppbp = new RootBeanDefinition(ProtectPointcutPostProcessor.class);
|
||||
ppbp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
ppbp.getConstructorArgumentValues().addGenericArgumentValue(mapBasedMethodDefinitionSource);
|
||||
ppbp.getPropertyValues().addPropertyValue("pointcutMap", pointcutMap);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.PROTECT_POINTCUT_POST_PROCESSOR, ppbp);
|
||||
}
|
||||
|
||||
// Create our list of method metadata delegates
|
||||
ManagedList delegates = new ManagedList();
|
||||
delegates.add(mapBasedMethodDefinitionSource);
|
||||
|
||||
if (useSecured) {
|
||||
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(SECURED_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
|
||||
}
|
||||
|
||||
if (useJsr250) {
|
||||
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
|
||||
}
|
||||
|
||||
// Register our DelegatingMethodDefinitionSource
|
||||
RootBeanDefinition delegatingMethodDefinitionSource = new RootBeanDefinition(DelegatingMethodDefinitionSource.class);
|
||||
delegatingMethodDefinitionSource.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
delegatingMethodDefinitionSource.getPropertyValues().addPropertyValue("methodDefinitionSources", delegates);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE, delegatingMethodDefinitionSource);
|
||||
|
||||
// Register the applicable AccessDecisionManager, handling the special JSR 250 voter if being used
|
||||
String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
|
||||
|
||||
if (!StringUtils.hasText(accessManagerId)) {
|
||||
ConfigUtils.registerDefaultAccessManagerIfNecessary(parserContext);
|
||||
|
||||
if (jsr250Enabled) {
|
||||
if (useJsr250) {
|
||||
ConfigUtils.addVoter(new RootBeanDefinition(JSR_250_VOTER_CLASS, null, null), parserContext);
|
||||
}
|
||||
|
||||
accessManagerId = BeanIds.ACCESS_MANAGER;
|
||||
}
|
||||
|
||||
registerMethodSecurityInterceptor(parserContext, accessManagerId, source);
|
||||
|
||||
registerAdvisor(parserContext, source);
|
||||
|
||||
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether JSR-250 and/or Secured annotations are enabled and adds the appropriate
|
||||
* MethodDefinitionSource delegates if required.
|
||||
*/
|
||||
private boolean registerAnnotationBasedMethodDefinitionSources(Element element, ParserContext pc, ManagedList delegates) {
|
||||
boolean useJsr250 = "enabled".equals(element.getAttribute(ATT_USE_JSR250));
|
||||
boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED));
|
||||
|
||||
// Check the required classes are present
|
||||
if (useSecured) {
|
||||
validatePresent(SECURED_METHOD_DEFINITION_SOURCE_CLASS, element, pc);
|
||||
validatePresent(SECURED_DEPENDENCY_CLASS, element, pc);
|
||||
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(SECURED_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
|
||||
}
|
||||
|
||||
if (useJsr250) {
|
||||
validatePresent(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS, element, pc);
|
||||
validatePresent(JSR_250_VOTER_CLASS, element, pc);
|
||||
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
|
||||
}
|
||||
|
||||
return useJsr250;
|
||||
}
|
||||
|
||||
private void registerDelegatingMethodDefinitionSource(ParserContext parserContext, ManagedList delegates, Object source) {
|
||||
if (parserContext.getRegistry().containsBeanDefinition(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE)) {
|
||||
parserContext.getReaderContext().error("Duplicate <global-method-security> detected.", source);
|
||||
}
|
||||
RootBeanDefinition delegatingMethodDefinitionSource = new RootBeanDefinition(DelegatingMethodDefinitionSource.class);
|
||||
delegatingMethodDefinitionSource.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
delegatingMethodDefinitionSource.setSource(source);
|
||||
delegatingMethodDefinitionSource.getPropertyValues().addPropertyValue("methodDefinitionSources", delegates);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE, delegatingMethodDefinitionSource);
|
||||
}
|
||||
|
||||
private void registerProtectPointcutPostProcessor(ParserContext parserContext, Map pointcutMap,
|
||||
MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource, Object source) {
|
||||
RootBeanDefinition ppbp = new RootBeanDefinition(ProtectPointcutPostProcessor.class);
|
||||
ppbp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
ppbp.setSource(source);
|
||||
ppbp.getConstructorArgumentValues().addGenericArgumentValue(mapBasedMethodDefinitionSource);
|
||||
ppbp.getPropertyValues().addPropertyValue("pointcutMap", pointcutMap);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.PROTECT_POINTCUT_POST_PROCESSOR, ppbp);
|
||||
}
|
||||
|
||||
private Map parseProtectPointcuts(ParserContext parserContext, List protectPointcutElts) {
|
||||
Map pointcutMap = new LinkedHashMap();
|
||||
|
||||
for (Iterator i = protectPointcutElts.iterator(); i.hasNext();) {
|
||||
Element childElt = (Element) i.next();
|
||||
String accessConfig = childElt.getAttribute(ATT_ACCESS);
|
||||
String expression = childElt.getAttribute(ATT_EXPRESSION);
|
||||
|
||||
if (!StringUtils.hasText(accessConfig)) {
|
||||
parserContext.getReaderContext().error("Access configuration required", parserContext.extractSource(childElt));
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(expression)) {
|
||||
parserContext.getReaderContext().error("Pointcut expression required", parserContext.extractSource(childElt));
|
||||
}
|
||||
|
||||
ConfigAttributeDefinition def = new ConfigAttributeDefinition(StringUtils.commaDelimitedListToStringArray(accessConfig));
|
||||
pointcutMap.put(expression, def);
|
||||
}
|
||||
|
||||
return pointcutMap;
|
||||
}
|
||||
|
||||
private void registerMethodSecurityInterceptor(ParserContext parserContext, String accessManagerId, Object source) {
|
||||
// MethodSecurityInterceptor
|
||||
RootBeanDefinition interceptor = new RootBeanDefinition(MethodSecurityInterceptor.class);
|
||||
interceptor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
interceptor.setSource(source);
|
||||
|
||||
|
||||
interceptor.getPropertyValues().addPropertyValue("accessDecisionManager", new RuntimeBeanReference(accessManagerId));
|
||||
interceptor.getPropertyValues().addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
interceptor.getPropertyValues().addPropertyValue("objectDefinitionSource", new RuntimeBeanReference(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE));
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_INTERCEPTOR, interceptor);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(interceptor, BeanIds.METHOD_SECURITY_INTERCEPTOR));
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_INTERCEPTOR_POST_PROCESSOR,
|
||||
new RootBeanDefinition(MethodSecurityInterceptorPostProcessor.class));
|
||||
}
|
||||
|
||||
private void registerAdvisor(ParserContext parserContext, Object source) {
|
||||
// MethodDefinitionSourceAdvisor
|
||||
RootBeanDefinition advisor = new RootBeanDefinition(MethodDefinitionSourceAdvisor.class);
|
||||
advisor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
advisor.setSource(source);
|
||||
advisor.getConstructorArgumentValues().addGenericArgumentValue(BeanIds.METHOD_SECURITY_INTERCEPTOR);
|
||||
advisor.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE));
|
||||
advisor.getConstructorArgumentValues().addGenericArgumentValue(interceptor);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_DEFINITION_SOURCE_ADVISOR, advisor);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_DEFINITION_SOURCE_ADVISOR, advisor);
|
||||
}
|
||||
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+152
-233
@@ -29,7 +29,6 @@ import org.springframework.security.securechannel.InsecureChannelProcessor;
|
||||
import org.springframework.security.securechannel.SecureChannelProcessor;
|
||||
import org.springframework.security.securechannel.RetryWithHttpEntryPoint;
|
||||
import org.springframework.security.securechannel.RetryWithHttpsEntryPoint;
|
||||
import org.springframework.security.ui.AccessDeniedHandlerImpl;
|
||||
import org.springframework.security.ui.ExceptionTranslationFilter;
|
||||
import org.springframework.security.ui.SessionFixationProtectionFilter;
|
||||
import org.springframework.security.ui.webapp.DefaultLoginPageGeneratingFilter;
|
||||
@@ -95,59 +94,139 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
static final String ATT_USER_SERVICE_REF = "user-service-ref";
|
||||
|
||||
static final String ATT_ENTRY_POINT_REF = "entry-point-ref";
|
||||
static final String ATT_ONCE_PER_REQUEST = "once-per-request";
|
||||
static final String ATT_ACCESS_DENIED_PAGE = "access-denied-page";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
final BeanDefinitionRegistry registry = parserContext.getRegistry();
|
||||
final UrlMatcher matcher = createUrlMatcher(element);
|
||||
final Object source = parserContext.extractSource(element);
|
||||
// SEC-501 - should paths stored in request maps be converted to lower case
|
||||
// true if Ant path and using lower case
|
||||
final boolean convertPathsToLowerCase = (matcher instanceof AntUrlPathMatcher) && matcher.requiresLowerCaseUrl();
|
||||
|
||||
final List interceptUrlElts = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL);
|
||||
final Map filterChainMap = new LinkedHashMap();
|
||||
final LinkedHashMap channelRequestMap = new LinkedHashMap();
|
||||
BeanDefinitionRegistry registry = parserContext.getRegistry();
|
||||
RootBeanDefinition filterChainProxy = new RootBeanDefinition(FilterChainProxy.class);
|
||||
RootBeanDefinition httpScif = new RootBeanDefinition(HttpSessionContextIntegrationFilter.class);
|
||||
|
||||
registerFilterChainProxy(parserContext, filterChainMap, matcher, source);
|
||||
|
||||
parseInterceptUrlsForChannelSecurityAndFilterChain(interceptUrlElts, filterChainMap, channelRequestMap,
|
||||
convertPathsToLowerCase, parserContext);
|
||||
BeanDefinition portMapper = new PortMappingsBeanDefinitionParser().parse(
|
||||
DomUtils.getChildElementByTagName(element, Elements.PORT_MAPPINGS), parserContext);
|
||||
registry.registerBeanDefinition(BeanIds.PORT_MAPPER, portMapper);
|
||||
|
||||
registerHttpSessionIntegrationFilter(element, parserContext);
|
||||
RuntimeBeanReference portMapperRef = new RuntimeBeanReference(BeanIds.PORT_MAPPER);
|
||||
|
||||
String createSession = element.getAttribute(ATT_CREATE_SESSION);
|
||||
if (OPT_CREATE_SESSION_ALWAYS.equals(createSession)) {
|
||||
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.TRUE);
|
||||
httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
|
||||
} else if (OPT_CREATE_SESSION_NEVER.equals(createSession)) {
|
||||
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.FALSE);
|
||||
httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
|
||||
} else {
|
||||
createSession = DEF_CREATE_SESSION_IF_REQUIRED;
|
||||
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.TRUE);
|
||||
httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder filterSecurityInterceptorBuilder
|
||||
= BeanDefinitionBuilder.rootBeanDefinition(FilterSecurityInterceptor.class);
|
||||
|
||||
BeanDefinitionBuilder exceptionTranslationFilterBuilder
|
||||
= BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
|
||||
|
||||
Map filterChainMap = new LinkedHashMap();
|
||||
|
||||
registerServletApiFilter(element, parserContext);
|
||||
|
||||
// Set up the access manager reference for http
|
||||
UrlMatcher matcher = createUrlMatcher(element);
|
||||
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("matcher", matcher);
|
||||
|
||||
// Add servlet-api integration filter if required
|
||||
String provideServletApi = element.getAttribute(ATT_SERVLET_API_PROVISION);
|
||||
if (!StringUtils.hasText(provideServletApi)) {
|
||||
provideServletApi = DEF_SERVLET_API_PROVISION;
|
||||
}
|
||||
|
||||
if ("true".equals(provideServletApi)) {
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER,
|
||||
new RootBeanDefinition(SecurityContextHolderAwareRequestFilter.class));
|
||||
}
|
||||
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("filterChainMap", filterChainMap);
|
||||
|
||||
// Set up the access manager and authentication manager references for http
|
||||
String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
|
||||
|
||||
if (!StringUtils.hasText(accessManagerId)) {
|
||||
ConfigUtils.registerDefaultAccessManagerIfNecessary(parserContext);
|
||||
accessManagerId = BeanIds.ACCESS_MANAGER;
|
||||
}
|
||||
|
||||
filterSecurityInterceptorBuilder.addPropertyValue("accessDecisionManager",
|
||||
new RuntimeBeanReference(accessManagerId));
|
||||
filterSecurityInterceptorBuilder.addPropertyValue("authenticationManager",
|
||||
ConfigUtils.registerProviderManagerIfNecessary(parserContext));
|
||||
|
||||
// SEC-501 - should paths stored in request maps be converted to lower case
|
||||
// true if Ant path and using lower case
|
||||
boolean convertPathsToLowerCase = (matcher instanceof AntUrlPathMatcher) && matcher.requiresLowerCaseUrl();
|
||||
|
||||
// Register the portMapper. A default will always be created, even if no element exists.
|
||||
BeanDefinition portMapper = new PortMappingsBeanDefinitionParser().parse(
|
||||
DomUtils.getChildElementByTagName(element, Elements.PORT_MAPPINGS), parserContext);
|
||||
registry.registerBeanDefinition(BeanIds.PORT_MAPPER, portMapper);
|
||||
|
||||
registerExceptionTranslationFilter(element, parserContext);
|
||||
LinkedHashMap channelRequestMap = new LinkedHashMap();
|
||||
LinkedHashMap filterInvocationDefinitionMap = new LinkedHashMap();
|
||||
|
||||
List interceptUrlElts = DomUtils.getChildElementsByTagName(element, "intercept-url");
|
||||
parseInterceptUrlsForChannelSecurityAndFilterChain(interceptUrlElts, filterChainMap, channelRequestMap,
|
||||
convertPathsToLowerCase, parserContext);
|
||||
parseInterceptUrlsForFilterInvocationRequestMap(interceptUrlElts, filterInvocationDefinitionMap,
|
||||
convertPathsToLowerCase, parserContext);
|
||||
|
||||
DefaultFilterInvocationDefinitionSource interceptorFilterInvDefSource =
|
||||
new DefaultFilterInvocationDefinitionSource(matcher, filterInvocationDefinitionMap);
|
||||
DefaultFilterInvocationDefinitionSource channelFilterInvDefSource =
|
||||
new DefaultFilterInvocationDefinitionSource(matcher, channelRequestMap);
|
||||
|
||||
filterSecurityInterceptorBuilder.addPropertyValue("objectDefinitionSource", interceptorFilterInvDefSource);
|
||||
|
||||
|
||||
// Check if we need to register the channel processing beans
|
||||
if (channelRequestMap.size() > 0) {
|
||||
// At least one channel requirement has been specified
|
||||
registerChannelProcessingBeans(parserContext, matcher, channelRequestMap);
|
||||
}
|
||||
|
||||
registerFilterSecurityInterceptor(element, parserContext, matcher, accessManagerId,
|
||||
parseInterceptUrlsForFilterInvocationRequestMap(interceptUrlElts, convertPathsToLowerCase, parserContext));
|
||||
RootBeanDefinition channelFilter = new RootBeanDefinition(ChannelProcessingFilter.class);
|
||||
channelFilter.getPropertyValues().addPropertyValue("channelDecisionManager",
|
||||
new RuntimeBeanReference(BeanIds.CHANNEL_DECISION_MANAGER));
|
||||
|
||||
boolean sessionControlEnabled = registerConcurrentSessionControlBeansIfRequired(element, parserContext);
|
||||
channelFilter.getPropertyValues().addPropertyValue("filterInvocationDefinitionSource",
|
||||
channelFilterInvDefSource);
|
||||
RootBeanDefinition channelDecisionManager = new RootBeanDefinition(ChannelDecisionManagerImpl.class);
|
||||
ManagedList channelProcessors = new ManagedList(3);
|
||||
RootBeanDefinition secureChannelProcessor = new RootBeanDefinition(SecureChannelProcessor.class);
|
||||
RootBeanDefinition retryWithHttp = new RootBeanDefinition(RetryWithHttpEntryPoint.class);
|
||||
RootBeanDefinition retryWithHttps = new RootBeanDefinition(RetryWithHttpsEntryPoint.class);
|
||||
retryWithHttp.getPropertyValues().addPropertyValue("portMapper", portMapperRef);
|
||||
retryWithHttps.getPropertyValues().addPropertyValue("portMapper", portMapperRef);
|
||||
secureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttps);
|
||||
RootBeanDefinition inSecureChannelProcessor = new RootBeanDefinition(InsecureChannelProcessor.class);
|
||||
inSecureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttp);
|
||||
channelProcessors.add(secureChannelProcessor);
|
||||
channelProcessors.add(inSecureChannelProcessor);
|
||||
channelDecisionManager.getPropertyValues().addPropertyValue("channelProcessors", channelProcessors);
|
||||
|
||||
registry.registerBeanDefinition(BeanIds.CHANNEL_PROCESSING_FILTER, channelFilter);
|
||||
registry.registerBeanDefinition(BeanIds.CHANNEL_DECISION_MANAGER, channelDecisionManager);
|
||||
}
|
||||
|
||||
Element sessionControlElt = DomUtils.getChildElementByTagName(element, Elements.CONCURRENT_SESSIONS);
|
||||
if (sessionControlElt != null) {
|
||||
new ConcurrentSessionsBeanDefinitionParser().parse(sessionControlElt, parserContext);
|
||||
}
|
||||
|
||||
String sessionFixationAttribute = element.getAttribute(ATT_SESSION_FIXATION_PROTECTION);
|
||||
|
||||
registerSessionFixationProtectionFilter(parserContext, element.getAttribute(ATT_SESSION_FIXATION_PROTECTION),
|
||||
sessionControlEnabled);
|
||||
if(!StringUtils.hasText(sessionFixationAttribute)) {
|
||||
sessionFixationAttribute = OPT_SESSION_FIXATION_MIGRATE_SESSION;
|
||||
}
|
||||
|
||||
if (!sessionFixationAttribute.equals(OPT_SESSION_FIXATION_NO_PROTECTION)) {
|
||||
BeanDefinitionBuilder sessionFixationFilter =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(SessionFixationProtectionFilter.class);
|
||||
sessionFixationFilter.addPropertyValue("migrateSessionAttributes",
|
||||
Boolean.valueOf(sessionFixationAttribute.equals(OPT_SESSION_FIXATION_MIGRATE_SESSION)));
|
||||
if (sessionControlElt != null) {
|
||||
sessionFixationFilter.addPropertyReference("sessionRegistry", BeanIds.SESSION_REGISTRY);
|
||||
}
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER,
|
||||
sessionFixationFilter.getBeanDefinition());
|
||||
}
|
||||
|
||||
boolean autoConfig = false;
|
||||
if ("true".equals(element.getAttribute(ATT_AUTO_CONFIG))) {
|
||||
@@ -163,10 +242,6 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
Element rememberMeElt = DomUtils.getChildElementByTagName(element, Elements.REMEMBER_ME);
|
||||
if (rememberMeElt != null || autoConfig) {
|
||||
new RememberMeBeanDefinitionParser().parse(rememberMeElt, parserContext);
|
||||
// Post processor to inject RememberMeServices into filters which need it
|
||||
RootBeanDefinition rememberMeInjectionPostProcessor = new RootBeanDefinition(RememberMeServicesInjectionBeanPostProcessor.class);
|
||||
rememberMeInjectionPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
registry.registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR, rememberMeInjectionPostProcessor);
|
||||
}
|
||||
|
||||
Element logoutElt = DomUtils.getChildElementByTagName(element, Elements.LOGOUT);
|
||||
@@ -181,164 +256,21 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
new X509BeanDefinitionParser().parse(x509Elt, parserContext);
|
||||
}
|
||||
|
||||
// Register the post processors which will tie up the loose ends in the configuration once the app context has been created and all beans are available.
|
||||
RootBeanDefinition postProcessor = new RootBeanDefinition(EntryPointInjectionBeanPostProcessor.class);
|
||||
registry.registerBeanDefinition(BeanIds.FILTER_CHAIN_PROXY, filterChainProxy);
|
||||
registry.registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||
registry.registerBeanDefinition(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER, httpScif);
|
||||
registry.registerBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER, exceptionTranslationFilterBuilder.getBeanDefinition());
|
||||
registry.registerBeanDefinition(BeanIds.FILTER_SECURITY_INTERCEPTOR, filterSecurityInterceptorBuilder.getBeanDefinition());
|
||||
|
||||
// Register the post processor which will tie up the loose ends in the configuration once the app context has been created and all beans are available.
|
||||
RootBeanDefinition postProcessor = new RootBeanDefinition(HttpSecurityConfigPostProcessor.class);
|
||||
postProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
registry.registerBeanDefinition(BeanIds.ENTRY_POINT_INJECTION_POST_PROCESSOR, postProcessor);
|
||||
RootBeanDefinition postProcessor2 = new RootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
|
||||
postProcessor2.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
registry.registerBeanDefinition(BeanIds.USER_DETAILS_SERVICE_INJECTION_POST_PROCESSOR, postProcessor2);
|
||||
|
||||
registry.registerBeanDefinition(BeanIds.HTTP_POST_PROCESSOR, postProcessor);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void registerFilterChainProxy(ParserContext pc, Map filterChainMap, UrlMatcher matcher, Object source) {
|
||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
|
||||
pc.getReaderContext().error("Duplicate <http> element detected", source);
|
||||
}
|
||||
|
||||
RootBeanDefinition filterChainProxy = new RootBeanDefinition(FilterChainProxy.class);
|
||||
filterChainProxy.setSource(source);
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("matcher", matcher);
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("filterChainMap", filterChainMap);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_CHAIN_PROXY, filterChainProxy);
|
||||
pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||
}
|
||||
|
||||
private void registerHttpSessionIntegrationFilter(Element element, ParserContext pc) {
|
||||
RootBeanDefinition httpScif = new RootBeanDefinition(HttpSessionContextIntegrationFilter.class);
|
||||
|
||||
String createSession = element.getAttribute(ATT_CREATE_SESSION);
|
||||
if (OPT_CREATE_SESSION_ALWAYS.equals(createSession)) {
|
||||
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.TRUE);
|
||||
httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
|
||||
} else if (OPT_CREATE_SESSION_NEVER.equals(createSession)) {
|
||||
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.FALSE);
|
||||
httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
|
||||
} else {
|
||||
createSession = DEF_CREATE_SESSION_IF_REQUIRED;
|
||||
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.TRUE);
|
||||
httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
|
||||
}
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER, httpScif);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER));
|
||||
}
|
||||
|
||||
// Adds the servlet-api integration filter if required
|
||||
private void registerServletApiFilter(Element element, ParserContext pc) {
|
||||
String provideServletApi = element.getAttribute(ATT_SERVLET_API_PROVISION);
|
||||
if (!StringUtils.hasText(provideServletApi)) {
|
||||
provideServletApi = DEF_SERVLET_API_PROVISION;
|
||||
}
|
||||
|
||||
if ("true".equals(provideServletApi)) {
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER,
|
||||
new RootBeanDefinition(SecurityContextHolderAwareRequestFilter.class));
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean registerConcurrentSessionControlBeansIfRequired(Element element, ParserContext parserContext) {
|
||||
Element sessionControlElt = DomUtils.getChildElementByTagName(element, Elements.CONCURRENT_SESSIONS);
|
||||
if (sessionControlElt == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
new ConcurrentSessionsBeanDefinitionParser().parse(sessionControlElt, parserContext);
|
||||
logger.info("Concurrent session filter in use, setting 'forceEagerSessionCreation' to true");
|
||||
BeanDefinition sessionIntegrationFilter = parserContext.getRegistry().getBeanDefinition(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER);
|
||||
sessionIntegrationFilter.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void registerExceptionTranslationFilter(Element element, ParserContext pc) {
|
||||
String accessDeniedPage = element.getAttribute(ATT_ACCESS_DENIED_PAGE);
|
||||
ConfigUtils.validateHttpRedirect(accessDeniedPage, pc, pc.extractSource(element));
|
||||
BeanDefinitionBuilder exceptionTranslationFilterBuilder
|
||||
= BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
|
||||
|
||||
if (StringUtils.hasText(accessDeniedPage)) {
|
||||
AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl();
|
||||
accessDeniedHandler.setErrorPage(accessDeniedPage);
|
||||
exceptionTranslationFilterBuilder.addPropertyValue("accessDeniedHandler", accessDeniedHandler);
|
||||
}
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER, exceptionTranslationFilterBuilder.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.EXCEPTION_TRANSLATION_FILTER));
|
||||
}
|
||||
|
||||
private void registerFilterSecurityInterceptor(Element element, ParserContext pc, UrlMatcher matcher,
|
||||
String accessManagerId, LinkedHashMap filterInvocationDefinitionMap) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterSecurityInterceptor.class);
|
||||
|
||||
builder.addPropertyReference("accessDecisionManager", accessManagerId);
|
||||
builder.addPropertyReference("authenticationManager", BeanIds.AUTHENTICATION_MANAGER);
|
||||
|
||||
if ("false".equals(element.getAttribute(ATT_ONCE_PER_REQUEST))) {
|
||||
builder.addPropertyValue("observeOncePerRequest", Boolean.FALSE);
|
||||
}
|
||||
|
||||
DefaultFilterInvocationDefinitionSource fids =
|
||||
new DefaultFilterInvocationDefinitionSource(matcher, filterInvocationDefinitionMap);
|
||||
fids.setStripQueryStringFromUrls(matcher instanceof AntUrlPathMatcher);
|
||||
|
||||
builder.addPropertyValue("objectDefinitionSource", fids);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_SECURITY_INTERCEPTOR, builder.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FILTER_SECURITY_INTERCEPTOR));
|
||||
}
|
||||
|
||||
private void registerChannelProcessingBeans(ParserContext pc, UrlMatcher matcher, LinkedHashMap channelRequestMap) {
|
||||
RootBeanDefinition channelFilter = new RootBeanDefinition(ChannelProcessingFilter.class);
|
||||
channelFilter.getPropertyValues().addPropertyValue("channelDecisionManager",
|
||||
new RuntimeBeanReference(BeanIds.CHANNEL_DECISION_MANAGER));
|
||||
DefaultFilterInvocationDefinitionSource channelFilterInvDefSource =
|
||||
new DefaultFilterInvocationDefinitionSource(matcher, channelRequestMap);
|
||||
channelFilterInvDefSource.setStripQueryStringFromUrls(matcher instanceof AntUrlPathMatcher);
|
||||
|
||||
channelFilter.getPropertyValues().addPropertyValue("filterInvocationDefinitionSource",
|
||||
channelFilterInvDefSource);
|
||||
RootBeanDefinition channelDecisionManager = new RootBeanDefinition(ChannelDecisionManagerImpl.class);
|
||||
ManagedList channelProcessors = new ManagedList(3);
|
||||
RootBeanDefinition secureChannelProcessor = new RootBeanDefinition(SecureChannelProcessor.class);
|
||||
RootBeanDefinition retryWithHttp = new RootBeanDefinition(RetryWithHttpEntryPoint.class);
|
||||
RootBeanDefinition retryWithHttps = new RootBeanDefinition(RetryWithHttpsEntryPoint.class);
|
||||
RuntimeBeanReference portMapper = new RuntimeBeanReference(BeanIds.PORT_MAPPER);
|
||||
retryWithHttp.getPropertyValues().addPropertyValue("portMapper", portMapper);
|
||||
retryWithHttps.getPropertyValues().addPropertyValue("portMapper", portMapper);
|
||||
secureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttps);
|
||||
RootBeanDefinition inSecureChannelProcessor = new RootBeanDefinition(InsecureChannelProcessor.class);
|
||||
inSecureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttp);
|
||||
channelProcessors.add(secureChannelProcessor);
|
||||
channelProcessors.add(inSecureChannelProcessor);
|
||||
channelDecisionManager.getPropertyValues().addPropertyValue("channelProcessors", channelProcessors);
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.CHANNEL_PROCESSING_FILTER, channelFilter);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.CHANNEL_PROCESSING_FILTER));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.CHANNEL_DECISION_MANAGER, channelDecisionManager);
|
||||
|
||||
}
|
||||
|
||||
private void registerSessionFixationProtectionFilter(ParserContext pc, String sessionFixationAttribute, boolean sessionControlEnabled) {
|
||||
if(!StringUtils.hasText(sessionFixationAttribute)) {
|
||||
sessionFixationAttribute = OPT_SESSION_FIXATION_MIGRATE_SESSION;
|
||||
}
|
||||
|
||||
if (!sessionFixationAttribute.equals(OPT_SESSION_FIXATION_NO_PROTECTION)) {
|
||||
BeanDefinitionBuilder sessionFixationFilter =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(SessionFixationProtectionFilter.class);
|
||||
sessionFixationFilter.addPropertyValue("migrateSessionAttributes",
|
||||
Boolean.valueOf(sessionFixationAttribute.equals(OPT_SESSION_FIXATION_MIGRATE_SESSION)));
|
||||
if (sessionControlEnabled) {
|
||||
sessionFixationFilter.addPropertyReference("sessionRegistry", BeanIds.SESSION_REGISTRY);
|
||||
}
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER,
|
||||
sessionFixationFilter.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SESSION_FIXATION_PROTECTION_FILTER));
|
||||
}
|
||||
}
|
||||
|
||||
private void parseBasicFormLoginAndOpenID(Element element, ParserContext pc, boolean autoConfig) {
|
||||
private void parseBasicFormLoginAndOpenID(Element element, ParserContext parserContext, boolean autoConfig) {
|
||||
RootBeanDefinition formLoginFilter = null;
|
||||
RootBeanDefinition formLoginEntryPoint = null;
|
||||
String formLoginPage = null;
|
||||
@@ -349,12 +281,12 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
String realm = element.getAttribute(ATT_REALM);
|
||||
if (!StringUtils.hasText(realm)) {
|
||||
realm = DEF_REALM;
|
||||
}
|
||||
}
|
||||
|
||||
Element basicAuthElt = DomUtils.getChildElementByTagName(element, Elements.BASIC_AUTH);
|
||||
if (basicAuthElt != null || autoConfig) {
|
||||
new BasicAuthenticationBeanDefinitionParser(realm).parse(basicAuthElt, pc);
|
||||
}
|
||||
new BasicAuthenticationBeanDefinitionParser(realm).parse(basicAuthElt, parserContext);
|
||||
}
|
||||
|
||||
Element formLoginElt = DomUtils.getChildElementByTagName(element, Elements.FORM_LOGIN);
|
||||
|
||||
@@ -362,7 +294,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
|
||||
"org.springframework.security.ui.webapp.AuthenticationProcessingFilter");
|
||||
|
||||
parser.parse(formLoginElt, pc);
|
||||
parser.parse(formLoginElt, parserContext);
|
||||
formLoginFilter = parser.getFilterBean();
|
||||
formLoginEntryPoint = parser.getEntryPointBean();
|
||||
formLoginPage = parser.getLoginPage();
|
||||
@@ -374,7 +306,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
|
||||
"org.springframework.security.ui.openid.OpenIDAuthenticationProcessingFilter");
|
||||
|
||||
parser.parse(openIDLoginElt, pc);
|
||||
parser.parse(openIDLoginElt, parserContext);
|
||||
openIDFilter = parser.getFilterBean();
|
||||
openIDEntryPoint = parser.getEntryPointBean();
|
||||
openIDLoginPage = parser.getLoginPage();
|
||||
@@ -389,28 +321,27 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
|
||||
BeanDefinition openIDProvider = openIDProviderBuilder.getBeanDefinition();
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_PROVIDER, openIDProvider);
|
||||
ConfigUtils.getRegisteredProviders(pc).add(new RuntimeBeanReference(BeanIds.OPEN_ID_PROVIDER));
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(openIDProvider);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_PROVIDER, openIDProvider);
|
||||
}
|
||||
|
||||
boolean needLoginPage = false;
|
||||
if (formLoginFilter == null && openIDFilter == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (formLoginFilter != null) {
|
||||
needLoginPage = true;
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, formLoginFilter);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, formLoginEntryPoint);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, formLoginFilter);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, formLoginEntryPoint);
|
||||
}
|
||||
|
||||
if (openIDFilter != null) {
|
||||
needLoginPage = true;
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_FILTER, openIDFilter);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_ENTRY_POINT, openIDEntryPoint);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_FILTER, openIDFilter);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_ENTRY_POINT, openIDEntryPoint);
|
||||
}
|
||||
|
||||
// If no login page has been defined, add in the default page generator.
|
||||
if (needLoginPage && formLoginPage == null && openIDLoginPage == null) {
|
||||
if (formLoginPage == null && openIDLoginPage == null) {
|
||||
logger.info("No login page configured. The default internal one will be used. Use the '"
|
||||
+ FormLoginBeanDefinitionParser.ATT_LOGIN_PAGE + "' attribute to set the URL of the login page.");
|
||||
BeanDefinitionBuilder loginPageFilter =
|
||||
@@ -424,9 +355,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
loginPageFilter.addConstructorArg(new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
|
||||
}
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER,
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER,
|
||||
loginPageFilter.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER));
|
||||
}
|
||||
|
||||
// We need to establish the main entry point.
|
||||
@@ -434,39 +364,30 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
String customEntryPoint = element.getAttribute(ATT_ENTRY_POINT_REF);
|
||||
|
||||
if (StringUtils.hasText(customEntryPoint)) {
|
||||
pc.getRegistry().registerAlias(customEntryPoint, BeanIds.MAIN_ENTRY_POINT);
|
||||
parserContext.getRegistry().registerAlias(customEntryPoint, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
// Basic takes precedence if explicit element is used and no others are configured
|
||||
if (basicAuthElt != null && formLoginElt == null && openIDLoginElt == null) {
|
||||
pc.getRegistry().registerAlias(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
parserContext.getRegistry().registerAlias(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
// If formLogin has been enabled either through an element or auto-config, then it is used if no openID login page
|
||||
// has been set
|
||||
if (formLoginFilter != null && openIDLoginPage == null) {
|
||||
pc.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
parserContext.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise use OpenID if enabled
|
||||
// Otherwise use OpenID
|
||||
if (openIDFilter != null && formLoginFilter == null) {
|
||||
pc.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
parserContext.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
// If X.509 has been enabled, use the preauth entry point.
|
||||
if (DomUtils.getChildElementByTagName(element, Elements.X509) != null) {
|
||||
pc.getRegistry().registerAlias(BeanIds.PRE_AUTH_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
pc.getReaderContext().error("No AuthenticationEntryPoint could be established. Please " +
|
||||
"make sure you have a login mechanism configured through the namespace (such as form-login) or " +
|
||||
"specify a custom AuthenticationEntryPoint with the custom-entry-point-ref attribute ",
|
||||
pc.extractSource(element));
|
||||
throw new IllegalStateException("Couldn't set entry point");
|
||||
}
|
||||
|
||||
static UrlMatcher createUrlMatcher(Element element) {
|
||||
@@ -561,9 +482,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
}
|
||||
|
||||
static LinkedHashMap parseInterceptUrlsForFilterInvocationRequestMap(List urlElts, boolean useLowerCasePaths, ParserContext parserContext) {
|
||||
LinkedHashMap filterInvocationDefinitionMap = new LinkedHashMap();
|
||||
|
||||
static void parseInterceptUrlsForFilterInvocationRequestMap(List urlElts, Map filterInvocationDefinitionMap,
|
||||
boolean useLowerCasePaths, ParserContext parserContext) {
|
||||
|
||||
Iterator urlEltsIterator = urlElts.iterator();
|
||||
ConfigAttributeEditor editor = new ConfigAttributeEditor();
|
||||
|
||||
@@ -593,8 +514,6 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
filterInvocationDefinitionMap.put(new RequestKey(path, method), editor.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
return filterInvocationDefinitionMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+288
@@ -0,0 +1,288 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.concurrent.ConcurrentSessionFilter;
|
||||
import org.springframework.security.context.HttpSessionContextIntegrationFilter;
|
||||
import org.springframework.security.ui.AbstractProcessingFilter;
|
||||
import org.springframework.security.ui.AuthenticationEntryPoint;
|
||||
import org.springframework.security.ui.basicauth.BasicProcessingFilter;
|
||||
import org.springframework.security.ui.rememberme.RememberMeServices;
|
||||
import org.springframework.security.userdetails.UserDetailsByNameServiceWrapper;
|
||||
import org.springframework.security.util.FilterChainProxy;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Responsible for tying up the HTTP security configuration - building ordered filter stack and linking up
|
||||
* with other beans.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
*/
|
||||
public class HttpSecurityConfigPostProcessor implements BeanFactoryPostProcessor, Ordered {
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
injectUserDetailsServiceIntoRememberMeServices(beanFactory);
|
||||
injectUserDetailsServiceIntoX509Provider(beanFactory);
|
||||
injectUserDetailsServiceIntoOpenIDProvider(beanFactory);
|
||||
|
||||
injectAuthenticationEntryPointIntoExceptionTranslationFilter(beanFactory);
|
||||
|
||||
injectRememberMeServicesIntoFiltersRequiringIt(beanFactory);
|
||||
|
||||
configureFilterChain(beanFactory);
|
||||
}
|
||||
|
||||
private void injectUserDetailsServiceIntoRememberMeServices(ConfigurableListableBeanFactory bf) {
|
||||
try {
|
||||
BeanDefinition rememberMeServices = bf.getBeanDefinition(BeanIds.REMEMBER_ME_SERVICES);
|
||||
PropertyValue pv = rememberMeServices.getPropertyValues().getPropertyValue("userDetailsService");
|
||||
|
||||
if (pv == null) {
|
||||
rememberMeServices.getPropertyValues().addPropertyValue("userDetailsService",
|
||||
ConfigUtils.getUserDetailsService(bf));
|
||||
} else {
|
||||
RuntimeBeanReference cachingUserService = getCachingUserService(bf, pv.getValue());
|
||||
|
||||
if (cachingUserService != null) {
|
||||
rememberMeServices.getPropertyValues().addPropertyValue("userDetailsService", cachingUserService);
|
||||
}
|
||||
}
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private void injectUserDetailsServiceIntoX509Provider(ConfigurableListableBeanFactory bf) {
|
||||
try {
|
||||
BeanDefinition x509AuthProvider = bf.getBeanDefinition(BeanIds.X509_AUTH_PROVIDER);
|
||||
PropertyValue pv = x509AuthProvider.getPropertyValues().getPropertyValue("preAuthenticatedUserDetailsService");
|
||||
|
||||
if (pv == null) {
|
||||
UserDetailsByNameServiceWrapper preAuthUserService = new UserDetailsByNameServiceWrapper();
|
||||
preAuthUserService.setUserDetailsService(ConfigUtils.getUserDetailsService(bf));
|
||||
x509AuthProvider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService",
|
||||
preAuthUserService);
|
||||
} else {
|
||||
RootBeanDefinition preAuthUserService = (RootBeanDefinition) pv.getValue();
|
||||
Object userService =
|
||||
preAuthUserService.getPropertyValues().getPropertyValue("userDetailsService").getValue();
|
||||
|
||||
RuntimeBeanReference cachingUserService = getCachingUserService(bf, userService);
|
||||
|
||||
if (cachingUserService != null) {
|
||||
preAuthUserService.getPropertyValues().addPropertyValue("userDetailsService", cachingUserService);
|
||||
}
|
||||
}
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private void injectUserDetailsServiceIntoOpenIDProvider(ConfigurableListableBeanFactory beanFactory) {
|
||||
try {
|
||||
BeanDefinition openIDProvider = beanFactory.getBeanDefinition(BeanIds.OPEN_ID_PROVIDER);
|
||||
PropertyValue pv = openIDProvider.getPropertyValues().getPropertyValue("userDetailsService");
|
||||
|
||||
if (pv == null) {
|
||||
openIDProvider.getPropertyValues().addPropertyValue("userDetailsService",
|
||||
ConfigUtils.getUserDetailsService(beanFactory));
|
||||
}
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private RuntimeBeanReference getCachingUserService(ConfigurableListableBeanFactory bf, Object userServiceRef) {
|
||||
Assert.isInstanceOf(RuntimeBeanReference.class, userServiceRef,
|
||||
"userDetailsService property value must be a RuntimeBeanReference");
|
||||
|
||||
String id = ((RuntimeBeanReference)userServiceRef).getBeanName();
|
||||
// Overwrite with the caching version if available
|
||||
String cachingId = id + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX;
|
||||
|
||||
if (bf.containsBeanDefinition(cachingId)) {
|
||||
return new RuntimeBeanReference(cachingId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the remember-me services, if required, on any instances of AbstractProcessingFilter and
|
||||
* BasicProcessingFilter.
|
||||
*/
|
||||
private void injectRememberMeServicesIntoFiltersRequiringIt(ConfigurableListableBeanFactory beanFactory) {
|
||||
Map beans = beanFactory.getBeansOfType(RememberMeServices.class);
|
||||
|
||||
RememberMeServices rememberMeServices = null;
|
||||
|
||||
if(beans.size() == 0) {
|
||||
logger.debug("No RememberMeServices configured");
|
||||
return;
|
||||
}
|
||||
|
||||
if (beans.size() == 1) {
|
||||
rememberMeServices = (RememberMeServices) beans.values().toArray()[0];
|
||||
} else {
|
||||
throw new SecurityConfigurationException("More than one RememberMeServices bean found.");
|
||||
}
|
||||
|
||||
if (rememberMeServices == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Address AbstractProcessingFilter instances
|
||||
Iterator filters = beanFactory.getBeansOfType(AbstractProcessingFilter.class).values().iterator();
|
||||
|
||||
while (filters.hasNext()) {
|
||||
AbstractProcessingFilter filter = (AbstractProcessingFilter) filters.next();
|
||||
|
||||
logger.info("Using RememberMeServices " + rememberMeServices + " with filter " + filter);
|
||||
filter.setRememberMeServices(rememberMeServices);
|
||||
}
|
||||
|
||||
// Address BasicProcessingFilter instance, if it exists
|
||||
// NB: For remember-me to be sent back, a user must submit a "_spring_security_remember_me" with their login request.
|
||||
// Most of the time a user won't present such a parameter with their BASIC authentication request.
|
||||
// In the future we might support setting the AbstractRememberMeServices.alwaysRemember = true, but I am reluctant to
|
||||
// do so because it seems likely to lead to lower security for 99.99% of users if they set the property to true.
|
||||
if (beanFactory.containsBean(BeanIds.BASIC_AUTHENTICATION_FILTER)) {
|
||||
BasicProcessingFilter filter = (BasicProcessingFilter) beanFactory.getBean(BeanIds.BASIC_AUTHENTICATION_FILTER);
|
||||
|
||||
logger.info("Using RememberMeServices " + rememberMeServices + " with filter " + filter);
|
||||
filter.setRememberMeServices(rememberMeServices);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the entry point that should be used in ExceptionTranslationFilter. Strategy is
|
||||
*
|
||||
* <ol>
|
||||
* <li>If only one, use that one.</li>
|
||||
* <li>If more than one, use the form login entry point (if form login is being used), then try basic</li>
|
||||
* <li>If still null, throw an exception (for now).</li>
|
||||
* </ol>
|
||||
*
|
||||
*/
|
||||
private void injectAuthenticationEntryPointIntoExceptionTranslationFilter(ConfigurableListableBeanFactory beanFactory) {
|
||||
logger.info("Selecting AuthenticationEntryPoint for use in ExceptionTranslationFilter");
|
||||
|
||||
BeanDefinition etf =
|
||||
beanFactory.getBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER);
|
||||
Map entryPointMap = beanFactory.getBeansOfType(AuthenticationEntryPoint.class);
|
||||
List entryPoints = new ArrayList(entryPointMap.values());
|
||||
|
||||
Assert.isTrue(entryPoints.size() > 0, "No AuthenticationEntryPoint instances defined");
|
||||
|
||||
AuthenticationEntryPoint mainEntryPoint;
|
||||
|
||||
if (entryPoints.size() == 1) {
|
||||
mainEntryPoint = (AuthenticationEntryPoint) entryPoints.get(0);
|
||||
} else {
|
||||
mainEntryPoint = (AuthenticationEntryPoint) beanFactory.getBean(BeanIds.MAIN_ENTRY_POINT);
|
||||
|
||||
if (mainEntryPoint == null) {
|
||||
mainEntryPoint = (AuthenticationEntryPoint) entryPointMap.get(BeanIds.FORM_LOGIN_ENTRY_POINT);
|
||||
}
|
||||
|
||||
if (mainEntryPoint == null) {
|
||||
mainEntryPoint = (AuthenticationEntryPoint) entryPointMap.get(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT);
|
||||
if (mainEntryPoint == null) {
|
||||
throw new SecurityConfigurationException("Failed to resolve authentication entry point");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Main AuthenticationEntryPoint set to " + mainEntryPoint);
|
||||
|
||||
etf.getPropertyValues().addPropertyValue("authenticationEntryPoint", mainEntryPoint);
|
||||
}
|
||||
|
||||
private void configureFilterChain(ConfigurableListableBeanFactory beanFactory) {
|
||||
FilterChainProxy filterChainProxy =
|
||||
(FilterChainProxy) beanFactory.getBean(BeanIds.FILTER_CHAIN_PROXY);
|
||||
// Set the default match
|
||||
List defaultFilterChain = orderFilters(beanFactory);
|
||||
|
||||
// Note that this returns a copy
|
||||
Map filterMap = filterChainProxy.getFilterChainMap();
|
||||
|
||||
String allUrlsMatch = filterChainProxy.getMatcher().getUniversalMatchPattern();
|
||||
|
||||
filterMap.put(allUrlsMatch, defaultFilterChain);
|
||||
|
||||
filterChainProxy.setFilterChainMap(filterMap);
|
||||
|
||||
Map sessionFilters = beanFactory.getBeansOfType(ConcurrentSessionFilter.class);
|
||||
|
||||
if (!sessionFilters.isEmpty()) {
|
||||
logger.info("Concurrent session filter in use, setting 'forceEagerSessionCreation' to true");
|
||||
HttpSessionContextIntegrationFilter scif = (HttpSessionContextIntegrationFilter)
|
||||
beanFactory.getBean(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER);
|
||||
scif.setForceEagerSessionCreation(true);
|
||||
}
|
||||
|
||||
logger.info("Configured filter chain(s): " + filterChainProxy);
|
||||
}
|
||||
|
||||
private List orderFilters(ConfigurableListableBeanFactory beanFactory) {
|
||||
Map filters = beanFactory.getBeansOfType(Filter.class);
|
||||
|
||||
Assert.notEmpty(filters, "No filters found in app context!");
|
||||
|
||||
Iterator ids = filters.keySet().iterator();
|
||||
|
||||
List orderedFilters = new ArrayList();
|
||||
|
||||
while (ids.hasNext()) {
|
||||
String id = (String) ids.next();
|
||||
Filter filter = (Filter) filters.get(id);
|
||||
|
||||
if (filter instanceof FilterChainProxy) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Filters must be Spring security filters or wrapped using <custom-filter>
|
||||
if (!filter.getClass().getName().startsWith("org.springframework.security")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(filter instanceof Ordered)) {
|
||||
logger.info("Filter " + id + " doesn't implement the Ordered interface, skipping it.");
|
||||
continue;
|
||||
}
|
||||
|
||||
orderedFilters.add(filter);
|
||||
}
|
||||
|
||||
Collections.sort(orderedFilters, new OrderComparator());
|
||||
|
||||
return orderedFilters;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return HIGHEST_PRECEDENCE + 1;
|
||||
}
|
||||
}
|
||||
+9
-32
@@ -1,8 +1,9 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.security.userdetails.jdbc.JdbcUserDetailsManager;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
@@ -12,45 +13,21 @@ import org.w3c.dom.Element;
|
||||
*/
|
||||
public class JdbcUserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser {
|
||||
static final String ATT_DATA_SOURCE = "data-source-ref";
|
||||
static final String ATT_USERS_BY_USERNAME_QUERY = "users-by-username-query";
|
||||
static final String ATT_AUTHORITIES_BY_USERNAME_QUERY = "authorities-by-username-query";
|
||||
static final String ATT_GROUP_AUTHORITIES_QUERY = "group-authorities-by-username-query";
|
||||
static final String ATT_ROLE_PREFIX = "role-prefix";
|
||||
|
||||
protected String getBeanClassName(Element element) {
|
||||
return "org.springframework.security.userdetails.jdbc.JdbcUserDetailsManager";
|
||||
protected Class getBeanClass(Element element) {
|
||||
return JdbcUserDetailsManager.class;
|
||||
}
|
||||
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
// TODO: Set authenticationManager property
|
||||
String dataSource = element.getAttribute(ATT_DATA_SOURCE);
|
||||
|
||||
// An explicit dataSource was specified, so use it
|
||||
if (dataSource != null) {
|
||||
builder.addPropertyReference("dataSource", dataSource);
|
||||
} else {
|
||||
parserContext.getReaderContext().error(ATT_DATA_SOURCE + " is required for "
|
||||
+ Elements.JDBC_USER_SERVICE, parserContext.extractSource(element));
|
||||
}
|
||||
|
||||
String usersQuery = element.getAttribute(ATT_USERS_BY_USERNAME_QUERY);
|
||||
String authoritiesQuery = element.getAttribute(ATT_AUTHORITIES_BY_USERNAME_QUERY);
|
||||
String groupAuthoritiesQuery = element.getAttribute(ATT_GROUP_AUTHORITIES_QUERY);
|
||||
String rolePrefix = element.getAttribute(ATT_ROLE_PREFIX);
|
||||
|
||||
if (StringUtils.hasText(rolePrefix)) {
|
||||
builder.addPropertyValue("rolePrefix", rolePrefix);
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(usersQuery)) {
|
||||
builder.addPropertyValue("usersByUsernameQuery", usersQuery);
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(authoritiesQuery)) {
|
||||
builder.addPropertyValue("authoritiesByUsernameQuery", authoritiesQuery);
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(groupAuthoritiesQuery)) {
|
||||
builder.addPropertyValue("enableGroups", Boolean.TRUE);
|
||||
builder.addPropertyValue("authoritiesByUsernameQuery", groupAuthoritiesQuery);
|
||||
// TODO: Have some sensible fallback if dataSource not specified, eg autowire
|
||||
throw new BeanDefinitionStoreException(ATT_DATA_SOURCE + " is required for "
|
||||
+ Elements.JDBC_USER_SERVICE );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.security.ldap.SpringSecurityContextSource;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.ldap.SpringSecurityContextSource;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
@@ -16,56 +17,35 @@ import org.springframework.security.ldap.SpringSecurityContextSource;
|
||||
*/
|
||||
class LdapConfigUtils {
|
||||
|
||||
/**
|
||||
* Checks for the presence of a ContextSource instance. Also supplies the standard reference to any
|
||||
* unconfigured <ldap-authentication-provider> or <ldap-user-service> beans. This is
|
||||
* necessary in cases where the user has given the server a specific Id, but hasn't used
|
||||
* the server-ref attribute to link this to the other ldap definitions. See SEC-799.
|
||||
*/
|
||||
/** Checks for the presence of a ContextSource instance */
|
||||
private static class ContextSourceSettingPostProcessor implements BeanFactoryPostProcessor, Ordered {
|
||||
/** If set to true, a bean parser has indicated that the default context source name needs to be set */
|
||||
private boolean defaultNameRequired;
|
||||
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) throws BeansException {
|
||||
String[] sources = bf.getBeanNamesForType(SpringSecurityContextSource.class);
|
||||
Map beans = bf.getBeansOfType(SpringSecurityContextSource.class);
|
||||
|
||||
if (sources.length == 0) {
|
||||
if (beans.size() == 0) {
|
||||
throw new SecurityConfigurationException("No SpringSecurityContextSource instances found. Have you " +
|
||||
"added an <" + Elements.LDAP_SERVER + " /> element to your application context?");
|
||||
}
|
||||
|
||||
if (!bf.containsBean(BeanIds.CONTEXT_SOURCE) && defaultNameRequired) {
|
||||
if (sources.length > 1) {
|
||||
throw new SecurityConfigurationException("More than one SpringSecurityContextSource instance found. " +
|
||||
"Please specify a specific server id using the 'server-ref' attribute when configuring your <" +
|
||||
Elements.LDAP_PROVIDER + "> " + "or <" + Elements.LDAP_USER_SERVICE + ">.");
|
||||
}
|
||||
|
||||
bf.registerAlias(sources[0], BeanIds.CONTEXT_SOURCE);
|
||||
}
|
||||
}
|
||||
|
||||
public void setDefaultNameRequired(boolean defaultNameRequired) {
|
||||
this.defaultNameRequired = defaultNameRequired;
|
||||
|
||||
// else if (beans.size() > 1) {
|
||||
// throw new SecurityConfigurationException("More than one SpringSecurityContextSource instance found. " +
|
||||
// "Please specify a specific server id when configuring your <" + Elements.LDAP_PROVIDER + "> " +
|
||||
// "or <" + Elements.LDAP_USER_SERVICE + ">.");
|
||||
// }
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return LOWEST_PRECEDENCE;
|
||||
}
|
||||
}
|
||||
|
||||
static void registerPostProcessorIfNecessary(BeanDefinitionRegistry registry, boolean defaultNameRequired) {
|
||||
|
||||
static void registerPostProcessorIfNecessary(BeanDefinitionRegistry registry) {
|
||||
if (registry.containsBeanDefinition(BeanIds.CONTEXT_SOURCE_SETTING_POST_PROCESSOR)) {
|
||||
if (defaultNameRequired) {
|
||||
BeanDefinition bd = registry.getBeanDefinition(BeanIds.CONTEXT_SOURCE_SETTING_POST_PROCESSOR);
|
||||
bd.getPropertyValues().addPropertyValue("defaultNameRequired", Boolean.valueOf(defaultNameRequired));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
BeanDefinition bd = new RootBeanDefinition(ContextSourceSettingPostProcessor.class);
|
||||
registry.registerBeanDefinition(BeanIds.CONTEXT_SOURCE_SETTING_POST_PROCESSOR, bd);
|
||||
bd.getPropertyValues().addPropertyValue("defaultNameRequired", Boolean.valueOf(defaultNameRequired));
|
||||
registry.registerBeanDefinition(BeanIds.CONTEXT_SOURCE_SETTING_POST_PROCESSOR,
|
||||
new RootBeanDefinition(ContextSourceSettingPostProcessor.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+27
-42
@@ -1,8 +1,11 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
|
||||
import org.springframework.security.providers.ldap.LdapAuthenticationProvider;
|
||||
import org.springframework.security.providers.ldap.authenticator.BindAuthenticator;
|
||||
import org.springframework.security.providers.ldap.authenticator.PasswordComparisonAuthenticator;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
@@ -24,19 +27,14 @@ public class LdapProviderBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private static final String ATT_USER_DN_PATTERN = "user-dn-pattern";
|
||||
private static final String ATT_USER_PASSWORD = "password-attribute";
|
||||
private static final String ATT_HASH = PasswordEncoderParser.ATT_HASH;
|
||||
private static final String ATT_USER_PASSWORD= "password-attribute";
|
||||
|
||||
private static final String DEF_USER_SEARCH_FILTER = "uid={0}";
|
||||
|
||||
private static final String PROVIDER_CLASS = "org.springframework.security.providers.ldap.LdapAuthenticationProvider";
|
||||
private static final String BIND_AUTH_CLASS = "org.springframework.security.providers.ldap.authenticator.BindAuthenticator";
|
||||
private static final String PASSWD_AUTH_CLASS = "org.springframework.security.providers.ldap.authenticator.PasswordComparisonAuthenticator";
|
||||
private static final String DEF_USER_SEARCH_FILTER="uid={0}";
|
||||
|
||||
public BeanDefinition parse(Element elt, ParserContext parserContext) {
|
||||
RuntimeBeanReference contextSource = LdapUserServiceBeanDefinitionParser.parseServerReference(elt, parserContext);
|
||||
|
||||
BeanDefinition searchBean = LdapUserServiceBeanDefinitionParser.parseSearchBean(elt, parserContext);
|
||||
RootBeanDefinition searchBean = LdapUserServiceBeanDefinitionParser.parseSearchBean(elt, parserContext);
|
||||
String userDnPattern = elt.getAttribute(ATT_USER_DN_PATTERN);
|
||||
|
||||
String[] userDnPatternArray = new String[0];
|
||||
@@ -46,62 +44,49 @@ public class LdapProviderBeanDefinitionParser implements BeanDefinitionParser {
|
||||
// TODO: Validate the pattern and make sure it is a valid DN.
|
||||
} else if (searchBean == null) {
|
||||
logger.info("No search information or DN pattern specified. Using default search filter '" + DEF_USER_SEARCH_FILTER + "'");
|
||||
BeanDefinitionBuilder searchBeanBuilder = BeanDefinitionBuilder.rootBeanDefinition(LdapUserServiceBeanDefinitionParser.LDAP_SEARCH_CLASS);
|
||||
searchBeanBuilder.setSource(elt);
|
||||
searchBeanBuilder.addConstructorArg("");
|
||||
searchBeanBuilder.addConstructorArg(DEF_USER_SEARCH_FILTER);
|
||||
searchBeanBuilder.addConstructorArg(contextSource);
|
||||
searchBean = searchBeanBuilder.getBeanDefinition();
|
||||
searchBean = new RootBeanDefinition(FilterBasedLdapUserSearch.class);
|
||||
searchBean.setSource(elt);
|
||||
searchBean.getConstructorArgumentValues().addIndexedArgumentValue(0, "");
|
||||
searchBean.getConstructorArgumentValues().addIndexedArgumentValue(1, DEF_USER_SEARCH_FILTER);
|
||||
searchBean.getConstructorArgumentValues().addIndexedArgumentValue(2, contextSource);
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder authenticatorBuilder =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(BIND_AUTH_CLASS);
|
||||
RootBeanDefinition authenticator = new RootBeanDefinition(BindAuthenticator.class);
|
||||
Element passwordCompareElt = DomUtils.getChildElementByTagName(elt, Elements.LDAP_PASSWORD_COMPARE);
|
||||
|
||||
if (passwordCompareElt != null) {
|
||||
authenticatorBuilder =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(PASSWD_AUTH_CLASS);
|
||||
authenticator = new RootBeanDefinition(PasswordComparisonAuthenticator.class);
|
||||
|
||||
String passwordAttribute = passwordCompareElt.getAttribute(ATT_USER_PASSWORD);
|
||||
if (StringUtils.hasText(passwordAttribute)) {
|
||||
authenticatorBuilder.addPropertyValue("passwordAttributeName", passwordAttribute);
|
||||
authenticator.getPropertyValues().addPropertyValue("passwordAttributeName", passwordAttribute);
|
||||
}
|
||||
|
||||
Element passwordEncoderElement = DomUtils.getChildElementByTagName(passwordCompareElt, Elements.PASSWORD_ENCODER);
|
||||
String hash = passwordCompareElt.getAttribute(ATT_HASH);
|
||||
|
||||
if (passwordEncoderElement != null) {
|
||||
if (StringUtils.hasText(hash)) {
|
||||
parserContext.getReaderContext().warning("Attribute 'hash' cannot be used with 'password-encoder' and " +
|
||||
"will be ignored.", parserContext.extractSource(elt));
|
||||
}
|
||||
PasswordEncoderParser pep = new PasswordEncoderParser(passwordEncoderElement, parserContext);
|
||||
authenticatorBuilder.addPropertyValue("passwordEncoder", pep.getPasswordEncoder());
|
||||
authenticator.getPropertyValues().addPropertyValue("passwordEncoder", pep.getPasswordEncoder());
|
||||
|
||||
if (pep.getSaltSource() != null) {
|
||||
parserContext.getReaderContext().warning("Salt source information isn't valid when used with LDAP",
|
||||
passwordEncoderElement);
|
||||
parserContext.getReaderContext().warning("Salt source information isn't valid when used with LDAP", passwordEncoderElement);
|
||||
}
|
||||
} else if (StringUtils.hasText(hash)) {
|
||||
Class encoderClass = (Class) PasswordEncoderParser.ENCODER_CLASSES.get(hash);
|
||||
authenticatorBuilder.addPropertyValue("passwordEncoder", new RootBeanDefinition(encoderClass));
|
||||
}
|
||||
}
|
||||
|
||||
authenticatorBuilder.addConstructorArg(contextSource);
|
||||
authenticatorBuilder.addPropertyValue("userDnPatterns", userDnPatternArray);
|
||||
authenticator.getConstructorArgumentValues().addGenericArgumentValue(contextSource);
|
||||
authenticator.getPropertyValues().addPropertyValue("userDnPatterns", userDnPatternArray);
|
||||
|
||||
if (searchBean != null) {
|
||||
authenticatorBuilder.addPropertyValue("userSearch", searchBean);
|
||||
authenticator.getPropertyValues().addPropertyValue("userSearch", searchBean);
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder ldapProvider = BeanDefinitionBuilder.rootBeanDefinition(PROVIDER_CLASS);
|
||||
ldapProvider.addConstructorArg(authenticatorBuilder.getBeanDefinition());
|
||||
ldapProvider.addConstructorArg(LdapUserServiceBeanDefinitionParser.parseAuthoritiesPopulator(elt, parserContext));
|
||||
ldapProvider.addPropertyValue("userDetailsContextMapper",
|
||||
LdapUserServiceBeanDefinitionParser.parseUserDetailsClass(elt, parserContext));
|
||||
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(ldapProvider.getBeanDefinition());
|
||||
RootBeanDefinition ldapProvider = new RootBeanDefinition(LdapAuthenticationProvider.class);
|
||||
ldapProvider.getConstructorArgumentValues().addGenericArgumentValue(authenticator);
|
||||
ldapProvider.getConstructorArgumentValues().addGenericArgumentValue(LdapUserServiceBeanDefinitionParser.parseAuthoritiesPopulator(elt, parserContext));
|
||||
|
||||
LdapConfigUtils.registerPostProcessorIfNecessary(parserContext.getRegistry());
|
||||
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(ldapProvider);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
+17
-28
@@ -1,10 +1,6 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import javax.naming.directory.Attribute;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.BasicAttribute;
|
||||
import javax.naming.directory.BasicAttributes;
|
||||
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
@@ -12,6 +8,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedSet;
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
@@ -23,9 +20,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
* @version $Id$
|
||||
*/
|
||||
public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private static final String CONTEXT_SOURCE_CLASS="org.springframework.security.ldap.DefaultSpringSecurityContextSource";
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/** Defines the Url of the ldap server to use. If not specified, an embedded apache DS instance will be created */
|
||||
private static final String ATT_URL = "url";
|
||||
@@ -58,8 +53,7 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
if (!StringUtils.hasText(url)) {
|
||||
contextSource = createEmbeddedServer(elt, parserContext);
|
||||
} else {
|
||||
contextSource = new RootBeanDefinition();
|
||||
contextSource.setBeanClassName(CONTEXT_SOURCE_CLASS);
|
||||
contextSource = new RootBeanDefinition(DefaultSpringSecurityContextSource.class);
|
||||
contextSource.getConstructorArgumentValues().addIndexedArgumentValue(0, url);
|
||||
}
|
||||
|
||||
@@ -98,22 +92,17 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
*/
|
||||
private RootBeanDefinition createEmbeddedServer(Element element, ParserContext parserContext) {
|
||||
Object source = parserContext.extractSource(element);
|
||||
BeanDefinitionBuilder configuration =
|
||||
BeanDefinitionBuilder.rootBeanDefinition("org.apache.directory.server.configuration.MutableServerStartupConfiguration");
|
||||
BeanDefinitionBuilder partition =
|
||||
BeanDefinitionBuilder.rootBeanDefinition("org.apache.directory.server.core.partition.impl.btree.MutableBTreePartitionConfiguration");
|
||||
BeanDefinitionBuilder configuration = BeanDefinitionBuilder.rootBeanDefinition("org.apache.directory.server.configuration.MutableServerStartupConfiguration");
|
||||
BeanDefinitionBuilder partition = BeanDefinitionBuilder.rootBeanDefinition("org.apache.directory.server.core.partition.impl.btree.MutableBTreePartitionConfiguration");
|
||||
configuration.setSource(source);
|
||||
partition.setSource(source);
|
||||
|
||||
Attributes rootAttributes = new BasicAttributes("dc", "springsecurity");
|
||||
Attribute a = new BasicAttribute("objectClass");
|
||||
a.add("top");
|
||||
a.add("domain");
|
||||
a.add("extensibleObject");
|
||||
rootAttributes.put(a);
|
||||
|
||||
DirContextAdapter rootContext = new DirContextAdapter();
|
||||
rootContext.setAttributeValues("objectClass", new String[] {"top", "domain", "extensibleObject"});
|
||||
rootContext.setAttributeValue("dc", "springsecurity");
|
||||
|
||||
partition.addPropertyValue("name", "springsecurity");
|
||||
partition.addPropertyValue("contextEntry", rootAttributes);
|
||||
partition.addPropertyValue("contextEntry", rootContext.getAttributes());
|
||||
|
||||
String suffix = element.getAttribute(ATT_ROOT_SUFFIX);
|
||||
|
||||
@@ -142,15 +131,15 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
String url = "ldap://127.0.0.1:" + port + "/" + suffix;
|
||||
|
||||
BeanDefinitionBuilder contextSource = BeanDefinitionBuilder.rootBeanDefinition(CONTEXT_SOURCE_CLASS);
|
||||
contextSource.addConstructorArg(url);
|
||||
contextSource.addPropertyValue("userDn", "uid=admin,ou=system");
|
||||
contextSource.addPropertyValue("password", "secret");
|
||||
RootBeanDefinition contextSource = new RootBeanDefinition(DefaultSpringSecurityContextSource.class);
|
||||
contextSource.getConstructorArgumentValues().addIndexedArgumentValue(0, url);
|
||||
contextSource.getPropertyValues().addPropertyValue("userDn", "uid=admin,ou=system");
|
||||
contextSource.getPropertyValues().addPropertyValue("password", "secret");
|
||||
|
||||
RootBeanDefinition apacheContainer = new RootBeanDefinition("org.springframework.security.config.ApacheDSContainer", null, null);
|
||||
apacheContainer.setSource(source);
|
||||
apacheContainer.getConstructorArgumentValues().addGenericArgumentValue(configuration.getBeanDefinition());
|
||||
apacheContainer.getConstructorArgumentValues().addGenericArgumentValue(contextSource.getBeanDefinition());
|
||||
apacheContainer.getConstructorArgumentValues().addGenericArgumentValue(contextSource);
|
||||
|
||||
String ldifs = element.getAttribute(ATT_LDIF_FILE);
|
||||
if (!StringUtils.hasText(ldifs)) {
|
||||
@@ -168,6 +157,6 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.EMBEDDED_APACHE_DS, apacheContainer);
|
||||
|
||||
return (RootBeanDefinition) contextSource.getBeanDefinition();
|
||||
return contextSource;
|
||||
}
|
||||
}
|
||||
|
||||
+22
-52
@@ -1,5 +1,8 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.security.userdetails.ldap.LdapUserDetailsService;
|
||||
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
|
||||
import org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
@@ -14,7 +17,7 @@ import org.w3c.dom.Element;
|
||||
* @since 2.0
|
||||
*/
|
||||
public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser {
|
||||
public static final String ATT_SERVER = "server-ref";
|
||||
public static final String ATT_SERVER = "server-ref";
|
||||
public static final String ATT_USER_SEARCH_FILTER = "user-search-filter";
|
||||
public static final String ATT_USER_SEARCH_BASE = "user-search-base";
|
||||
public static final String DEF_USER_SEARCH_BASE = "";
|
||||
@@ -24,20 +27,9 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
public static final String ATT_GROUP_ROLE_ATTRIBUTE = "group-role-attribute";
|
||||
public static final String DEF_GROUP_SEARCH_FILTER = "(uniqueMember={0})";
|
||||
public static final String DEF_GROUP_SEARCH_BASE = "ou=groups";
|
||||
|
||||
static final String ATT_ROLE_PREFIX = "role-prefix";
|
||||
static final String ATT_USER_CLASS = "user-details-class";
|
||||
static final String OPT_PERSON = "person";
|
||||
static final String OPT_INETORGPERSON = "inetOrgPerson";
|
||||
|
||||
public static final String LDAP_SEARCH_CLASS = "org.springframework.security.ldap.search.FilterBasedLdapUserSearch";
|
||||
public static final String PERSON_MAPPER_CLASS = "org.springframework.security.userdetails.ldap.PersonContextMapper";
|
||||
public static final String INET_ORG_PERSON_MAPPER_CLASS = "org.springframework.security.userdetails.ldap.InetOrgPersonContextMapper";
|
||||
public static final String LDAP_USER_MAPPER_CLASS = "org.springframework.security.userdetails.ldap.LdapUserDetailsMapper";
|
||||
public static final String LDAP_AUTHORITIES_POPULATOR_CLASS = "org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator";
|
||||
|
||||
protected String getBeanClassName(Element element) {
|
||||
return "org.springframework.security.userdetails.ldap.LdapUserDetailsService";
|
||||
protected Class getBeanClass(Element element) {
|
||||
return LdapUserDetailsService.class;
|
||||
}
|
||||
|
||||
protected void doParse(Element elt, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
@@ -48,7 +40,8 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
|
||||
builder.addConstructorArg(parseSearchBean(elt, parserContext));
|
||||
builder.addConstructorArg(parseAuthoritiesPopulator(elt, parserContext));
|
||||
builder.addPropertyValue("userDetailsMapper", parseUserDetailsClass(elt, parserContext));
|
||||
|
||||
LdapConfigUtils.registerPostProcessorIfNecessary(parserContext.getRegistry());
|
||||
}
|
||||
|
||||
static RootBeanDefinition parseSearchBean(Element elt, ParserContext parserContext) {
|
||||
@@ -68,48 +61,33 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
return null;
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder searchBuilder = BeanDefinitionBuilder.rootBeanDefinition(LDAP_SEARCH_CLASS);
|
||||
searchBuilder.setSource(source);
|
||||
searchBuilder.addConstructorArg(userSearchBase);
|
||||
searchBuilder.addConstructorArg(userSearchFilter);
|
||||
searchBuilder.addConstructorArg(parseServerReference(elt, parserContext));
|
||||
RootBeanDefinition search = new RootBeanDefinition(FilterBasedLdapUserSearch.class);
|
||||
search.setSource(source);
|
||||
search.getConstructorArgumentValues().addIndexedArgumentValue(0, userSearchBase);
|
||||
search.getConstructorArgumentValues().addIndexedArgumentValue(1, userSearchFilter);
|
||||
search.getConstructorArgumentValues().addIndexedArgumentValue(2, parseServerReference(elt, parserContext));
|
||||
|
||||
return (RootBeanDefinition) searchBuilder.getBeanDefinition();
|
||||
return search;
|
||||
}
|
||||
|
||||
static RuntimeBeanReference parseServerReference(Element elt, ParserContext parserContext) {
|
||||
String server = elt.getAttribute(ATT_SERVER);
|
||||
boolean requiresDefaultName = false;
|
||||
|
||||
|
||||
if (!StringUtils.hasText(server)) {
|
||||
server = BeanIds.CONTEXT_SOURCE;
|
||||
requiresDefaultName = true;
|
||||
}
|
||||
|
||||
RuntimeBeanReference contextSource = new RuntimeBeanReference(server);
|
||||
contextSource.setSource(parserContext.extractSource(elt));
|
||||
LdapConfigUtils.registerPostProcessorIfNecessary(parserContext.getRegistry(), requiresDefaultName);
|
||||
|
||||
return contextSource;
|
||||
}
|
||||
|
||||
static RootBeanDefinition parseUserDetailsClass(Element elt, ParserContext parserContext) {
|
||||
String userDetailsClass = elt.getAttribute(ATT_USER_CLASS);
|
||||
|
||||
if (OPT_PERSON.equals(userDetailsClass)) {
|
||||
return new RootBeanDefinition(PERSON_MAPPER_CLASS, null, null);
|
||||
} else if (OPT_INETORGPERSON.equals(userDetailsClass)) {
|
||||
return new RootBeanDefinition(INET_ORG_PERSON_MAPPER_CLASS, null, null);
|
||||
}
|
||||
return new RootBeanDefinition(LDAP_USER_MAPPER_CLASS, null, null);
|
||||
}
|
||||
|
||||
static RootBeanDefinition parseAuthoritiesPopulator(Element elt, ParserContext parserContext) {
|
||||
String groupSearchFilter = elt.getAttribute(ATT_GROUP_SEARCH_FILTER);
|
||||
String groupSearchBase = elt.getAttribute(ATT_GROUP_SEARCH_BASE);
|
||||
String groupRoleAttribute = elt.getAttribute(ATT_GROUP_ROLE_ATTRIBUTE);
|
||||
String rolePrefix = elt.getAttribute(ATT_ROLE_PREFIX);
|
||||
|
||||
|
||||
if (!StringUtils.hasText(groupSearchFilter)) {
|
||||
groupSearchFilter = DEF_GROUP_SEARCH_FILTER;
|
||||
}
|
||||
@@ -118,24 +96,16 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
groupSearchBase = DEF_GROUP_SEARCH_BASE;
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder populator = BeanDefinitionBuilder.rootBeanDefinition(LDAP_AUTHORITIES_POPULATOR_CLASS);
|
||||
RootBeanDefinition populator = new RootBeanDefinition(DefaultLdapAuthoritiesPopulator.class);
|
||||
populator.setSource(parserContext.extractSource(elt));
|
||||
populator.addConstructorArg(parseServerReference(elt, parserContext));
|
||||
populator.addConstructorArg(groupSearchBase);
|
||||
populator.addPropertyValue("groupSearchFilter", groupSearchFilter);
|
||||
populator.addPropertyValue("searchSubtree", Boolean.TRUE);
|
||||
|
||||
if (StringUtils.hasText(rolePrefix)) {
|
||||
if ("none".equals(rolePrefix)) {
|
||||
rolePrefix = "";
|
||||
}
|
||||
populator.addPropertyValue("rolePrefix", rolePrefix);
|
||||
}
|
||||
populator.getConstructorArgumentValues().addIndexedArgumentValue(0, parseServerReference(elt, parserContext));
|
||||
populator.getConstructorArgumentValues().addIndexedArgumentValue(1, groupSearchBase);
|
||||
populator.getPropertyValues().addPropertyValue("groupSearchFilter", groupSearchFilter);
|
||||
|
||||
if (StringUtils.hasLength(groupRoleAttribute)) {
|
||||
populator.addPropertyValue("groupRoleAttribute", groupRoleAttribute);
|
||||
populator.getPropertyValues().addPropertyValue("groupRoleAttribute", groupRoleAttribute);
|
||||
}
|
||||
|
||||
return (RootBeanDefinition) populator.getBeanDefinition();
|
||||
return populator;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-8
@@ -31,18 +31,15 @@ public class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||
String logoutSuccessUrl = null;
|
||||
String invalidateSession = null;
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(LogoutFilter.class);
|
||||
|
||||
if (element != null) {
|
||||
Object source = parserContext.extractSource(element);
|
||||
builder.setSource(source);
|
||||
logoutUrl = element.getAttribute(ATT_LOGOUT_URL);
|
||||
ConfigUtils.validateHttpRedirect(logoutUrl, parserContext, source);
|
||||
logoutSuccessUrl = element.getAttribute(ATT_LOGOUT_SUCCESS_URL);
|
||||
ConfigUtils.validateHttpRedirect(logoutSuccessUrl, parserContext, source);
|
||||
invalidateSession = element.getAttribute(ATT_INVALIDATE_SESSION);
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(LogoutFilter.class);
|
||||
builder.setSource(parserContext.extractSource(element));
|
||||
|
||||
if (!StringUtils.hasText(logoutUrl)) {
|
||||
logoutUrl = DEF_LOGOUT_URL;
|
||||
}
|
||||
@@ -73,8 +70,7 @@ public class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||
builder.addConstructorArg(handlers);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.LOGOUT_FILTER, builder.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.LOGOUT_FILTER));
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.security.AfterInvocationManager;
|
||||
import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor;
|
||||
|
||||
/**
|
||||
* BeanPostProcessor which sets the AfterInvocationManager on the default MethodSecurityInterceptor,
|
||||
* if one has been configured.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*
|
||||
*/
|
||||
public class MethodSecurityInterceptorPostProcessor implements BeanPostProcessor, BeanFactoryAware{
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if(!BeanIds.METHOD_SECURITY_INTERCEPTOR.equals(beanName)) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
MethodSecurityInterceptor interceptor = (MethodSecurityInterceptor) bean;
|
||||
|
||||
if (beanFactory.containsBean(BeanIds.AFTER_INVOCATION_MANAGER)) {
|
||||
logger.debug("Setting AfterInvocationManaer on MethodSecurityInterceptor");
|
||||
interceptor.setAfterInvocationManager((AfterInvocationManager)
|
||||
beanFactory.getBean(BeanIds.AFTER_INVOCATION_MANAGER));
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
}
|
||||
+20
-40
@@ -1,29 +1,29 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.springframework.security.ui.FilterChainOrder;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.ui.FilterChainOrder;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import javax.servlet.FilterChain;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Adds the decorated "Filter" bean into the standard filter chain maintained by the FilterChainProxy.
|
||||
* This allows user to add their own custom filters to the security chain. If the user's filter
|
||||
* Replaces a Spring bean of type "Filter" with a wrapper class which implements the <tt>Ordered</tt>
|
||||
* interface. This allows user to add their own filter to the security chain. If the user's filter
|
||||
* already implements Ordered, and no "order" attribute is specified, the filter's default order will be used.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
@@ -33,23 +33,21 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
|
||||
|
||||
public static final String ATT_AFTER = "after";
|
||||
public static final String ATT_BEFORE = "before";
|
||||
public static final String ATT_POSITION = "position";
|
||||
|
||||
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder holder, ParserContext parserContext) {
|
||||
Element elt = (Element)node;
|
||||
String order = getOrder(elt, parserContext);
|
||||
|
||||
BeanDefinition filter = holder.getBeanDefinition();
|
||||
BeanDefinitionBuilder wrapper = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.config.OrderedFilterBeanDefinitionDecorator$OrderedFilterDecorator");
|
||||
wrapper.addConstructorArg(holder.getBeanName());
|
||||
wrapper.addConstructorArg(new RuntimeBeanReference(holder.getBeanName()));
|
||||
wrapper.addConstructorArg(filter);
|
||||
|
||||
if (StringUtils.hasText(order)) {
|
||||
wrapper.addPropertyValue("order", order);
|
||||
}
|
||||
|
||||
ConfigUtils.addHttpFilter(parserContext, wrapper.getBeanDefinition());
|
||||
|
||||
return holder;
|
||||
return new BeanDefinitionHolder(wrapper.getBeanDefinition(), holder.getBeanName());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,17 +56,7 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
|
||||
private String getOrder(Element elt, ParserContext pc) {
|
||||
String after = elt.getAttribute(ATT_AFTER);
|
||||
String before = elt.getAttribute(ATT_BEFORE);
|
||||
String position = elt.getAttribute(ATT_POSITION);
|
||||
|
||||
if(ConfigUtils.countNonEmpty(new String[] {after, before, position}) != 1) {
|
||||
pc.getReaderContext().error("A single '" + ATT_AFTER + "', '" + ATT_BEFORE + "', or '" +
|
||||
ATT_POSITION + "' attribute must be supplied", pc.extractSource(elt));
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(position)) {
|
||||
return Integer.toString(FilterChainOrder.getOrder(position));
|
||||
}
|
||||
|
||||
|
||||
if (StringUtils.hasText(after)) {
|
||||
return Integer.toString(FilterChainOrder.getOrder(after) + 1);
|
||||
}
|
||||
@@ -120,13 +108,5 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
|
||||
public String getBeanName() {
|
||||
return beanName;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "OrderedFilterDecorator[ delegate=" + delegate + "; order=" + getOrder() + "]";
|
||||
}
|
||||
|
||||
Filter getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ public class PasswordEncoderParser {
|
||||
static final String ATT_BASE_64 = "base64";
|
||||
static final String OPT_HASH_PLAINTEXT = "plaintext";
|
||||
static final String OPT_HASH_SHA = "sha";
|
||||
static final String OPT_HASH_SHA256 = "sha-256";
|
||||
static final String OPT_HASH_MD4 = "md4";
|
||||
static final String OPT_HASH_MD5 = "md5";
|
||||
static final String OPT_HASH_LDAP_SHA = "{sha}";
|
||||
@@ -46,7 +45,6 @@ public class PasswordEncoderParser {
|
||||
ENCODER_CLASSES = new HashMap();
|
||||
ENCODER_CLASSES.put(OPT_HASH_PLAINTEXT, PlaintextPasswordEncoder.class);
|
||||
ENCODER_CLASSES.put(OPT_HASH_SHA, ShaPasswordEncoder.class);
|
||||
ENCODER_CLASSES.put(OPT_HASH_SHA256, ShaPasswordEncoder.class);
|
||||
ENCODER_CLASSES.put(OPT_HASH_MD4, Md4PasswordEncoder.class);
|
||||
ENCODER_CLASSES.put(OPT_HASH_MD5, Md5PasswordEncoder.class);
|
||||
ENCODER_CLASSES.put(OPT_HASH_LDAP_SHA, LdapShaPasswordEncoder.class);
|
||||
@@ -76,11 +74,6 @@ public class PasswordEncoderParser {
|
||||
} else {
|
||||
Class beanClass = (Class) ENCODER_CLASSES.get(hash);
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
|
||||
|
||||
if (OPT_HASH_SHA256.equals(hash)) {
|
||||
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, new Integer(256));
|
||||
}
|
||||
|
||||
beanDefinition.setSource(parserContext.extractSource(element));
|
||||
if (useBase64) {
|
||||
if (BaseDigestPasswordEncoder.class.isAssignableFrom(beanClass)) {
|
||||
|
||||
+35
-64
@@ -23,14 +23,12 @@ import org.w3c.dom.Element;
|
||||
*/
|
||||
public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
static final String ATT_KEY = "key";
|
||||
static final String DEF_KEY = "SpringSecured";
|
||||
static final String DEF_KEY = "doesNotMatter";
|
||||
|
||||
static final String ATT_DATA_SOURCE = "data-source-ref";
|
||||
static final String ATT_SERVICES_REF = "services-ref";
|
||||
static final String ATT_DATA_SOURCE = "data-source";
|
||||
static final String ATT_TOKEN_REPOSITORY = "token-repository-ref";
|
||||
static final String ATT_USER_SERVICE_REF = "user-service-ref";
|
||||
static final String ATT_TOKEN_VALIDITY = "token-validity-seconds";
|
||||
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
@@ -39,46 +37,32 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
String key = null;
|
||||
Object source = null;
|
||||
String userServiceRef = null;
|
||||
String rememberMeServicesRef = null;
|
||||
String tokenValiditySeconds = null;
|
||||
|
||||
if (element != null) {
|
||||
tokenRepository = element.getAttribute(ATT_TOKEN_REPOSITORY);
|
||||
dataSource = element.getAttribute(ATT_DATA_SOURCE);
|
||||
key = element.getAttribute(ATT_KEY);
|
||||
userServiceRef = element.getAttribute(ATT_USER_SERVICE_REF);
|
||||
rememberMeServicesRef = element.getAttribute(ATT_SERVICES_REF);
|
||||
tokenValiditySeconds = element.getAttribute(ATT_TOKEN_VALIDITY);
|
||||
userServiceRef = element.getAttribute(ATT_USER_SERVICE_REF);
|
||||
source = parserContext.extractSource(element);
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(key)) {
|
||||
key = DEF_KEY;
|
||||
}
|
||||
|
||||
RootBeanDefinition services = null;
|
||||
|
||||
RootBeanDefinition filter = new RootBeanDefinition(RememberMeProcessingFilter.class);
|
||||
RootBeanDefinition services = new RootBeanDefinition(PersistentTokenBasedRememberMeServices.class);
|
||||
|
||||
filter.getPropertyValues().addPropertyValue("authenticationManager",
|
||||
new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
|
||||
boolean dataSourceSet = StringUtils.hasText(dataSource);
|
||||
boolean tokenRepoSet = StringUtils.hasText(tokenRepository);
|
||||
boolean servicesRefSet = StringUtils.hasText(rememberMeServicesRef);
|
||||
boolean userServiceSet = StringUtils.hasText(userServiceRef);
|
||||
boolean tokenValiditySet = StringUtils.hasText(tokenValiditySeconds);
|
||||
|
||||
if (servicesRefSet && (dataSourceSet || tokenRepoSet || userServiceSet || tokenValiditySet)) {
|
||||
parserContext.getReaderContext().error(ATT_SERVICES_REF + " can't be used in combination with attributes "
|
||||
+ ATT_TOKEN_REPOSITORY + "," + ATT_DATA_SOURCE + ", " + ATT_USER_SERVICE_REF + " or " + ATT_TOKEN_VALIDITY, source);
|
||||
}
|
||||
|
||||
|
||||
if (dataSourceSet && tokenRepoSet) {
|
||||
parserContext.getReaderContext().error("Specify " + ATT_TOKEN_REPOSITORY + " or " +
|
||||
ATT_DATA_SOURCE +" but not both", source);
|
||||
parserContext.getReaderContext().error("Specify tokenRepository or dataSource but not both", element);
|
||||
}
|
||||
|
||||
boolean isPersistent = dataSourceSet | tokenRepoSet;
|
||||
|
||||
if (isPersistent) {
|
||||
Object tokenRepo;
|
||||
services = new RootBeanDefinition(PersistentTokenBasedRememberMeServices.class);
|
||||
|
||||
if (tokenRepoSet) {
|
||||
tokenRepo = new RuntimeBeanReference(tokenRepository);
|
||||
@@ -88,51 +72,38 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
new RuntimeBeanReference(dataSource));
|
||||
}
|
||||
services.getPropertyValues().addPropertyValue("tokenRepository", tokenRepo);
|
||||
} else if (!servicesRefSet) {
|
||||
} else {
|
||||
isPersistent = false;
|
||||
services = new RootBeanDefinition(TokenBasedRememberMeServices.class);
|
||||
}
|
||||
|
||||
if (services != null) {
|
||||
if (userServiceSet) {
|
||||
services.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(userServiceRef));
|
||||
}
|
||||
|
||||
if (tokenValiditySet) {
|
||||
services.getPropertyValues().addPropertyValue("tokenValiditySeconds", new Integer(tokenValiditySeconds));
|
||||
}
|
||||
services.setSource(source);
|
||||
services.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services);
|
||||
} else {
|
||||
parserContext.getRegistry().registerAlias(rememberMeServicesRef, BeanIds.REMEMBER_ME_SERVICES);
|
||||
if (!StringUtils.hasText(key) && !isPersistent) {
|
||||
key = DEF_KEY;
|
||||
}
|
||||
|
||||
registerProvider(parserContext, source, key);
|
||||
|
||||
registerFilter(parserContext, source);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void registerProvider(ParserContext pc, Object source, String key) {
|
||||
BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(pc);
|
||||
BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
RootBeanDefinition provider = new RootBeanDefinition(RememberMeAuthenticationProvider.class);
|
||||
provider.setSource(source);
|
||||
provider.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
ManagedList providers = (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
|
||||
providers.add(provider);
|
||||
}
|
||||
|
||||
private void registerFilter(ParserContext pc, Object source) {
|
||||
RootBeanDefinition filter = new RootBeanDefinition(RememberMeProcessingFilter.class);
|
||||
|
||||
filter.setSource(source);
|
||||
filter.getPropertyValues().addPropertyValue("authenticationManager",
|
||||
new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
|
||||
services.setSource(source);
|
||||
provider.setSource(source);
|
||||
|
||||
if (StringUtils.hasText(userServiceRef)) {
|
||||
services.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(userServiceRef));
|
||||
}
|
||||
|
||||
provider.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
services.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
|
||||
ManagedList providers = (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
|
||||
providers.add(provider);
|
||||
|
||||
filter.getPropertyValues().addPropertyValue("rememberMeServices",
|
||||
new RuntimeBeanReference(BeanIds.REMEMBER_ME_SERVICES));
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_FILTER, filter);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.REMEMBER_ME_FILTER));
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_FILTER, filter);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
-66
@@ -1,66 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.security.ui.AbstractProcessingFilter;
|
||||
import org.springframework.security.ui.basicauth.BasicProcessingFilter;
|
||||
import org.springframework.security.ui.rememberme.RememberMeServices;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
*/
|
||||
public class RememberMeServicesInjectionBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private ListableBeanFactory beanFactory;
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof AbstractProcessingFilter) {
|
||||
AbstractProcessingFilter pf = (AbstractProcessingFilter) bean;
|
||||
|
||||
if (pf.getRememberMeServices() == null) {
|
||||
logger.info("Setting RememberMeServices on bean " + beanName);
|
||||
pf.setRememberMeServices(getRememberMeServices());
|
||||
}
|
||||
} else if (BeanIds.BASIC_AUTHENTICATION_FILTER.equals(beanName)) {
|
||||
// NB: For remember-me to be sent back, a user must submit a "_spring_security_remember_me" with their login request.
|
||||
// Most of the time a user won't present such a parameter with their BASIC authentication request.
|
||||
// In the future we might support setting the AbstractRememberMeServices.alwaysRemember = true, but I am reluctant to
|
||||
// do so because it seems likely to lead to lower security for 99.99% of users if they set the property to true.
|
||||
|
||||
BasicProcessingFilter bf = (BasicProcessingFilter) bean;
|
||||
logger.info("Setting RememberMeServices on bean " + beanName);
|
||||
bf.setRememberMeServices(getRememberMeServices());
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
private RememberMeServices getRememberMeServices() {
|
||||
Map beans = beanFactory.getBeansOfType(RememberMeServices.class);
|
||||
|
||||
Assert.isTrue(beans.size() > 0, "No RememberMeServices configured");
|
||||
Assert.isTrue(beans.size() == 1, "More than one RememberMeServices bean found.");
|
||||
|
||||
return (RememberMeServices) beans.values().toArray()[0];
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
+6
-7
@@ -1,12 +1,13 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.providers.dao.salt.ReflectionSaltSource;
|
||||
import org.springframework.security.providers.dao.salt.SystemWideSaltSource;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
@@ -26,8 +27,7 @@ public class SaltSourceBeanDefinitionParser implements BeanDefinitionParser {
|
||||
saltSource = new RootBeanDefinition(ReflectionSaltSource.class);
|
||||
saltSource.getPropertyValues().addPropertyValue("userPropertyToUse", userProperty);
|
||||
saltSource.setSource(parserContext.extractSource(element));
|
||||
saltSource.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
|
||||
return saltSource;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ public class SaltSourceBeanDefinitionParser implements BeanDefinitionParser {
|
||||
saltSource = new RootBeanDefinition(SystemWideSaltSource.class);
|
||||
saltSource.getPropertyValues().addPropertyValue("systemWideSalt", systemWideSalt);
|
||||
saltSource.setSource(parserContext.extractSource(element));
|
||||
saltSource.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
return saltSource;
|
||||
}
|
||||
|
||||
+1
-2
@@ -29,7 +29,6 @@ public class SecurityNamespaceHandler extends NamespaceHandlerSupport {
|
||||
registerBeanDefinitionDecorator(Elements.INTERCEPT_METHODS, new InterceptMethodsBeanDefinitionDecorator());
|
||||
registerBeanDefinitionDecorator(Elements.FILTER_CHAIN_MAP, new FilterChainMapBeanDefinitionDecorator());
|
||||
registerBeanDefinitionDecorator(Elements.CUSTOM_FILTER, new OrderedFilterBeanDefinitionDecorator());
|
||||
registerBeanDefinitionDecorator(Elements.CUSTOM_AUTH_PROVIDER, new CustomAuthenticationProviderBeanDefinitionDecorator());
|
||||
registerBeanDefinitionDecorator(Elements.CUSTOM_AFTER_INVOCATION_PROVIDER, new CustomAfterInvocationProviderBeanDefinitionDecorator());
|
||||
registerBeanDefinitionDecorator(Elements.CUSTOM_AUTH_RPOVIDER, new CustomAuthenticationProviderBeanDefinitionDecorator());
|
||||
}
|
||||
}
|
||||
|
||||
-139
@@ -1,139 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.security.providers.preauth.PreAuthenticatedAuthenticationProvider;
|
||||
import org.springframework.security.ui.rememberme.AbstractRememberMeServices;
|
||||
import org.springframework.security.userdetails.UserDetailsByNameServiceWrapper;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 2.0.2
|
||||
*/
|
||||
public class UserDetailsServiceInjectionBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (BeanIds.X509_AUTH_PROVIDER.equals(beanName)) {
|
||||
injectUserDetailsServiceIntoX509Provider((PreAuthenticatedAuthenticationProvider) bean);
|
||||
} else if (BeanIds.REMEMBER_ME_SERVICES.equals(beanName)) {
|
||||
injectUserDetailsServiceIntoRememberMeServices((AbstractRememberMeServices)bean);
|
||||
} else if (BeanIds.OPEN_ID_PROVIDER.equals(beanName)) {
|
||||
injectUserDetailsServiceIntoOpenIDProvider(bean);
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
private void injectUserDetailsServiceIntoRememberMeServices(AbstractRememberMeServices services) {
|
||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(BeanIds.REMEMBER_ME_SERVICES);
|
||||
PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("userDetailsService");
|
||||
|
||||
if (pv == null) {
|
||||
services.setUserDetailsService(getUserDetailsService());
|
||||
} else {
|
||||
UserDetailsService cachingUserService = getCachingUserService(pv.getValue());
|
||||
|
||||
if (cachingUserService != null) {
|
||||
services.setUserDetailsService(cachingUserService);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void injectUserDetailsServiceIntoX509Provider(PreAuthenticatedAuthenticationProvider provider) {
|
||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(BeanIds.X509_AUTH_PROVIDER);
|
||||
PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("preAuthenticatedUserDetailsService");
|
||||
UserDetailsByNameServiceWrapper wrapper = new UserDetailsByNameServiceWrapper();
|
||||
|
||||
if (pv == null) {
|
||||
wrapper.setUserDetailsService(getUserDetailsService());
|
||||
provider.setPreAuthenticatedUserDetailsService(wrapper);
|
||||
} else {
|
||||
RootBeanDefinition preAuthUserService = (RootBeanDefinition) pv.getValue();
|
||||
Object userService =
|
||||
preAuthUserService.getPropertyValues().getPropertyValue("userDetailsService").getValue();
|
||||
|
||||
UserDetailsService cachingUserService = getCachingUserService(userService);
|
||||
|
||||
if (cachingUserService != null) {
|
||||
wrapper.setUserDetailsService(cachingUserService);
|
||||
provider.setPreAuthenticatedUserDetailsService(wrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void injectUserDetailsServiceIntoOpenIDProvider(Object bean) {
|
||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(BeanIds.OPEN_ID_PROVIDER);
|
||||
PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("userDetailsService");
|
||||
|
||||
if (pv == null) {
|
||||
BeanWrapperImpl beanWrapper = new BeanWrapperImpl(bean);
|
||||
beanWrapper.setPropertyValue("userDetailsService", getUserDetailsService());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains a user details service for use in RememberMeServices etc. Will return a caching version
|
||||
* if available so should not be used for beans which need to separate the two.
|
||||
*/
|
||||
UserDetailsService getUserDetailsService() {
|
||||
Map beans = beanFactory.getBeansOfType(CachingUserDetailsService.class);
|
||||
|
||||
if (beans.size() == 0) {
|
||||
beans = beanFactory.getBeansOfType(UserDetailsService.class);
|
||||
}
|
||||
|
||||
if (beans.size() == 0) {
|
||||
throw new SecurityConfigurationException("No UserDetailsService registered.");
|
||||
|
||||
} else if (beans.size() > 1) {
|
||||
throw new SecurityConfigurationException("More than one UserDetailsService registered. Please " +
|
||||
"use a specific Id in your configuration");
|
||||
}
|
||||
|
||||
return (UserDetailsService) beans.values().toArray()[0];
|
||||
}
|
||||
|
||||
private UserDetailsService getCachingUserService(Object userServiceRef) {
|
||||
Assert.isInstanceOf(RuntimeBeanReference.class, userServiceRef,
|
||||
"userDetailsService property value must be a RuntimeBeanReference");
|
||||
|
||||
String id = ((RuntimeBeanReference)userServiceRef).getBeanName();
|
||||
// Overwrite with the caching version if available
|
||||
String cachingId = id + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX;
|
||||
|
||||
if (beanFactory.containsBeanDefinition(cachingId)) {
|
||||
return (UserDetailsService) beanFactory.getBean(cachingId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -6,6 +6,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.security.userdetails.memory.InMemoryDaoImpl;
|
||||
import org.springframework.security.userdetails.memory.UserMap;
|
||||
import org.springframework.security.userdetails.User;
|
||||
import org.springframework.security.util.AuthorityUtils;
|
||||
@@ -32,8 +33,8 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
|
||||
static final String ATT_DISABLED = "disabled";
|
||||
static final String ATT_LOCKED = "locked";
|
||||
|
||||
protected String getBeanClassName(Element element) {
|
||||
return "org.springframework.security.userdetails.memory.InMemoryDaoImpl";
|
||||
protected Class getBeanClass(Element element) {
|
||||
return InMemoryDaoImpl.class;
|
||||
}
|
||||
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
|
||||
+1
-2
@@ -45,8 +45,8 @@ public class X509BeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
|
||||
BeanDefinition provider = new RootBeanDefinition(PreAuthenticatedAuthenticationProvider.class);
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(provider);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.X509_AUTH_PROVIDER, provider);
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(new RuntimeBeanReference(BeanIds.X509_AUTH_PROVIDER));
|
||||
|
||||
String userServiceRef = element.getAttribute(ATT_USER_SERVICE_REF);
|
||||
|
||||
@@ -62,7 +62,6 @@ public class X509BeanDefinitionParser implements BeanDefinitionParser {
|
||||
filterBuilder.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.X509_FILTER, filterBuilder.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.X509_FILTER));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user