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
AccessControlEntry
s 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 AccessControlEntry
s, 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 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, 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
. The
default implementation is called ObjectIdentityImpl
.
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.
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.