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: 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.
Key Concepts The org.springframework.security.acls package should be consulted for its major 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. 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. Permission: A permission represents an immutable particular bit mask, and offers convenience functions for bit masking and outputting information. 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. ObjectIdentity: Each domain object is represented internally within the ACL module by an ObjectIdentity. AclService: Retrieves the Acl applicable for a given ObjectIdentity. 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.