diff --git a/src/docbkx/domain-acls-old.xml b/src/docbkx/domain-acls-old.xml
deleted file mode 100644
index e1acfc152e..0000000000
--- a/src/docbkx/domain-acls-old.xml
+++ /dev/null
@@ -1,479 +0,0 @@
-
- Domain Object Security (old ACL module)
-
-
- Overview
-
-
- PLEASE NOTE: Acegi Security 1.0.3 contains a preview of a new
- ACL module. The new ACL module is a significant rewrite of the
- existing ACL module. The new module can be found under the
- org.springframework.security.acls package, with the
- old ACL module under
- org.springframework.security.acl. We encourage
- users to consider testing with the new ACL module and build
- applications with it. The old ACL module should be considered
- deprecated and may be removed from a future release.
-
- Complex applications often will find the need to define access
- permissions not simply at a web request or method invocation level.
- Instead, security decisions need to comprise both who
- (Authentication), where
- (MethodInvocation) and what
- (SomeDomainObject). In other words, authorization
- decisions also need to consider the actual domain object instance
- subject of a method invocation.
-
- Imagine you're designing an application for a pet clinic. There
- will be two main groups of users of your Spring-based application:
- staff of the pet clinic, as well as the pet clinic's customers. The
- staff will have access to all of the data, whilst your customers will
- only be able to see their own customer records. To make it a little
- more interesting, your customers can allow other users to see their
- customer records, such as their "puppy preschool "mentor or president
- of their local "Pony Club". Using Spring Security as the foundation,
- you have several approaches that can be used:
-
- Write your business methods to enforce the security. You
- could consult a collection within the
- Customer domain object instance to determine
- which users have access. By using the
- SecurityContextHolder.getContext().getAuthentication(),
- you'll be able to access the Authentication
- object.
-
-
-
- Write an AccessDecisionVoter to enforce
- the security from the GrantedAuthority[]s
- stored in the Authentication object. This
- would mean your AuthenticationManager would
- need to populate the Authentication with
- custom GrantedAuthority[]s representing each
- of the Customer domain object instances the
- principal has access to.
-
-
-
- Write an AccessDecisionVoter to enforce
- the security and open the target Customer
- domain object directly. This would mean your voter needs access
- to a DAO that allows it to retrieve the
- Customer object. It would then access the
- Customer object's collection of approved
- users and make the appropriate decision.
-
-
-
- Each one of these approaches is perfectly legitimate. However,
- the first couples your authorization checking to your business code.
- The main problems with this include the enhanced difficulty of unit
- testing and the fact it would be more difficult to reuse the
- Customer authorization logic elsewhere. Obtaining
- the GrantedAuthority[]s from the
- Authentication object is also fine, but will not
- scale to large numbers of Customers. If a user
- might be able to access 5,000 Customers (unlikely
- in this case, but imagine if it were a popular vet for a large Pony
- Club!) the amount of memory consumed and time required to construct
- the Authentication object would be undesirable. The
- final method, opening the Customer directly from
- external code, is probably the best of the three. It achieves
- separation of concerns, and doesn't misuse memory or CPU cycles, but
- it is still inefficient in that both the
- AccessDecisionVoter and the eventual business
- method itself will perform a call to the DAO responsible for
- retrieving the Customer object. Two accesses per
- method invocation is clearly undesirable. In addition, with every
- approach listed you'll need to write your own access control list
- (ACL) persistence and business logic from scratch.
-
- Fortunately, there is another alternative, which we'll talk
- about below.
-
-
- Basic ACL Package
-
-
- Please note that our Basic ACL services are currently being
- refactored. We expect release 1.1.0 will contain this new code.
- Planned code is already in the Spring Security Subversion sandbox, so
- please check there if you have a new application requiring ACLs or are
- in the planning stages. The Basic ACL services will be deprecated from
- release 1.1.0.
-
- The org.springframework.security.acl package
- is very simple, comprising only a handful of interfaces and a single
- class, as shown in . It provides the basic foundation for
- access control list (ACL) lookups.
-
-
- Access Control List Manager
-
-
-
-
-
-
-
-
-
-
-
- The central interface is AclManager, which is
- defined by two methods:
-
- public AclEntry[] getAcls(java.lang.Object domainInstance);
-public AclEntry[] getAcls(java.lang.Object domainInstance, Authentication authentication);
-
- AclManager is intended to be used as a
- collaborator against your business objects, or, more desirably,
- AccessDecisionVoters. This means you use Spring's
- normal ApplicationContext features to wire up your
- AccessDecisionVoter (or business method) with an
- AclManager. Consideration was given to placing the
- ACL information in the ContextHolder, but it was
- felt this would be inefficient both in terms of memory usage as well
- as the time spent loading potentially unused ACL information. The
- trade-off of needing to wire up a collaborator for those objects
- requiring ACL information is rather minor, particularly in a
- Spring-managed application.
-
- The first method of the AclManager will
- return all ACLs applying to the domain object instance passed to it.
- The second method does the same, but only returns those ACLs which
- apply to the passed Authentication object.
-
- The AclEntry interface returned by
- AclManager is merely a marker interface. You will
- need to provide an implementation that reflects that ACL permissions
- for your application.
-
- Rounding out the
- org.springframework.security.acl package is an
- AclProviderManager class, with a corresponding
- AclProvider interface.
- AclProviderManager is a concrete implementation of
- AclManager, which iterates through registered
- AclProviders. The first
- AclProvider that indicates it can authoritatively
- provide ACL information for the presented domain object instance will
- be used. This is very similar to the
- AuthenticationProvider interface used for
- authentication.
-
- With this background, let's now look at a usable ACL
- implementation.
-
- Spring Security includes a production-quality ACL provider
- implementation, which is shown in .
-
-
- Basic ACL Manager
-
-
-
-
-
-
-
-
-
-
- The implementation is based on integer masking, which is
- commonly used for ACL permissions given its flexibility and speed.
- Anyone who has used Unix's chmod command will know
- all about this type of permission masking (eg chmod
- 777). You'll find the classes and interfaces for the integer
- masking ACL package under
- org.springframework.security.acl.basic.
-
- Extending the AclEntry interface is a
- BasicAclEntry interface, with the main methods
- shown below:
-
- public AclObjectIdentity getAclObjectIdentity();
-public AclObjectIdentity getAclObjectParentIdentity();
-public int getMask();
-public java.lang.Object getRecipient();
-
- As shown, each BasicAclEntry has four main
- properties. The mask is the integer that represents
- the permissions granted to the recipient. The
- aclObjectIdentity is able to identify the domain
- object instance for which the ACL applies, and the
- aclObjectParentIdentity optionally specifies the
- parent of the domain object instance. Multiple
- BasicAclEntrys usually exist against a single
- domain object instance, and as suggested by the parent identity
- property, permissions granted higher in the object hierarchy will
- trickle down and be inherited (unless blocked by integer zero).
-
- BasicAclEntry implementations typically
- provide convenience methods, such as
- isReadAllowed(), to avoid application classes
- needing to perform bit masking themselves. The
- SimpleAclEntry and
- AbstractBasicAclEntry demonstrate and provide much
- of this bit masking logic.
-
- The AclObjectIdentity itself is merely a
- marker interface, so you need to provide implementations for your
- domain objects. However, the package does include a
- NamedEntityObjectIdentity implementation which will
- suit many needs. The NamedEntityObjectIdentity
- identifies a given domain object instance by the classname of the
- instance and the identity of the instance. A
- NamedEntityObjectIdentity can be constructed
- manually (by calling the constructor and providing the classname and
- identity Strings), or by passing in any domain
- object that contains a getId() method.
-
- The actual AclProvider implementation is
- named BasicAclProvider. It has adopted a similar
- design to that used by the authentication-related
- DaoAuthenticationProvder. Specifically, you define
- a BasicAclDao against the provider, so different
- ACL repository types can be accessed in a pluggable manner. The
- BasicAclProvider also supports pluggable cache
- providers (with Spring Security including an implementation that
- fronts EH-CACHE).
-
- The BasicAclDao interface is very simple to
- implement:
-
- public BasicAclEntry[] getAcls(AclObjectIdentity aclObjectIdentity);
-
- A BasicAclDao implementation needs to
- understand the presented AclObjectIdentity and how
- it maps to a storage repository, find the relevant records, and create
- appropriate BasicAclEntry objects and return
- them.
-
- Spring Security includes a single BasicAclDao
- implementation called JdbcDaoImpl. As implied by
- the name, JdbcDaoImpl accesses ACL information from
- a JDBC database. There is also an extended version of this DAO,
- JdbcExtendedDaoImpl, which provides CRUD operations
- on the JDBC database, although we won't discuss these features here.
- The default database schema and some sample data will aid in
- understanding its function:
-
- CREATE TABLE acl_object_identity (
- id IDENTITY NOT NULL,
- object_identity VARCHAR_IGNORECASE(250) NOT NULL,
- parent_object INTEGER,
- acl_class VARCHAR_IGNORECASE(250) NOT NULL,
- CONSTRAINT unique_object_identity UNIQUE(object_identity),
- FOREIGN KEY (parent_object) REFERENCES acl_object_identity(id)
-);
-
-CREATE TABLE acl_permission (
- id IDENTITY NOT NULL,
- acl_object_identity INTEGER NOT NULL,
- recipient VARCHAR_IGNORECASE(100) NOT NULL,
- mask INTEGER NOT NULL,
- CONSTRAINT unique_recipient UNIQUE(acl_object_identity, recipient),
- FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity(id)
-);
-
-INSERT INTO acl_object_identity VALUES (1, 'corp.DomainObject:1', null,
- 'org.springframework.security.acl.basic.SimpleAclEntry');
- INSERT INTO acl_object_identity VALUES (2, 'corp.DomainObject:2', 1,
- 'org.springframework.security.acl.basic.SimpleAclEntry');
- INSERT INTO acl_object_identity VALUES (3, 'corp.DomainObject:3', 1,
- 'org.springframework.security.acl.basic.SimpleAclEntry');
- INSERT INTO acl_object_identity VALUES (4, 'corp.DomainObject:4', 1,
- 'org.springframework.security.acl.basic.SimpleAclEntry');
- INSERT INTO acl_object_identity VALUES (5, 'corp.DomainObject:5', 3,
- 'org.springframework.security.acl.basic.SimpleAclEntry');
- INSERT INTO acl_object_identity VALUES (6, 'corp.DomainObject:6', 3,
- 'org.springframework.security.acl.basic.SimpleAclEntry');
-
- INSERT INTO acl_permission VALUES (null, 1, 'ROLE_SUPERVISOR', 1);
-INSERT INTO acl_permission VALUES (null, 2, 'ROLE_SUPERVISOR', 0);
-INSERT INTO acl_permission VALUES (null, 2, 'rod', 2);
-INSERT INTO acl_permission VALUES (null, 3, 'scott', 14);
-INSERT INTO acl_permission VALUES (null, 6, 'scott', 1);
-
- As can be seen, database-specific constraints are used
- extensively to ensure the integrity of the ACL information. If you
- need to use a different database (Hypersonic SQL statements are shown
- above), you should try to implement equivalent constraints. The
- equivalent Oracle configuration is:
-
- CREATE TABLE ACL_OBJECT_IDENTITY (
- ID number(19,0) not null,
- OBJECT_IDENTITY varchar2(255) NOT NULL,
- PARENT_OBJECT number(19,0),
- ACL_CLASS varchar2(255) NOT NULL,
- primary key (ID)
-);
-ALTER TABLE ACL_OBJECT_IDENTITY ADD CONTRAINT FK_PARENT_OBJECT foreign key (ID) references ACL_OBJECT_IDENTITY
-
-CREATE SEQUENCE ACL_OBJECT_IDENTITY_SEQ;
-
-CREATE OR REPLACE TRIGGER ACL_OBJECT_IDENTITY_ID
-BEFORE INSERT ON ACL_OBJECT_IDENTITY
-FOR EACH ROW
-BEGIN
-SELECT ACL_OBJECT_IDENTITY_SEQ.NEXTVAL INTO :new.id FROM dual;
-END;
-
-CREATE TABLE ACL_PERMISSION (
- ID number(19,0) not null,
- ACL_OBJECT_IDENTITY number(19,0) NOT NULL,
- RECIPIENT varchar2(255) NOT NULL,
- MASK number(19,0) NOT NULL,
- primary key (ID)
-);
-
-ALTER TABLE ACL_PERMISSION ADD CONTRAINT UNIQUE_ID_RECIPIENT unique (acl_object_identity, recipient);
-
-CREATE SEQUENCE ACL_PERMISSION_SEQ;
-
-CREATE OR REPLACE TRIGGER ACL_PERMISSION_ID
-BEFORE INSERT ON ACL_PERMISSION
-FOR EACH ROW
-BEGIN
-SELECT ACL_PERMISSION_SEQ.NEXTVAL INTO :new.id FROM dual;
-END;
-
-<bean id="basicAclExtendedDao" class="org.springframework.security.acl.basic.jdbc.JdbcExtendedDaoImpl">
-<property name="dataSource">
- <ref bean="dataSource"/>
-</property>
-<property name="objectPropertiesQuery" value="${acegi.objectPropertiesQuery}"/>
-</bean>
-
-<prop key="acegi.objectPropertiesQuery">SELECT CHILD.ID, CHILD.OBJECT_IDENTITY, CHILD.ACL_CLASS, PARENT.OBJECT_IDENTITY as PARENT_OBJECT_IDENTITY FROM acl_object_identity as CHILD LEFT OUTER JOIN acl_object_identity as PARENT ON CHILD.parent_object=PARENT.id WHERE CHILD.object_identity = ?</prop>
-
- The JdbcDaoImpl will only respond to requests
- for NamedEntityObjectIdentitys. It converts such
- identities into a single String, comprising
- the NamedEntityObjectIdentity.getClassname() +
- ":" +
- NamedEntityObjectIdentity.getId(). This yields the
- type of object_identity values shown above. As
- indicated by the sample data, each database row corresponds to a
- single BasicAclEntry. As stated earlier and
- demonstrated by corp.DomainObject:2 in the above
- sample data, each domain object instance will often have multiple
- BasicAclEntry[]s.
-
- As JdbcDaoImpl is required to return concrete
- BasicAclEntry classes, it needs to know which
- BasicAclEntry implementation it is to create and
- populate. This is the role of the acl_class column.
- JdbcDaoImpl will create the indicated class and set
- its mask, recipient,
- aclObjectIdentity and
- aclObjectParentIdentity properties.
-
- As you can probably tell from the sample data, the
- parent_object_identity value can either be null or
- in the same format as the object_identity. If
- non-null, JdbcDaoImpl will create a
- NamedEntityObjectIdentity to place inside the
- returned BasicAclEntry class.
-
- Returning to the BasicAclProvider, before it
- can poll the BasicAclDao implementation it needs to
- convert the domain object instance it was passed into an
- AclObjectIdentity.
- BasicAclProvider has a protected
- AclObjectIdentity obtainIdentity(Object domainInstance)
- method that is responsible for this. As a protected method, it enables
- subclasses to easily override. The normal implementation checks
- whether the passed domain object instance implements the
- AclObjectIdentityAware interface, which is merely a
- getter for an AclObjectIdentity. If the domain
- object does implement this interface, that is the identity returned.
- If the domain object does not implement this interface, the method
- will attempt to create an AclObjectIdentity by
- passing the domain object instance to the constructor of a class
- defined by the
- BasicAclProvider.getDefaultAclObjectIdentity()
- method. By default the defined class is
- NamedEntityObjectIdentity, which was described in
- more detail above. Therefore, you will need to either (i) provide a
- getId() method on your domain objects, (ii)
- implement AclObjectIdentityAware on your domain
- objects, (iii) provide an alternative
- AclObjectIdentity implementation that will accept
- your domain object in its constructor, or (iv) override the
- obtainIdentity(Object) method.
-
- Once the AclObjectIdentity of the domain
- object instance is determined, the BasicAclProvider
- will poll the DAO to obtain its BasicAclEntry[]s.
- If any of the entries returned by the DAO indicate there is a parent,
- that parent will be polled, and the process will repeat until there is
- no further parent. The permissions assigned to a
- recipient closest to the domain object instance
- will always take priority and override any inherited permissions. From
- the sample data above, the following inherited permissions would
- apply:
-
- --- Mask integer 0 = no permissions
---- Mask integer 1 = administer
---- Mask integer 2 = read
---- Mask integer 6 = read and write permissions
---- Mask integer 14 = read and write and create permissions
-
----------------------------------------------------------------------
---- *** INHERITED RIGHTS FOR DIFFERENT INSTANCES AND RECIPIENTS ***
---- INSTANCE RECIPIENT PERMISSION(S) (COMMENT #INSTANCE)
----------------------------------------------------------------------
---- 1 ROLE_SUPERVISOR Administer
---- 2 ROLE_SUPERVISOR None (overrides parent #1)
---- rod Read
---- 3 ROLE_SUPERVISOR Administer (from parent #1)
---- scott Read, Write, Create
---- 4 ROLE_SUPERVISOR Administer (from parent #1)
---- 5 ROLE_SUPERVISOR Administer (from parent #3)
---- scott Read, Write, Create (from parent #3)
---- 6 ROLE_SUPERVISOR Administer (from parent #3)
---- scott Administer (overrides parent #3)
-
- So the above explains how a domain object instance has its
- AclObjectIdentity discovered, and the
- BasicAclDao will be polled successively until an
- array of inherited permissions is constructed for the domain object
- instance. The final step is to determine the
- BasicAclEntry[]s that are actually applicable to a
- given Authentication object.
-
- As you would recall, the AclManager (and all
- delegates, up to and including BasicAclProvider)
- provides a method which returns only those
- BasicAclEntry[]s applying to a passed
- Authentication object.
- BasicAclProvider delivers this functionality by
- delegating the filtering operation to an
- EffectiveAclsResolver implementation. The default
- implementation,
- GrantedAuthorityEffectiveAclsResolver, will iterate
- through the BasicAclEntry[]s and include only those
- where the recipient is equal to either the
- Authentication's principal or
- any of the Authentication's
- GrantedAuthority[]s. Please refer to the JavaDocs
- for more information.
-
-
- ACL Instantiation Approach
-
-
-
-
-
-
-
-
-
-
- explains the key relationships between objects
- in the Basic ACL package.
-
-
\ No newline at end of file
diff --git a/src/docbkx/domain-acls.xml b/src/docbkx/domain-acls.xml
index a353e7ce2f..204e4a85b0 100644
--- a/src/docbkx/domain-acls.xml
+++ b/src/docbkx/domain-acls.xml
@@ -1,179 +1,304 @@
-
- Domain Object Security
-
-
-
- Overview
-
-
- PLEASE NOTE: Acegi Security 1.0.3 contains a preview of a new
- ACL module. The new ACL module is a significant rewrite of the
- existing ACL module. The new module can be found under the
- org.springframework.security.acls package, with the
- old ACL module under
- org.springframework.security.acl. We encourage
- users to consider testing with the new ACL module and build
- applications with it. The old ACL module should be considered
- deprecated and may be removed from a future release.
-
- Complex applications often will find the need to define access
- permissions not simply at a web request or method invocation level.
- Instead, security decisions need to comprise both who
- (Authentication), where
- (MethodInvocation) and what
- (SomeDomainObject). In other words, authorization
- decisions also need to consider the actual domain object instance
- subject of a method invocation.
-
- Imagine you're designing an application for a pet clinic. There
- will be two main groups of users of your Spring-based application:
- staff of the pet clinic, as well as the pet clinic's customers. The
- staff will have access to all of the data, whilst your customers will
- only be able to see their own customer records. To make it a little
- more interesting, your customers can allow other users to see their
- customer records, such as their "puppy preschool "mentor or president
- of their local "Pony Club". Using Spring Security as the foundation,
- you have several approaches that can be used:
+
+ Domain Object Security
+
+
+
+ Overview
+
+ PLEASE NOTE: Before release 2.0.0, Spring Security was known as Acegi Security. An ACL
+ module was provided with the old Acegi Security releases under the
+ org.[acegisecurity/springsecurity].acl package. This old package
+ is now deprecated and will be removed in a future release of Spring Security. This
+ chapter covers the new ACL module, which is officially recommended from Spring Security
+ 2.0.0 and above, and can be found under the
+ org.springframework.security.acls package.
+ Complex applications often will find the need to define access permissions not simply
+ at a web request or method invocation level. Instead, security decisions need to
+ comprise both who (Authentication), where
+ (MethodInvocation) and what (SomeDomainObject). In
+ other words, authorization decisions also need to consider the actual domain object
+ instance subject of a method invocation.
+ Imagine you're designing an application for a pet clinic. There will be two main
+ groups of users of your Spring-based application: staff of the pet clinic, as well as
+ the pet clinic's customers. The staff will have access to all of the data, whilst your
+ customers will only be able to see their own customer records. To make it a little more
+ interesting, your customers can allow other users to see their customer records, such as
+ their "puppy preschool" mentor or president of their local "Pony Club". Using Spring
+ Security as the foundation, you have several approaches that can be used:
- Write your business methods to enforce the security. You
- could consult a collection within the
- Customer domain object instance to determine
- which users have access. By using the
- SecurityContextHolder.getContext().getAuthentication(),
+ Write your business methods to enforce the security. You could consult a
+ collection within the Customer domain object instance to
+ determine which users have access. By using the
+ SecurityContextHolder.getContext().getAuthentication(),
you'll be able to access the Authentication
- object.
+ object.
-
- Write an AccessDecisionVoter to enforce
- the security from the GrantedAuthority[]s
- stored in the Authentication object. This
- would mean your AuthenticationManager would
- need to populate the Authentication with
- custom GrantedAuthority[]s representing each
- of the Customer domain object instances the
- principal has access to.
+ Write an AccessDecisionVoter to enforce the security
+ from the GrantedAuthority[]s stored in the
+ Authentication object. This would mean your
+ AuthenticationManager would need to populate the
+ Authentication with custom
+ GrantedAuthority[]s representing each of the
+ Customer domain object instances the principal has
+ access to.
-
- Write an AccessDecisionVoter to enforce
- the security and open the target Customer
- domain object directly. This would mean your voter needs access
- to a DAO that allows it to retrieve the
- Customer object. It would then access the
- Customer object's collection of approved
- users and make the appropriate decision.
+ Write an AccessDecisionVoter to enforce the security
+ and open the target Customer domain object directly. This
+ would mean your voter needs access to a DAO that allows it to retrieve the
+ Customer object. It would then access the
+ Customer object's collection of approved users and
+ make the appropriate decision.
-
- Each one of these approaches is perfectly legitimate. However,
- the first couples your authorization checking to your business code.
- The main problems with this include the enhanced difficulty of unit
- testing and the fact it would be more difficult to reuse the
- Customer authorization logic elsewhere. Obtaining
- the GrantedAuthority[]s from the
- Authentication object is also fine, but will not
- scale to large numbers of Customers. If a user
- might be able to access 5,000 Customers (unlikely
- in this case, but imagine if it were a popular vet for a large Pony
- Club!) the amount of memory consumed and time required to construct
- the Authentication object would be undesirable. The
- final method, opening the Customer directly from
- external code, is probably the best of the three. It achieves
- separation of concerns, and doesn't misuse memory or CPU cycles, but
- it is still inefficient in that both the
- AccessDecisionVoter and the eventual business
- method itself will perform a call to the DAO responsible for
- retrieving the Customer object. Two accesses per
- method invocation is clearly undesirable. In addition, with every
- approach listed you'll need to write your own access control list
- (ACL) persistence and business logic from scratch.
-
- Fortunately, there is another alternative, which we'll talk
- about below.
+ Each one of these approaches is perfectly legitimate. However, the first couples your
+ authorization checking to your business code. The main problems with this include the
+ enhanced difficulty of unit testing and the fact it would be more difficult to reuse the
+ Customer authorization logic elsewhere. Obtaining the
+ GrantedAuthority[]s from the Authentication
+ object is also fine, but will not scale to large numbers of
+ Customers. If a user might be able to access 5,000
+ Customers (unlikely in this case, but imagine if it were a popular
+ vet for a large Pony Club!) the amount of memory consumed and time required to construct
+ the Authentication object would be undesirable. The final method,
+ opening the Customer directly from external code, is probably the
+ best of the three. It achieves separation of concerns, and doesn't misuse memory or CPU
+ cycles, but it is still inefficient in that both the
+ AccessDecisionVoter and the eventual business method itself will
+ perform a call to the DAO responsible for retrieving the Customer
+ object. Two accesses per method invocation is clearly undesirable. In addition, with
+ every approach listed you'll need to write your own access control list (ACL)
+ persistence and business logic from scratch.
+ Fortunately, there is another alternative, which we'll talk about below.
-
- Key Concepts
-
-
- The org.springframework.security.acls package should be
- consulted for its major interfaces. The key interfaces are:
-
+
+
+ Key Concepts
+
+ Spring Security's ACL services are shipped in the
+ spring-security-acl-xxx.jar. You will need to add this JAR to your
+ classpath to use Spring Security's domain object instance security capabilities.
+ Spring Security's domain object instance security capabilities centre on the concept
+ of an access control list (ACL). Every domain object instance in your system has its own
+ ACL, and the ACL records details of who can and can't work with that domain object. With
+ this in mind, Spring Security delivers three main ACL-related capabilities to your application:
+
+ A way of efficiently retrieving ACL entries for all of your domain objects
+ (and modifying those ACLs)
+
+
+ A way of ensuring a given principal is permitted to work with your
+ objects, before methods are called
+
+
+ A way of ensuring a given principal is permitted to work with your objects
+ (or something they return), after methods are called
+
+
+ As indicated by the first bullet point, one of the main capabilities of the Spring
+ Security ACL module is providing a high-performance way of retrieving ACLs. This ACL
+ repository capability is extremely important, because every domain object instance in
+ your system might have several access control entries, and each ACL might inherit from
+ other ACLs in a tree-like structure (this is supported out-of-the-box by Spring
+ Security, and is very commonly used). Spring Security's ACL capability has been
+ carefully designed to provide high performance retrieval of ACLs, together with
+ pluggable caching, deadlock-minimizing database updates, independence from ORM
+ frameworks (we use JDBC directly), proper encapsulation, and transparent database
+ updating.
+ Given databases are central to the operation of the ACL module, let's explore the four
+ main tables used by default in the implementation. The tables are presented below in
+ order of size in a typical Spring Security ACL deployment, with the table with the most
+ rows listed last:
+
+
+
+ ACL_SID allows us to uniquely identify any principal or authority in the
+ system ("SID" stands for "security identity"). The only columns are the ID,
+ a textual representation of the SID, and a flag to indicate whether the
+ textual representation refers to a prncipal name or a
+ GrantedAuthority. Thus, there is a single row for
+ each unique principal or GrantedAuthority. When used in
+ the context of receiving a permission, a SID is generally called a
+ "recipient".
+
+
+ ACL_CLASS allows us to uniquely identify any domain object class in the
+ system. The only columns are the ID and the Java class name. Thus, there is
+ a single row for each unique Class we wish to store ACL permissions
+ for.
+
+
+ ACL_OBJECT_IDENTITY stores information for each unique domain object
+ instance in the system. Columns include the ID, a foreign key to the
+ ACL_CLASS table, a unique identifier so we know which ACL_CLASS instance
+ we're providing information for, the parent, a foreign key to the ACL_SID
+ table to represent the owner of the domain object instance, and whether we
+ allow ACL entries to inherit from any parent ACL. We have a single row for
+ every domain object instance we're storing ACL permissions for.
+
+
+ Finally, ACL_ENTRY stores the individual permissions assigned to each
+ recipient. Columns include a foreign key to the ACL_OBJECT_IDENTITY, the
+ recipient (ie a foreign key to ACL_SID), whether we'll be auditing or not,
+ and the integer bit mask that represents the actual permission being granted
+ or denied. We have a single row for every recipient that receives a
+ permission to work with a domain object.
+
+
+
+ As mentioned in the last paragraph, the ACL system uses integer bit masking. Don't
+ worry, you need not be aware of the finer points of bit shifting to use the ACL system,
+ but suffice to say that we have 32 bits we can switch on or off. Each of these bits
+ represents a permission, and by default the permissions are read (bit 0), write (bit 1),
+ create (bit 2), delete (bit 3) and administer (bit 4). It's easy to implement your own
+ Permission instance if you wish to use other permissions, and the
+ remainder of the ACL framework will operate without knowledge of your extensions.
+ It is important to understand that the number of domain objects in your system has
+ absolutely no bearing on the fact we've chosen to use integer bit masking. Whilst you
+ have 32 bits available for permissions, you could have billions of domain object
+ instances (which will mean billions of rows in ACL_OBJECT_IDENTITY and quite probably
+ ACL_ENTRY). We make this point because we've found sometimes people mistakenly believe
+ they need a bit for each potential domain object, which is not the case.
+ Now that we've provided a basic overview of what the ACL system does, and what it
+ looks like at a table structure, let's explore the key interfaces. The key interfaces
+ are:
- Acl: Every domain object has one and only
- one Acl object, which internally holds the
- AccessControlEntrys as well as knows the owner
- of the Acl. An Acl does not refer directly to
- the domain object, but instead to an
- ObjectIdentity.
+ Acl: Every domain object has one and only one
+ Acl object, which internally holds the
+ AccessControlEntrys as well as knows the owner of the
+ Acl. An Acl does not refer directly to the domain object,
+ but instead to an ObjectIdentity. The Acl
+ is stored in the ACL_OBJECT_IDENTITY table.
-
- AccessControlEntry: An
- Acl holds multiple AccessControlEntrys, which
- are often abbreviated as ACEs in the framework. Each ACE refers to
- a specific tuple of Permission,
- Sid and Acl. An ACE can also
- be granting or non-granting and contain audit settings.
+ AccessControlEntry: An Acl holds
+ multiple AccessControlEntrys, which are often abbreviated as
+ ACEs in the framework. Each ACE refers to a specific tuple of
+ Permission, Sid and
+ Acl. An ACE can also be granting or non-granting and contain
+ audit settings. The ACE is stored in the ACL_ENTRY table.
-
- Permission: A permission represents an
- immutable particular bit mask, and offers convenience functions
- for bit masking and outputting information.
+ Permission: A permission represents a particular immutable
+ bit mask, and offers convenience functions for bit masking and outputting
+ information. The basic permissions presented above (bits 0 through 4) are
+ contained in the BasePermission class.
-
- Sid: The ACL module needs to refer to
- principals and GrantedAuthority[]s. A level of
- indirection is provided by the Sid interface.
- Common classes include PrincipalSid (to
- represent the principal inside an
- Authentication object) and
- GrantedAuthoritySid.
+ Sid: The ACL module needs to refer to principals and
+ GrantedAuthority[]s. A level of indirection is provided
+ by the Sid interface, which is an abbreviation of "security
+ identity". Common classes include PrincipalSid (to represent
+ the principal inside an Authentication object) and
+ GrantedAuthoritySid. The security identity information is
+ stored in the ACL_SID table.
-
- ObjectIdentity: Each domain object is
- represented internally within the ACL module by an
- ObjectIdentity.
+ ObjectIdentity: Each domain object is represented
+ internally within the ACL module by an ObjectIdentity. The
+ default implementation is called ObjectIdentityImpl.
-
- AclService: Retrieves the
- Acl applicable for a given
- ObjectIdentity.
+ AclService: Retrieves the Acl applicable
+ for a given ObjectIdentity. In the included implementation
+ (JdbcAclService), retrieval operations are delegated to a
+ LookupStrategy. The LookupStrategy
+ provides a highly optimized strategy for retrieving ACL information, using
+ batched retrievals (BasicLookupStrategy) and supporting
+ custom implementations that leverage materialized views, hierarchical queries
+ and similar performance-centric, non-ANSI SQL capabilities.
-
- MutableAclService: Allows a modified
- Acl to be presented for persistence. It is not
- essential to use this interface if you do not wish.
+ MutableAclService: Allows a modified Acl
+ to be presented for persistence. It is not essential to use this interface if
+ you do not wish.
-
- The ACL module was based on extensive feedback from the user
- community following real-world use of the original ACL module. This
- feedback resulted in a rearchitecture of the ACL module to offer
- significantly enhanced performance (particularly in the area of
- database retrieval), significantly better encapsulation, higher
- cohesion, and enhanced customisation points.
-
- The Contacts Sample that ships with Acegi Security 1.0.3 offers
- a demonstration of the new ACL module. Converting Contacts from using
- the old module to the new module was relatively simple, and users of
- the old ACL module will likely find their applications can be modified
- with relatively little work.
-
- We will document the new ACL module more fully with a subsequent
- release. Please note that the new ACL module should be considered a
- preview only (ie do not use in production without proper prior
- testing), and there is a small chance there may be changes between
- 1.0.3 and 1.1.0 when it will become final. Nevertheless,
- compatibility-affecting changes are considered quite unlikely,
- especially given the module is already based on several years of
- feedback from users of the original ACL module.
+ Please note that our out-of-the-box AclService and related database classes all use
+ ANSI SQL. This should therefore work with all major databases. At the time of writing,
+ the system had been successfully tested using Hypersonic SQL, PostgreSQL, Microsoft SQL
+ Server and Oracle.
+ Two samples ship with Spring Security that demonstrate the ACL module. The first is
+ the Contacts Sample, and the other is the Document Management System (DMS) Sample. We
+ suggest taking a look over these for examples.
+
+
+
+ Getting Started
+
+ To get starting using Spring Security's ACL capability, you will need to store your
+ ACL information somewhere. This necessitates the instantiation of a
+ DataSource using Spring. The DataSource is then
+ injected into a JdbcMutableAclService and
+ BasicLookupStrategy instance. The latter provides
+ high-performance ACL retrieval capabilities, and the former provides mutator
+ capabilities. Refer to one of the samples that ship with Spring Security for an example
+ configuration. You'll also need to populate the database with the four ACL-specific
+ tables listed in the last section (refer to the ACL samples for the appropriate SQL
+ statements).
+ Once you've created the required schema and instantiated
+ JdbcMutableAclService, you'll next need to ensure your domain
+ model supports interoperability with the Spring Security ACL package. Hopefully
+ ObjectIdentityImpl will prove sufficient, as it provides a large
+ number of ways in which it can be used. Most people will have domain objects that
+ contain a public Serializable getId() method. If the return type is
+ long, or compatible with long (eg an int), you will find you need not give further
+ consideration to ObjectIdentity issues. Many parts of the ACL module
+ rely on long identifiers. If you're not using long (or an int, byte etc), there is a
+ very good chance you'll need to reimplement a number of classes. We do not intend to
+ support non-long identifiers in Spring Security's ACL module, as longs are already
+ compatible with all database sequences, the most common identifier data type, and are of
+ sufficient length to accommodate all common usage scenarios.
+ The following fragment of code shows how to create an Acl, or
+ modify an existing
+ Acl:// Prepare the information we'd like in our access control entry (ACE)
+ObjectIdentity oi = new ObjectIdentityImpl(Foo.class, new Long(44));
+Sid sid = new PrincipalSid("Samantha");
+Permission p = BasePermission.ADMINISTRATION;
+
+// Create or update the relevant ACL
+MutableAcl acl = null;
+try {
+ acl = (MutableAcl) aclService.readAclById(oi);
+} catch (NotFoundException nfe) {
+ acl = aclService.createAcl(oi);
+}
+
+// Now grant some permissions via an access control entry (ACE)
+acl.insertAce(acl.getEntries().length, p, sid, true);
+aclService.updateAcl(acl);
+
+ In the example above, we're retrieving the ACL associated with the "Foo" domain object
+ with identifier number 44. We're then adding an ACE so that a principal named "Samantha"
+ can "administer" the object. The code fragment is relatively self-explanatory, except
+ the insertAce method. The first argument to the insertAce method is determining at what
+ position in the Acl the new entry will be inserted. In the example above, we're just
+ putting the new ACE at the end of the existing ACEs. The final argument is a boolean
+ indicating whether the ACE is granting or denying. Most of the time it will be granting
+ (true), but if it is denying (false), the permissions are effectively being blocked.
+ Spring Security does not provide any special integration to automatically create,
+ update or delete ACLs as part of your DAO or repository operations. Instead, you will
+ need to write code like shown above for your individual domain objects. It's worth
+ considering using AOP on your services layer to automatically integrate the ACL
+ information with your services layer operations. We've found this quite an effective
+ approach in the past.
+ Once you've used the above techniques to store some ACL information in the database,
+ the next step is to actually use the ACL information as part of authorization decision
+ logic. You have a number of choices here. You could write your own
+ AccessDecisionVoter or AfterInvocationProvider
+ that respectively fires before or after a method invocation. Such classes would use
+ AclService to retrieve the relevant ACL and then call
+ Acl.isGranted(Permission[] permission, Sid[] sids, boolean
+ administrativeMode) to decide whether permission is granted or denied.
+ Alternately, you could use our AclEntryVoter,
+ AclEntryAfterInvocationProvider or
+ AclEntryAfterInvocationCollectionFilteringProvider classes. All
+ of these classes provide a declarative-based approach to evaluating ACL information at
+ runtime, freeing you from needing to write any code. Please refer to the sample
+ applications to learn how to use these classes.
-
\ No newline at end of file
+
diff --git a/src/docbkx/springsecurity.xml b/src/docbkx/springsecurity.xml
index d807bb6be1..3190a6e4c0 100644
--- a/src/docbkx/springsecurity.xml
+++ b/src/docbkx/springsecurity.xml
@@ -192,9 +192,7 @@
-
-
-
+
\ No newline at end of file