Imagine you are designing an application for a pet clinic.
There are two main groups of users of your Spring-based application: staff of the pet clinic and the pet clinic's customers.
The staff should have access to all of the data, while your customers should be able to see only their own customer records.
To make it a little more interesting, your customers can let other users see their customer records, such as their "`puppy preschool`" mentor or the president of their local "`Pony Club`".
When you use Spring Security as the foundation, you have several possible approaches:
By using `SecurityContextHolder.getContext().getAuthentication()`, you can access the `Authentication` object.
* Write an `AccessDecisionVoter` to enforce the security from the `GrantedAuthority[]` instances stored in the `Authentication` object.
This means that your `AuthenticationManager` needs to populate the `Authentication` with custom `GrantedAuthority[]` objects to represent each of the `Customer` domain object instances to which the principal has access.
The main problems with this include the enhanced difficulty of unit testing and the fact that it would be more difficult to reuse the `Customer` authorization logic elsewhere.
Obtaining the `GrantedAuthority[]` instances from the `Authentication` object is also fine but will not scale to large numbers of `Customer` objects.
If a user can access 5,000 `Customer` objects (unlikely in this case, but imagine if it were a popular vet for a large Pony Club!) the amount of memory consumed and the time required to construct the `Authentication` object would be undesirable.
It achieves separation of concerns and does not misuse memory or CPU cycles, but it is still inefficient in that both the `AccessDecisionVoter` and the eventual business method itself perform a call to the DAO responsible for retrieving the `Customer` object.
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 by Spring Security, and it 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.
The only columns are the ID, a textual representation of the SID, and a flag to indicate whether the textual representation refers to a principal name or a `GrantedAuthority`.
Columns include the ID, a foreign key to the ACL_CLASS table, a unique identifier so we know the ACL_CLASS instance for which we provide information, 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 for which we store ACL permissions.
* Finally, `ACL_ENTRY` stores the individual permissions assigned to each recipient.
Columns include a foreign key to the `ACL_OBJECT_IDENTITY`, the recipient (i.e. 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.
However, you need not be aware of the finer points of bit shifting to use the ACL system.
Suffice it to say that we have 32 bits we can switch on or off.
Each of these bits represents a permission. By default, the permissions are read (bit 0), write (bit 1), create (bit 2), delete (bit 3), and administer (bit 4).
You can implement your own `Permission` instance if you wish to use other permissions, and the remainder of the ACL framework operates without knowledge of your extensions.
You should understand that the number of domain objects in your system has absolutely no bearing on the fact that we have chosen to use integer bit masking.
While you have 32 bits available for permissions, you could have billions of domain object instances (which means billions of rows in ACL_OBJECT_IDENTITY and, probably, ACL_ENTRY).
We make this point because we have found that people sometimes mistakenly that believe they need a bit for each potential domain object, which is not the case.
Now that we have provided a basic overview of what the ACL system does, and what it looks like at a table-structure level, we need to explore the key interfaces:
* `Acl`: Every domain object has one and only one `Acl` object, which internally holds the `AccessControlEntry` objects and knows the owner of the `Acl`.
The `LookupStrategy` provides a highly optimized strategy for retrieving ACL information, using batched retrievals (`BasicLookupStrategy`) and supporting custom implementations that use materialized views, hierarchical queries, and similar performance-centric, non-ANSI SQL capabilities.
The first is the {gh-samples-url}/servlet/xml/java/contacts[Contacts Sample], and the other is the {gh-samples-url}/servlet/xml/java/dms[Document Management System (DMS) Sample].
You also need to populate the database with the <<acl_tables,four ACL-specific tables>> listed in the previous section (see the ACL samples for the appropriate SQL statements).
Once you have created the required schema and instantiated `JdbcMutableAclService`, you need to ensure your domain model supports interoperability with the Spring Security ACL package.
Hopefully, `ObjectIdentityImpl` proves sufficient, as it provides a large number of ways in which it can be used.
Most people have domain objects that contain a `public Serializable getId()` method.
If the return type is `long` or compatible with `long` (such as an `int`), you may find that you need not give further consideration to `ObjectIdentity` issues.
If you do not use `long` (or an `int`, `byte`, and so on), you probably 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, are the most common identifier data type, and are of sufficient length to accommodate all common usage scenarios.
Once you have used the techniques described here to store some ACL information in the database, the next step is to actually use the ACL information as part of authorization decision logic.
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.