Using Spring Security is like the blessing. Everything is coded and you only need to implement it correctly. But always is good to know what we are implementing. This is the main purpose of this article, to understand how one of particular Spring Security modes, ACL, works.
Data Engineering Design Patterns

Looking for a book that defines and solves most common data engineering problems? I wrote
one on that topic! You can read it online
on the O'Reilly platform,
or get a print copy on Amazon.
I also help solve your data engineering problems 👉 contact@waitingforcode.com 📩
The article will be divided on two parts. The first one will cover theoretical concepts of ACL and Spring Security ACL project. It will present the key concepts of the project. At the second part, we will see how these thoughts are implemented in the code, in which packages and names.
Key concepts of Spring Security ACL
Before analyzing Spring Security project, let's start by understanding what is ACL ? ACL acronym means access control list. This is a list of permissions between objects and users. Thanks to these links we can determine which actions one user can do on the objects stored in the system. For example, we can check if a user with login user2 is able to modify an article entitled "Private rapport of activity 2013". We can draw a table to illustrate that :
Permissions to article "Private rapport of activity 2013" :User | Can read | Can modify | Can delete |
---|---|---|---|
user1 | Yes | No | No |
user2 | Yes | No | No |
user3 | Yes | Yes | No |
As we can see, user1 and user2 can only read the article. The last user can read and modify it. So, we can consider Spring Security ACL project as a programming implementation of above table.
In Spring Security ACL we can distinguish following actors :
- lookup strategystrategy which defines the way of retreiving the ACLs. It can be a retreival from the database, but also from configuration files, web services... Only one requirement, it must return an ACL from demanded object, for example: previously saw table converted to Java's Map object.
- object identityit's the object concerned by access control demand. Like we have saw previously, it can be an article entitled "Private rapport of activity 2013" with database id 309.
- granted authoritya granted authority is a kind of permission. Thanks to it voters can decide if an user can access to a protected element or not. Beware, a granted authority includes the role.
- expressionin Spring Security ACL mode, we use rarely the pure Java code to make the check access requests. More often we'll use the expressions placed on authorization annotations like @PreAuthorize or @PostAuthorize (will be detailed in one of next articles). An example of expression which can protect the article from above table could be
@PostAuthorize("hasPermission(returnObject, 'WRITE')") public Article getArticle(int id) { // db query return article; }
It means "return the object of this method only if a user can modify returned object - otherwise return null". - roleassociated with every user, the role is a precise example of granted authority. It determines the user's importance in the system but also can help to check if a user should be able to access to a protected resource. You should understand it thanks to this example. We have two users : one with role "ADMIN" and another one with the role "VISITOR". In additionally, we have this expression too : @PreAuthorize("hasRole('ADMIN')"). The method preceded with this expression will be executed only if the role of user connected to the system will be "ADMIN". Otherwise, an error page will be shown. As you can see, we treat the role as a permission.
- permissiondefines the activity which one user can do. For example, in previous table we have had 3 permissions represented by words: read, modify and delete. In Spring Security ACL, the permission can be expressed in words but also in integers or bytes.
- permission granting strategydetermines the strategy to adopt in the case when we check whether a permission(s) is granted to particular security identity (sid).
- permission evaluatorhelps to determine if one user has sufficient rights to access one element. In the case of our table, me, the article's author, is the permission evaluator. It's because I know the means of table rights (Yes/No). Ie, I know that user with No entry for write permission can't modify the object identity.
- access control entry (ACE)this objects presents one entry in ACL. In the case the table from the beginning of this paragraph, we can take the first line and normalized it into : user1[read=yes, write=no, delete=no].
- access control list (ACL)list of user's permissions to one object identity, just like our "Private rapport..." table.
- security identity (SID)represents the user who tries to access to one object identity, for example user1 whose role is "MODERATOR".
- voterlike in a democracy, the Spring Security ACL's voters, will make the decisions. They will check if connected user, represented by implementation of org.springframework.security.core.Authentication interface, has sufficient permissions to access to protected item (method, property).
A lot of concepts are similar. For example, permission evaluator and voter, both decide if a user can access to a protected element. But in the second part of this article, we'll see the exact decision flow in Spring Security ACL.
Spring Security ACL permission flow
Before starting to talk about Spring Security ACL components, let's take a look to a simplified schema of steps which are done every time when a security identity tries to execute protected method.
Roles hierarchy initialization
First, when servlet container starts, Spring initializes the beans defined in our configuration. We can observe the initialization of AclService, LookupStrategy, AuthorizationStrategy and RoleHierarchy implementations. The most interesting is the last one which constructs a tree of roles. The tree is made thanks to character > which defines the roles reachables from a parent role. For example, ROLE_ADMIN > ROLE_USER > ROLE_VISITOR means that ROLE_ADMIN encapsulates two following roles (ROLE_USER and ROLE_VISITOR) and that ROLE_USER encapsulates only ROLE_VISITOR. In practice, that means that security identity with the ROLE_ADMIN will be able to see the content reserved to ROLE_USER. But in another side, ROLE_VISITOR won't be able to see this content because it doesn't encapsulate ROLE_USER.
Expression treatment.
Imagine the following expression :
@PostAuthorize("hasPermission(returnObject, 'READ')") public Article getArticle(int id);
It means that the method will return the instance of Article class only if security identity has a permission to read it. How it works under hood ?
In this case, the implementation of MethodSecurityExpressionHandler, defined as the bean with id expressionHandler, is invoked. An expression handler is a class which treats the expression included in ACL annotations (@PostAuthorize, @PreAuthorize). It gets all of needed objects to evaluate if a user can call a secured method. Among these objects, we can find: the permission evaluator, roles hierarchy, authentified user, the method protected by the expression and a trust resolver.
Evaluator checks the permissions.
Now, it's the turn of permission evaluator to make a choice if the security identity can invoke a protected method. It does it by calling the same function as the function defined in security expression. In our example, it will be the method hasPermission. The permission check is made thanks to AclService implementation which verify in the datasource (for exemple: database), if a user can call secured method.
To make this check, AclService will demand a support of LookupStrategy implementation. The lookup strategy will return an access control entry.
At the end, permission evaluator verifies if security identity has a granted access to a secured resource by invoking isGranted() method of permission granting strategy. The result of this method is transmitted into permission evalutor. Thanks to that, it can send true if authorization occurs correctly and false if the authorization fails for the security identity.
Key classes of Spring Security ACL
In the previous part we saw some of methods used in authorization process. Now, we will see some of key classes and interfaces in Spring Security ACL infrastructure :
-
access control list
org.springframework.security.acls.model.Acl
Default implementation : org.springframework.security.acls.domain.AclImpl
This interface defines all ACL entries for a given object identity. Thanks to its implementations we can facility reach the instance of ObjectIdentity, Sid (object identity owner) and a list of control access entries (each line of access control list which implements AccessControlEntry interface).
One very important method is present in Acl interface. It's :
boolean isGranted(List
permission, List sids, boolean administrativeMode) The implementations of this method are invoked each time when permission evaluator checks if one security identity has sufficient permissions to access a protected element. In the default implementation of Acl, AclImpl, the isGranted method controls if security identities are correct and delegates the permission checking to permission granting strategy.
-
permission
org.springframework.security.acls.domain.AbstractPermission
Default implementation : org.springframework.security.acls.domain.BasePermission
A permission represents an action which every user can do on protected resources. It can be for example WRITE permission, represented in BasePermission class as :
public static final Permission WRITE = new BasePermission(1 << 1, 'W'); // 2
Note that you can use permissions in different objects. They can be Strings as well as Integers or Permission instances. The translation of them is done in the default implementation of permission evaluator, in the method List
resolvePermission(Object permission) . In some cases, this method uses an implementation of org.springframework.security.acls.domain.PermissionFactory to construct a Permission object. These implementations allows to construct Permission object from an integer mask (buildFromMask(int mask)), a String (buildFromName(String name)) and a list of Strings (buildFromNames(Listnames) ). -
lookup strategy
org.springframework.security.acls.jdbc.LookupStrategy
Default implementation : org.springframework.security.acls.jdbc.BasicLookupStrategy
A lookup strategy permits to find an appropriate access control entry or several access control lists. It constructs the Acl and Ace objects by converting java.sql.ResultSet in corresponding ACL objects. The implementations of LookupStrategy don't make any security checks. They are only the simple readers of the ACL datas from a specific resource (database, plaintext files etc.).
So, the LookupStrategy objects are the ACL data suppliers for theirs customers. And the main customer of lookup strategy is ACL service, presented in next line.
-
service
org.springframework.security.acls.model.AclService
Default implementation : org.springframework.security.acls.jdbc.JdbcMutableAclService
ACL service is a higher layer of lookup strategy. It invokes the functions which retrieve the ACL data without making a checks. The main difference between ACL service and a lookup strategy is the category of made operations. The lookup strategy is responsible for data reading whereas ACL service can read and write data too.
In the default implementation of AclService we can find the methods to get some ACL by object identity (readAclById(ObjectIdentity object, List
sids ), deleting an ACL for the given object identity (deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren)) or updating an ACL (updateAcl(MutableAcl acl)). -
voter
org.springframework.security.access.vote.AbstractAclVoter
Default implementation : org.springframework.security.acls.AclEntryVoter
It has a similar role to permission evaluator. The voter checks if one user can access secured resource. The voter makes that by checking user's role, usually prefixed by ROLE_ (RoleVoter is used), or by checking if the attribute corresponds to IS_AUTHENTICATED_ANONYMOUSLY (AuthenticatedVoter is used).
AclEntryVoter is more evolved form of voter. It permits to check if the user has sufficient rights to call a method protected by this voter.
Voter, unlike permission evaluator, can not take the decision. That means that it won't allow and disallow the access and will let the decision to AccessDecisionManager (ADM). ADM can decide to allow an access according to one of three following scenarios :
- affirmative : if at least one voter replies "yes" to access demand, user will be allowed to access protected element
- consensus : if majority of voters reply "yes", user will be able to access a protected resource.
- unanimous : every voter must return "yes" to allow an user to access to one protected resource.
So, voter is a kind of decision supplier and access decision manager is the decision maker.
-
object identity
org.springframework.security.acls.model.ObjectIdentity
Default implementation : org.springframework.security.acls.domain.ObjectIdentityImpl
The implementations of ObjectIdentity interface represent the object protected by user authorization. They contain some methods thanks to which we can retrieve human readable informations about protected resource, as getIdentifier (returns object identity id) or getType (returns objects stringified type, like for exemple "org.myprojects.db.entity.Article").
ObjectIdentity is used very often in searching methods, like JdbcAclService.readAclById, JdbcAclService.readAclsById or LookupStrategy.readAclsById. It helps to retrieve access control list linked with it. If we use the default Spring Security ACL implementation, ObjectIdentity represents the database table acl_object_identity.
-
access control entry
org.springframework.security.acls.model.AccessControlEntry
Default implementation : org.springframework.security.acls.domain.AccessControlEntryImpl
This is one entry of access control list. This entry contains the information about associated Permission, ObjectIdentity concerned by it and security identity (Sid) to whom belongs the entry. It also has a boolean property, granting, thanks to it we can check if the access to protected resource is allowed. The granting property has more of power than other properties of AccessControlEntry. It means that we can have an ACE corresponding to one SID with a WRITE permission. But if the value of granting property is false, the authorization will fail, event that a WRITE permission exists in the database (or plaintext file etc.)
-
permission granting strategy
org.springframework.security.acls.model.PermissionGrantingStrategy
Default implementation : org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy
The implementations of PermissionGrantingStrategy decide if one Sid can access to protected element. They do that by checking demanded permissions and comparing them with every ACL's AccessControlEntry permission. If both are equal and ACE's Sid is the same as the Sid of user to authorize, permission granting strategy considers that the user has sufficient permissions to access demanded element. Four major actors play in this strategy : ACL, ACE, permission and Sid.
-
permission evaluator
org.springframework.security.access.PermissionEvaluator
Default implementation : org.springframework.security.acls.AclPermissionEvaluator
It handles authorization expressions like @PreAuthorize or @PostAuthorize. The permission evaluator makes that by calling one of his hasPermission method. Both of them point on private function, checkPermission, that the result signifies if the user can execute protected method.
The permission checking is made thanks to Acl object. It's retrieved first with AclService's readAclById method. After that, the Acl's method isGranted() is invoked. In this method we use defined PermissionGrantingStrategy implementation to decide if the user is authorized to call the secured method.
-
security identity, granted authority
org.springframework.security.acls.model.Sid
Default implementations : org.springframework.security.acls.domain.PrincipalSid, org.springframework.security.acls.domain.GrantedAuthoritySid
The interface Sid is used to represent two very common authenticated user representations in Spring : Principal and GrantedAuthority. Both are stored at the same table in the database, acl_sid. They can be distinguish thanks to column principal. If its values is 1, Spring Security ACL will convert found ResultSet on PrincipalSid. In the other case, it will convert the result on GrantedAuthority. The conversion is made in BasicLookupStrategy.
Voters and permission evaluator
You are certainly a little bit troubled about the existence of two ways of authorizing somebody. As we can saw in the previous parts, voter plays the same role as permission evaluator. But they are some of subtle difference between them. Firstly, the architecture. Even if we can extend the voter as we want, it seems to be less evolved and flexible than permission evaluator. In fact, it will be harder to parse hasPermission expression by the voter. More, a lot of parsing code must be written by the programmer.
In additionally, the voter is the object more adapted to static checks, based for example on prefixed names like ROLE_*, IS_* etc. The invocation of these protections seems to be more weaker than the same invocation made by permission evaluator. The last invocation must pass by an expression handler.
Thirdly, the voter can't be used with the pre-post annotations. When we need to check if object returned by a method can be accessed by the user, @PostAuthorize annotation will be the only solution. To handle it, we'll need to pass by permission evaluator rather than by the roles.
And the last visible difference is the fact that the voter needs generally the help of an access decision manager (ADM). An access decision manager is a container of voters which, regarding of chosen scenario (affirmative, consensus, unanimous), allows or disallows access to a protected resource. And if one access decision manager is set, Spring will call it to check user's access permissions. ADM will iterate through every known voter and check if the voter allows the access. Permission evaluator goes directly to the goal without checking unusable decision makers.
In this article we discovered how Spring Security authorization (ACL) process works. The first part presented the theoretical concepts of authorization, with the list of authorization actors. In the next part, we saw the authorization flow in Spring Security project. The third one talked a little bit more about the project's key classes. At the end we learned which were the differences between two similar authorization ideas : role and permission evaluator.
Consulting

With nearly 16 years of experience, including 8 as data engineer, I offer expert consulting to design and optimize scalable data solutions.
As an O’Reilly author, Data+AI Summit speaker, and blogger, I bring cutting-edge insights to modernize infrastructure, build robust pipelines, and
drive data-driven decision-making. Let's transform your data challenges into opportunities—reach out to elevate your data engineering game today!
👉 contact@waitingforcode.com
đź”— past projects