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