Chapter 7. Authorizing user requests
This chapter covers
- Implementing authorization using Spring Security
- Using authentication levels, roles, and permissions
- Establishing access control lists
Authorization is the area of security that deals with protecting resources from users or systems—generically, principals—which aren’t allowed to view, modify, or otherwise access them. It generally builds on authentication. Authentication establishes the principal’s identity, and authorization decides what the principal is allowed to do. This chapter continues the treatment of Spring Security we began in chapter 6, this time exploring its authorization features.
Figure 7.1 shows the relationship between the types of authorization in Spring Security 3. On the one hand we have authorization targets, which correspond to what is being protected: methods, views, and web resources. On the other we have authorization styles, or how we’re protecting the targets: via authentication levels, roles, and access control lists (ACLs). Conceptually we’ll break authorization into the grid in table 7.1.
Table 7.1. Authorization combinations and their corresponding recipes
Authorization style |
Authentication target |
||
---|---|---|---|
Methods | Views | Web resources | |
Authentication-, role- and permission-based | Recipe 7.1 | Recipe 7.2 | Recipe 7.3 |
ACL-based | Recipe 7.4 | Recipe 7.5 | Unsupported |
Each recipe addresses one of the cells in the table.
Spring Security allows you to authorize the three target types that appear as columns in table 7.1:
- Methods— We often need to protect Java methods from unauthorized access. We can define access rules on a per-method basis.
- Views— JSPs frequently contain navigation and content that we want to show or hide according to the user’s permissions. For example, if the user doesn’t have access to an admin console, it probably doesn’t make sense to show the link to the admin console in the first place. We also need a way to suppress page content when the user isn’t allowed to see it. Spring Security has tag libraries to help here.
- Web resources— We can grant or deny access to different HTTP requests based on the associated URLs and HTTP methods.
There are other targets—for example, databases and SMTP mailers—but security for such resources is typically handled by the resource itself. We won’t discuss those here.
The two rows in table 7.1 deal with how access is determined. There are two complementary approaches:
- Authentication-, role-, and permission-based authorization— Authentication-based authorization uses authentication levels to determine access. Authentication levels range from anonymous (not authenticated) to remembered (authenticated via remember-me) to fully authenticated. Role-based authorization involves assigning roles to individual users and then using those roles to determine what users can see and do, ideally through associated permissions.
- ACL-based authorization— ACLs control access to an application’s domain objects based on user permissions attaching to those domain objects. For example, I have access to my inbox but not yours. Because ACLs attach to domain objects, people often refer to this authorization style as domain object authorization or domain object security.
The following recipes center around a discussion forum sample application. The first three recipes cover authentication- and role-based authorization. The last two recipes deal with ACL-based authorization.
Recipe 6.1 Implementing login and logout with remember-me authentication
Spring Security 3
There are multiple reasons to protect Java methods from unauthorized access:
- To consolidate the definition of access rules so they can be managed in one place instead of being distributed and repeated across multiple clients
- To avoid having to rely on potentially untrusted clients to enforce access rules
- To provide for defense-in-depth, which is a security best practice
Spring Security allows you to define access rules, using either XML or annotations, that you can apply to Java service methods. We’ll focus in this chapter on the annotation-based approach.
Secure service methods by defining authentication- and role-based access rules.
Approaches to securing Java methods involve defining rules that specify who has access to which methods. You’ll define access rules using annotations, although XML-based rules are also an option. Consult the Spring Security reference documentation for information on using security pointcuts and AOP to secure Java methods. These recipes require that your Maven configuration be set up as described under “Building and Configuration” at http://springinpractice.com/code-and-setup to enable Jetty startup to find the jetty-env.xml configuration file.
The first thing to understand is how to define an access rule. Let’s take the “who” part first. As of Spring 3, you can use the SpEL to define who has access to a target (whether a method or otherwise). Table 7.2 shows the predicates for defining authentication- and role-based access rules.
Table 7.2. SpEL predicates for defining authentication- and role-based access controls
Predicate |
Truth condition |
---|---|
permitAll | Always true (truth constant). |
denyAll | Always false (falsity constant). |
isAnonymous() | Principal is anonymous. |
isAuthenticated() | Principal isn’t anonymous. |
isRememberMe() | Principal authenticated via remember-me. |
isFullyAuthenticated() | Principal authenticated by providing credentials explicitly. |
hasRole(role) | Principal has the specified role. |
hasAnyRole(role1, role2, ..., role n) | Principal has at least one of the specified roles. |
hasIpAddress(ipAddr) | Client IP address matches a specified address. ipAddr can be either a single IP address or a range of IP addresses using IP/netmask notation. (Available only in web contexts.) |
With the annotation-based approach, you add security annotations to your service beans, and then you add a single line to your beans-security.xml configuration.
Let’s look at an example. You’ll secure the ForumServiceImpl service bean in the sample app. This service allows clients to access forum-related functionality, like getting forums, updating messages in a forum, and so on. For now, your rules will be simple, although later you’ll refine them. They will be things like these:
- The user must have a general, application-wide “read forums” permission to get a forum or forums from the service.
- The user must have a general, application-wide “create messages” permission to post a message to a forum.
You get the idea. Let’s implement the rules using Spring Security annotations. Listing 7.1 shows what ForumServiceImpl.java looks like with the annotations in place.
Despite its simplicity, this code snippet uses two key techniques that we need to discuss in a little detail. Let’s cover the raw mechanics, then we’ll look at the bigger picture.
The class-level @PreAuthorize annotation defines a default denyAll rule for the methods in the class . The denyAll rule rejects access no matter what. That may seem like a strange thing to do, but it’s one of the key techniques that we’ll discuss momentarily.
@PreAuthorize means the denyAll check takes place before entering the method; there’s also an @PostAuthorize annotation that’s similar but performs a check after exiting the method. You’ll see use cases for @PostAuthorize in recipe 7.4.
The default applies unless individual methods override it with method-level annotations. Of course, denying access to everybody doesn’t make for a useful method. So at you override the default denyAll rule by specifying that having the PERM_READ_FORUMS permission is a necessary and sufficient condition for entering the getForums() method. Similarly, at
you create a rule that says that having the PERM_CREATE_MESSAGES permission is necessary and sufficient for entering the createMessage() method.
You might wonder why you’re using a hasRole() predicate to check for a permission, because roles and permissions aren’t the same thing.[1] That gets to the second key technique we need to discuss. Without further ado, here are the two techniques.
1 A role typically entails a set of permissions. The “release engineer” role, for example, might have permission to deploy software packages to servers.
Broadly speaking, there are two approaches to authorization: whitelisting and blacklisting. Whitelisting denies requests unless they’re explicitly granted (on the whitelist), whereas blacklisting grants requests unless they’re explicitly forbidden (on the blacklist). Whitelisting, as the more paranoid, generally makes for better security, and security professionals consider it a best practice. Use it whenever it’s practical to do so.
Your default denyAll rule is effectively a whitelist implementation. If somebody adds a new method to ForumServiceImpl and forgets to attach an access rule, the default rule prevents anybody from using the method.
Tip
Whitelisting is a security best practice. Use class-level @PreAuthorize ("denyAll") annotations to implement whitelists.
Now let’s look at the second key technique.
The goal behind this technique is to avoid embedding security policy decisions in the code. Such decisions should be set at runtime because they vary across customers, they vary over time, and sometimes they need to be changed immediately (for example, in response to a security breach).
Consider, for example, the difference between this rule
and this one:
The first rule breaks when somebody decides that teaching assistants, parents, faculty trainers, accreditors, or any number of other roles should gain access, or that one of the roles should lose access (for instance, faculty-only forums). The roles may be different for different customers using the software, and many of the roles may not make any sense for some customers.
The second rule is more resilient in the face of such changes, because in essence it says that a user can access a given forum if they have read access to forums generally. The rule isn’t perfect—you may decide there isn’t any such thing as read access to forums generally (that is, access exists on a forum-by-forum basis)—but clearly it’s much more flexible, especially if you can establish the relationship between roles and permissions outside of the code itself. And you can certainly do that.
As a general rule, prefer permission-based rules to role-based rules. There are exceptions (you’ll see an example in recipe 7.2), but it holds in general.
Spring Security 3 appears schizophrenic on the issue of separating roles and permissions. The interface underlying ROLE_STUDENT, PERM_READ_FORUMS, and so forth is called GrantedAuthority, and this sounds like a fancy way of saying permission rather than role. But the examples in the Spring Security reference documentation tend to treat granted authorities as roles; even the hasRole() and hasAnyRole() predicates steer you toward using roles directly, which is at best a questionable practice for the reasons already given.[2]
2 See Willie Wheeler, “Quick tip: Spring Security role-based authorization and permissions,” October 27, 2010, http://mng.bz/010n, for a more extended treatment of this topic.
Apparent schizophrenia aside, Spring Security makes it easy to do the right thing. The sample code, for instance, uses a custom UserDetailsService backed by the user/role/permission schema shown in figure 7.2.[3] The src/main/sql/schema.sql script contains this schema, but it’s just an example. Even if you’re using JdbcDaoImpl instead of a custom UserDetailsService, you can take advantage of the Spring Security group schema to separate roles and permissions.[4]
3 The sample code uses BIGINTs but in real life you’ll almost certainly want to use a smaller type, like INTs or even smaller. This will improve indexing and conserve storage. Of course, if you do need room for 18 quintillion accounts, then BIGINT is the data type for you.
4 See Rich Freedman, “Spring Security Database Schema,” August 19, 2008, http://mng.bz/NsB0, for more information. The basic idea is that groups are roles and granted authorities are permissions. The group schema itself is similar to figure 7.2.
In addition to the schema, you also need sample data so you can test the security configuration. Figure 7.3 shows the roles and permissions that each sample user has, as contained in the src/main/sql/data.sql script.
That’s it for source code changes. Now you need to activate the security annotations. To do that, you add a single line to the beans-security.xml configuration from recipe 6.1:
You’ve enabled Spring Security’s pre- and post-annotations, disabled by default, because they allow you to use SpEL to define access rules in an elegant fashion. This is the preferred approach in Spring Security 3. There are a couple of other options, which we’ll list for completeness:
- jsr250-annotations="enabled"—Activates the standard JSR 250 security annotations. Although these are standard, they support only simple role-based rules and aren’t nearly as powerful as Spring Security’s pre/post annotations. These are disabled by default.
- secured-annotations="enabled"—Support for Spring’s legacy @Secured annotation. Originally superseded by the JSR 250 @RolesAllowed annotation, and now by the Spring Security @PreAuthorize annotation. @Secured is disabled by default.
That’s annotation-based configuration. To try the security annotations, try the following:
1. Start up the application, and click the Forums link. Spring Security forces a login because the call to getForums() requires the PERM_READ_FORUMS permission.
2. Log in as user daniel/p@ssword. He has just the student role.
3. Go into one of the forums, select a message, and try to block it (the link is available at the bottom of the message). You should get an error message in a dialog box because the ForumServiceImpl.setMessageVisible() method requires the PERM_ADMIN_MESSAGES permission, which the student role doesn’t have.
4. Try the same thing with editing and deleting messages. You’ll be able to access the edit page and the delete confirm box. But there will be an error message when you try to save the edit or confirm the deletion, because the student role doesn’t have the required PERM_UPDATE_MESSAGES and PERM_DELETE_MESSAGES permissions.
5. Log out, and then log back in under juan/p@ssword. User juan has the admin role. Try the same operations. You should be able to execute all of them, because the admin role has the required permissions.
The first authorization recipe showed how to create authorization rules and apply them to Java methods. You’ve focused on applying them to Java service beans, although it’s also possible to use Spring Security with AspectJ to attach authorization rules to domain objects when implementing a domain-driven design.
The next recipe shows how to secure views by applying authorization rules to code fragments inside a JSP.
Recipe 6.1 Implementing login and logout with remember-me authentication
Spring Security 3 (including tag library), Spring Expression Language
In many cases it’s necessary to suppress JSP fragments.[5] One case would be where the fragment contains content the user isn’t authorized to view. Another is where the fragment contains navigation pointing to pages the user isn’t allowed to access.[6] This recipe shows how to use Spring Security 3 to implement this type of suppression.
5 Here we mean subsets of the content inside a JSP, rather than .jspf files per se.
6 Note that there are also plenty of cases where it does make sense to show navigation that points to features or content the user can’t access. One such example would involve trying to entice the user to purchase premium features or content.
We’ll use a basic forum application to illustrate the techniques involved.
Show or hide JSP page fragments based on the user’s authentication level and role.
Recipe 7.1 showed how to accomplish authorization based on authentication levels. We’ll show how to add authorization based on roles and permissions. The main tool here is the Spring Security tag library.
Figure 7.4 presents the page navigation. The Home link appears for all users. The Forums link is present if the user has the read forums permission. The My Account and Logout (not displayed) links appear only if the user is authenticated; otherwise a Login link appears. Finally, the Admin link appears only if the user has the admin role.
To control the display, you use the <spring:authorize access="[predicate]"> JSP tag along with SpEL predicates you saw in recipe 7.1. The tag displays its body if and only if the predicate evaluates true against the current principal.
Listing 7.2 shows how you use the predicates to implement the desired display controls.

As in recipe 6.1, you use the Spring Security tag library to implement page fragment shows and hides, and you use isAnonymous()
and isAuthenticated()
to decide whether to greet the user as a guest or by name. You use the same predicates to control the visibility of the My Account, Login, and Logout links.
The new piece is hasRole(). At you use it to show the Forums link according to whether the user has the PERM_READ_FORUMS permission, and at
you use it to show the Admin link based on whether the user has the ROLE_ADMIN role. Keep in mind (as discussed in recipe 7.1) that the hasRole() predicate is a test for whether the specified granted authority exists; the granted authority doesn’t strictly have to be a role.
Recall that recipe 7.1 mentioned that sometimes it does make sense to build access rules based on roles rather than permissions. Listing 7.2 provides a case in point. Here, it makes sense to tie the Admin page directly to the admin role, because that rule is unlikely to require revision: the page specifically targets the role. Similarly, it’s fine to tie the Login link to isAnonymous(), and it’s appropriate to tie the My Account and Logout links to isAuthenticated().
There is a second way to specify access conditions for <security:authorize> tags. Instead of defining an access attribute, you can define a url attribute, along with an optional method attribute for HTTP methods, to establish an access condition. The idea is that the tag displays its body if and only if the user has access to the URL via the method in question. You’ll see how to define access controls on a URL and method in the next recipe.
This approach is useful when rendering navigation, because it allows you to bind the visibility of a given navigation item to its access definition instead of duplicating what’s essentially a single rule. You’ll put this technique into use in recipe 7.3.
What about the other <security:authorize> attributes?
The <security:authorize> tag has other attributes we haven’t covered: ifAnyGranted, ifAllGranted, and ifNotGranted. These are deprecated; use either access or url and method instead.
This recipe showed how to hide links and content based on user authentication levels and roles. In the case of links, developers sometimes use the technique of hiding links as a substitute for proper access controls. This is known as security by obscurity and isn’t generally considered real security, because users can still enter the target URL directly into the browser if they know or guess it.[7] Instead, the techniques in this recipe are more like user experience and usability techniques than security techniques where navigation and links are concerned. To defend the link targets against unauthorized access, it will help to have a way to selectively permit or deny HTTP requests, and that’s what the next recipe shows how to do.
7 Try it using http://localhost:8080/sip/main/admin.html and some account other than juan. You’ll find that you can still get to the admin page.
Recipe 6.1 Implementing login and logout with remember-me authentication
Spring Security 3
In recipe 7.2, you saw how to display web-page content based on user authentication levels, roles, and permissions. This is often used as a way to keep the UI streamlined; in most cases it doesn’t make sense to show users links that they aren’t allowed to use.
But it’s important not to mistake obscurity for security. Just because the link is hidden doesn’t mean users can’t get to it. To have real security, you must protect your web resources with access rules. This recipe shows how to do that.
Control users’ access to web resources according to their authentication level, roles, and permissions.
You’ll continue using Spring Security 3 to implement authentication-, role-, and permission-based authentication for the web URLs in your sample forum application. The relevant code is in the beans-security.xml file. You use the intercept-url element to define access rules for web URLs as shown in the following listing.

To define access rules, you once again take advantage of SpEL. You do that by setting use-expressions="true" at . Prior to Spring Security 3, there was a non-SpEL method of defining rules. That approach is now legacy, so we won’t cover it here.
Now you have the <intercept-url> rules. Before looking at the specific rules, let’s discuss the high-level approach and some details about the mechanics of defining a rule.
As with recipe 7.1, you adopt the best practice of defining access on a whitelist model. To implement a whitelist, bear in mind that rules are evaluated on a first-match basis; that is, the first rule in the list with a pattern that matches the request URL is the rule that applies. Therefore you need to place more specific patterns before more general patterns. You make your list a whitelist by making the most general rule one that denies access to all resources using denyAll.
To specify rules, you use a URL pattern, an optional HTTP method (GET, POST, PUT, DELETE, and so on), and either filters="none" or access="[predicate]". The rule applies to all HTTP methods if the method is omitted. The first option, filters="none", indicates that the pattern and method don’t require authentication, authorization, or any other security services. The second option allows you to use SpEL to define the conditions under which the user can use the URL/method pair in question.
The patterns have two possible syntaxes, which you choose by setting the path-type attribute on the containing <http> element. The default syntax is Ant, which uses either path-type="ant" or nothing because it’s the default. The alternative is regular expression syntax via path-type="regex". You’ll use the default Ant-style syntax.
Now let’s look at the specific rules. The first four use filters="none" to indicate that neither the skin files nor the static assets (images, CSS, JavaScript) require security services .
Next you have rules for specific URL and method combinations. Although the methods are optional, it’s a good practice to specify them explicitly to avoid opening up access unnecessarily. (This is very much in line with the whitelist approach.) At you use permitAll to specify that GET requests for the home page are always to be granted. At
you use hasRole('ROLE_ADMIN') to ensure that only administrators have access to the admin page. You define additional access rules for forums and messages at
and
. Although it would have been possible to use Ant’s ** wildcard to shorten the list of rules, doing so would effectively create a blacklist inside of the whitelist, and from a security perspective it’s safer to require grants to be explicit.
At you create the denyAll rule that makes your rule list a whitelist.
To test this:
- Try to access http://localhost:8080/sip/admin.html anonymously by manually entering it in the browser’s address bar. You should be redirected to a login page. If you log in as juan, the request should succeed; otherwise, you should get the access-denied page.
- Log into the app as elvira using the normal login process. Once you’ve done so, manually enter the admin URL from the previous bullet. Unlike in recipe 7.2, you should now get the access-denied page.
There’s one loose end to tie up before we move on to the next recipe.
In recipe 7.2, we pointed out that it’s possible to specify <security:authorize> access rules in terms of URLs and HTTP methods instead of defining access conditions explicitly. Recall that the idea is to bind the display of a navigation item to the user’s access to that item such that you can define the access rule in a single location (such as beans-security.xml) instead of defining it in two. Indeed, let’s update subhead.jspf to take advantage of this feature (see listing 7.2 for the original listing):
Now, when you change the rules in beans-security.xml, the <security:authorize> tag’s behavior automatically reflects the change. You can define rules authoritatively in the Spring Security configuration file instead of duplicating rule definitions in the JSPs.
In the preceding three recipes, you’ve assumed fairly simple requirements around access, mostly around application-wide roles and permissions. For example, you’ve assumed that users either do or don’t have permission to edit messages.
Real-world access requirements tend to be more nuanced. You might want each forum to have a moderator with administrative privileges over that forum, rather than having just a single site administrator. For any given message, you might want the site admin, the forum moderator, and the original author to have edit permissions, but no one else. You might want the site admin and forum moderator to be able to block, unblock, and delete messages, but nobody else.
The requirements just described require machinery more powerful than that offered so far, because they’re based not on simple application-wide permissions but on relationships between a principal and a domain object being accessed. A given user either is or isn’t the moderator for a given forum, and the answer makes a difference in terms of what the user is allowed to do with messages in that forum.
Recipes 7.4 and 7.5 show how to implement domain object security using Spring Security 3 access control lists.
Recipe 6.1 Implementing login and logout with remember-me authentication
Recipe 7.1 Authorizing Java methods using authentication levels, roles, and permissions
Spring Security 3
This is the first of two recipes that deal with authorizing access to and displaying specific domain objects that exist in your system. Keeping with the discussion forum example, imagine that you want to allow the author, the forum moderator, and the site admin to edit a message after it’s been posted, and nobody else. Additionally, moderators must be able to block, unblock, and delete messages in forums they moderate.[8]
8 You’ll handle part of this requirement around blocking, unblocking, and deleting messages in this recipe. Recipe 7.5 completes the treatment of that requirement.
Enter access control lists (ACLs). The idea is that each domain object has an associated list of access rules specifying who is allowed to do what with the object. Each rule, more formally known as an access control entry (ACE), specifies an actor, an action, and either grant or deny, indicating whether the actor may perform the action on the domain object. The end result is that you can resolve questions like, “Can Juan edit message 106?” This gives you the ability to define fine-grained access rules. See figure 7.5 for a visual explanation of access control lists.
Figure 7.5. An ACL for a message. The author has one set of permissions with respect to the message, and other users have other permissions.

Speaking more conceptually, you have actors, targets, and actions. Actors (like Daniel) want to perform actions (like editing) against domain object targets (like message 106). You need to decide in any given instance whether the desired action is permissible. This is where Spring Security’s ACL module helps.
ACL-based authorization is more complex than role-based authorization. With role-based authorization, you manage predicates on principals without worrying about specific targets. You can use role-based authorization to answer questions like. “Can Daniel edit messages generally?” ACL-based authorization is finer-grained and involves managing relationships between actors and targets. Figure 7.6 shows the difference between role-based and ACL-based authorization.
Figure 7.6. With rolebased authorization, a user might have permission to (say) edit messages in general. With ACL-based authorization, you can set user edit permissions on a message-by-message basis.

With that background, you’re ready to tackle the rest of the recipe.
Authorize service method invocations involving domain objects based on the relationship between the principal and the domain object(s) in question. Specifically, the author, the forum moderator, and the site admin must be able to edit existing posts. You also need to lay the groundwork allowing moderators to block, unblock, and delete posts, although that will require additional work in recipe 7.5.
You’ll use the Spring Security ACL module to implement domain object authorization. Here’s a roadmap of the recipe ahead:
- Defining domain object ACLs— First we’ll cover the basics of granting (or, less commonly, denying) user permissions on domain objects using the ACL database schema to drive the discussion. (For example, “Daniel has permission to edit message 106.”)
- Defining ACL-based access rules for Java methods— You’ll see how to use annotations to define ACL-based access rules, specified in terms of user permissions, on Java methods. (For example, “Allow the method invocation if the current user has permission to edit the passed message.”)
- Configuring Spring Security for ACLs— You need configuration to activate domain object security. You’ll learn how to do that.
- Optimizing ACL definition— We’ll look at ways to simplify and streamline ACL definitions.
- Manipulating ACLs programmatically— We’ll look at programmatic manipulation of ACL data, which is often necessary in cases where the app creates new domain objects. (For example, give the author of a new message permission to edit the message even after it has already been posted.)
Because the ACL module is database-driven, you’ll start there both to get a good grasp of the key concepts and details on the database schema. Note that the schema we’re about to cover replaces the one from the earlier recipes, so you should rebuild the database using the scripts at src/main/sql at this time.
To begin, you need to understand some key ACL concepts and how to define user permissions on domain objects so you can define access rules in terms of said permissions. The ACL database schema is the logical place to start both because it highlights the concepts and because it’s where you define the user permissions.
The ACL module has four tables to store actors, actions, and targets (domain objects). Together they provide a framework for defining access rules for specific domain objects. Spring Security uses the access rules to make access decisions.
Figure 7.7 is the E/R diagram for the ACL module. Again, see the sample code for the MySQL scripts.[9]
9 Alternatively, see Willie Wheeler, “Spring Security 3 database schemas for MySQL,” July 6, 2010, http://mng.bz/Q3IZ.
Tip
In figure 7.7, all the IDs are MySQL BIGINTs. It’s unlikely in the extreme that you’ll require BIGINTs for your dataset, and using them consumes space unnecessarily. It pays to think about your expected data volumes and choose data widths accordingly.
Let’s go over the tables in detail because it will help you better understand how ACL-based security works. As an example, you’ll define a rule that grants user daniel permission to edit message 106.
You represent actors using the acl_sid table. A security identity (SID) can be a principal such as an end user or a system or a granted authority such as the admin role or even a system-wide permission as noted in recipe 7.1.
The principal column is a flag indicating whether the SID is a principal or a granted authority, and the sid column contains a username or granted authority name accordingly. Together the principal and sid columns allow Spring Security to associate SIDs in the ACL schema with app users and granted authorities, as figure 7.8 shows.
Figure 7.8. How Spring Security links its ACL schema to its user schema. This allows Spring Security to support custom app objects because the Spring Security user schema uses Java interfaces.

To be concrete, consider user daniel with a role called ROLE_USER. Table 7.3 shows how the sample app maps these to rows in the acl_sid table.
The IDs are arbitrary, but the other columns aren’t. SID 100 is the granted authority (here, a role) called ROLE_USER. There is a corresponding row—that is, a row where the name is ROLE_USER—in your application’s role table. SID 201 is the principal named daniel. Once again there is a corresponding row—a row where the username is daniel—in your application’s account table. (See the sample code.)
You represent domain object targets using the acl_class and acl_object_identity tables, which model domain object types and instances, respectively. In the acl_class table, there are only two columns: id and class. The id column is an arbitrary ID. The class column holds a fully qualified classname, such as com.springinpractice.ch07 .domain.Message.
There’s a lot going on in acl_object_identity, whose rows are referred to as OIDs. Each OID is Spring Security’s representation of an application domain object. The object_id_class column references the acl_class table and allows you to specify the domain object’s type. The object_id_identity column is for the domain object’s native ID, which Spring Security assumes to be numeric and exposed by an id property on the domain object. Together these two columns pick out a domain object.
Continuing with the example, suppose you want to represent message ID 106. You need to create a corresponding OID using the acl_class and acl_object_identity tables in the ACL schema. (If the class already exists in acl_class, then you need create only a row in acl_object_identity.) Figure 7.9 presents the situation schematically.
Tables 7.4 and 7.5 show the same thing in record form.
Table 7.4. Representing messages generally using acl_class
id |
class |
---|---|
3 | com.springinpractice.ch07.domain.Message |
Table 7.5. Representing message 106 using acl_object_identity (some columns suppressed)
id |
object_id_class |
object_id_identity |
---|---|---|
112 | 3 | 106 |
In tables 7.4 and 7.5, the IDs in the id column (3 and 112 for class and OID, respectively) are arbitrary. But the ID in the object_id_identity column isn’t. It contains the message’s native ID, which is 106.
We’ve focused on a subset of the OID columns, but there are a few other columns: parent_object, entries_inheriting, and owner_id. These are more advanced in nature, so we’ll ignore them in this first pass and return to them shortly.
Actions are what SIDs want to do with OIDs, such as creating or editing them. Each row in the acl_entry table, or ACE, is essentially an assertion to the effect that such-and-such SID either does or doesn’t have permission to perform such-and-such action on such-and-such OID. Each ACE involves a SID, an OID, a permission, and either grant or deny. The list of ACEs for a given OID is the OID’s ACL.
Let’s talk about permissions. The simplest way to think about permissions is that the BasePermission class defines five default permissions with associated codes (masks), as shown in table 7.6.
Table 7.6. ACL permissions and their numeric values
Permission |
Mask |
Notes |
---|---|---|
READ | 1 | |
WRITE | 2 | |
CREATE | 4 | |
DELETE | 8 | |
ADMINISTRATION | 16 | Principals with this permission can manipulate the object’s ACL. |
The precise interpretation of the specific permissions depends on the application, but they correspond to the standard CRUD (create, read, update and delete) operations plus an administrative operation. Principals with the administrative permission are able to manage the corresponding object’s ACL (add or remove ACEs, change parent, change ownership, change audit information, and so on). There are other ways to be able to manage object ACLs, and you’ll see those later in the recipe.
Up to 32 distinct permissions are possible, although the 5 just given should be sufficient for many use cases. If you create additional permissions, their masks must be powers of 2.[10]
10 In some cases custom permissions are helpful. Our current project, for instance, is a software deployment automation system. Permission to deploy to environments like dev, test, and prod varies with role; for example, developers can deploy to the development environment but not to production. We distinguish the ability to update the environment domain object from the ability to update the real-world environment. We use the standard WRITE permission for the former and a custom DEPLOY permission for the latter, because the ability to update an environment’s description (say) is distinct from the ability to deploy a change to it.
Use only one ACE per permission
Spring Security supports up to 32 permissions: the 5 defaults from table 7.6 and up to 27 custom permissions. You can represent individual permissions using a bit index i (0-31) or, equivalently, as integers of the form 2i, which explains why the default codes are all powers of 2. So far, so good.
Besides representing individual permissions, you might want to represent sets of permissions, as when granting such-and-such user both READ and WRITE permissions on some message. Bitmasks are a well-established and economical way to do that. The number 3, for instance, represents this combination because 3 = 1 (READ) + 2 (WRITE).
Unfortunately, despite the use of the mask terminology in the database table and in the API, the default ACL implementation, AclImpl, doesn’t support arbitrary bitmasks. You can’t grant READ and WRITE using a single ACE with the mask set to 3. Instead you need to create an ACE for the READ permission and a second ACE for the WRITE permission. The reason is somewhat difficult,[11] but suffice to say that many Spring Security beginners understandably but incorrectly assume that they can place bitmasks in the mask column.
11 For a detailed explanation, see “ACE masks are not being compared as bitmasks,” https://jira.springsource.org/browse/SEC-1140.
It looks like Spring Security 3.1 will make it possible for AclImpl to treat the mask as a true bitmask using a strategy interface.[12]
12 “Provide strategy interface for AclImpl isGranted() method,” https://jira.springsource.org/browse/SEC-1166.
There’s also a granting flag. If it’s 1, the ACE grants the permission. If it’s 0, the ACE denies the permission.
Table 7.7 shows a sample ACE, one that grants the edit (a.k.a. write) permission to your hero daniel for message 106.
Table 7.7. Granting Daniel permission to edit message 106 (some columns suppressed)
id |
acl_object_identity |
ace_order |
sid |
mask |
granting |
---|---|---|---|---|---|
42 | 112 | 0 | 201 | 2 | 1 |
SID 201 corresponds to daniel as per table 7.3, and OID 112 corresponds to message 106 as per table 7.5. The mask value 2 indicates the WRITE permission as per table 7.6, and granting value 1 means that you’re granting the permission rather than denying it.
The ace_order column is the ACE’s 0-indexed order in the domain object’s ACL. The org.springframework.security.acls.model.Acl interface doesn’t specify semantics for the ACE order. See the Javadoc for AclImpl.isGranted() for details on how the order matters for the default AclImpl implementation.[13]
13 It’s fairly complicated, but the basic idea is that the first matching ACE is the one that wins. But that’s a simplification; again, consult the Javadoc for details.
Those are the basics. You’re now ready to learn how to define access rules on Java methods in terms of user permissions like the one you’ve just defined.
You saw in recipe 7.1 that Spring Security provides an @PreAuthorize annotation that allows you to define access rules for Java methods using SpEL expressions. In recipe 7.1 you defined rules in terms of authentication status, roles, and system-wide permissions. But now you’re going to define rules in terms of permissions on domain objects.
As it happens, Spring Security supports several access-control annotations, as shown in table 7.8.
Table 7.8. Annotations for controlling access to Java methods
Annotation |
Description |
---|---|
@PreAuthorize(expression) | Checks the expression before allowing access to the annotated method |
@PostAuthorize(expression) | Checks the expression after executing the method but before returning the return value to the caller |
@PreFilter(value=expression [, filterTarget=collection]) | Filters a collection of domain objects before passing it into the annotated method |
@PostFilter(expression) | Filters a collection of domain objects returned from the annotated method before returning them to the caller |
As we just mentioned, the expressions can reference domain objects. Table 7.9 introduces the SpEL expressions that support this.
Table 7.9. SpEL expressions for domain object security
Expression |
Description |
---|---|
#paramName | Variable referring to a method argument by parameter name. |
filterObject | Term referring to an arbitrary collection element in a filter annotation (either @PreFilter or @PostFilter). |
returnValue | Term referring to the method’s return value. Used in @PostAuthorize. |
hasPermission( domainObject, permission) | Predicate indicating whether the current principal has a given permission on a given domain object. Legal values for permission are read, write, create, delete, and admin (no quotes). |
Let’s look at a few examples from the class ForumServiceImpl in the sample code.
First, here’s @PreAuthorize:
In the snippet, the rule is to allow entry into the method if and only if the current principal has the delete permission on the message being passed in. Spring Security checks this by matching on the Message class and domain object ID as previously described. You use the special variable syntax, #message, to reference the passed message.[14]
14 If you’re wondering how Spring Security knows the parameter name, the answer is that it uses compiler debug information. You must compile the code with the debug local variable information turned on in order for this feature to work. There are other such examples in Spring, especially in Spring Web MVC.
The @PostAuthorize annotation isn’t as generally useful as @PreAuthorize, but it has its uses. Sometimes you want to drive access decisions based on something other than object IDs. For instance, the sample app allows forum moderators and site admins to block messages. Only users with the admin permission on a blocked message should be able to see it. The following code snippet shows how to use the @PostAuthorize annotation to accomplish this:
In this example, you have no way of knowing whether the message is visible based on the message ID alone. You have to get the message (using the special returnObject term), check for the read permission (using the hasPermission predicate), and then check its visibility. @PostAuthorize is useful in such cases.
Notice that you’re also using a @PreAuthorize("permitAll") annotation. The reason is that ForumServiceImpl has a type-level @PreAuthorize("denyAll") annotation whose purpose is to create a whitelist security model as we explained in recipe 7.1. You have to override that annotation so calls can enter the method.
The sample app doesn’t use the @PreFilter annotation, and it’s not commonly used, but for completeness we’ll say something about it here. Prefiltering can be useful where bulk operations on domain objects are concerned. It allows you to remove a domain object from the bulk operation when the current principal doesn’t have permission to perform the operation on that domain object. The domain objects need to be part of a java.util.Collection (an array won’t work), and the Collection needs to support the remove() method. Null values in the collection aren’t allowed.
Suppose, hypothetically, that you wanted to support a bulk delete on messages. The following code would allow you to do that:
You’d need to use @PreAuthorize("permitAll"). But after that, you’d use the @PreFilter annotation with the special filterObject (representing an arbitrary collection element) and hasPermission expressions to exclude messages for which the current principal lacks the delete permission.
In this case you have only one collection parameter, but if you had more than one, you’d use the filterTarget element to choose one.
When a method returns a collection of domain objects, sometimes you want to filter out individual elements before handing them over to the caller. That’s what @PostFilter is for. The following snippet includes a given forum in the result set if—and only if—the principal has read permission on the forum:
As with @PreFilter, you use filterObject and hasPermission to perform the desired filtering.
The annotations define the access rules, but you need to activate them to make them do anything. You’ll need to add configuration to make that work.
There are a couple of different pieces to the configuration. First, you make a minor tweak to the <global-method-security> definition in beans-security.xml:
Here you add an explicit expression handler definition to the <global-method-security> definition. Although <global-method-security> creates a default expression handler, it can’t handle hasPermission() expressions because it doesn’t come with a permission handler. You address that with a new beans-security-acl.xml configuration as shown next.

Figure 7.10 is the same expression handler configuration as a bean dependency graph.
You use the beans namespace in listing 7.4 rather than the security namespace. The security namespace doesn’t (at the time of this writing, anyway) directly support ACL configuration, so you need to do everything explicitly.
First you define the expression handler . It’s still the default expression handler, but you’re giving it a nondefault configuration by injecting a permission evaluator that knows how to handle hasPermission() expressions, which is the whole point of the beans-security-acl.xml configuration. The specific permission evaluator you need is the AclPermissionEvaluator, so you create one at
.
The permission evaluator relies on an ACL service for ACL CRUD operations. You use a JdbcMutableAclService because your ACLs are in a database (that’s the JDBC part) and you want to be able to create, update, and delete ACLs as you create, update, and delete the corresponding domain objects (that’s the mutable part). Because it’s a JDBC-based ACL service, you inject a data source. The service also uses caching for performance, so you inject an Ehcache-backed cache too
.[15]
15 Don’t forget to configure your Ehcache, at least for production. See http://ehcache.org/documentation/configuration.html for information on how to do that.
ACL lookups are the most common operation, so for performance the ACL service delegates them to a LookupStrategy. This allows you to adopt DBMS-specific optimizations as desired. For simplicity you use a BasicLookupStrategy , which is based on ANSI SQL. It doesn’t have DBMS-specific optimizations, but it attempts to be performant within the confines of ANSI SQL. The BasicLookupStrategy uses the same data source and cache that the JdbcMutableAclService uses. You also inject a console logger
for logging purposes.
The BasicLookupStrategy also has an AclAuthorizationStrategyImpl , which it injects into the AclImpls that it returns from lookups. The AclAuthorizationStrategyImpl supports ACL administration by authorizing ACL modification attempts. Its constructor takes an array of three granted authorities as described in table 7.10.
Table 7.10. AclAuthorizationStrategyImpl constructor arguments
Index |
Param name |
Description |
---|---|---|
0 | Change ownership | Authority able to change ACL ownership. That is, the specified authority has the special AclAuthorizationStrategy.CHANGE_OWNERSHIP permission. |
1 | Change auditing | Authority able to modify auditing details. That is, the specified authority has the special AclAuthorizationStrategy.CHANGE_AUDITING permission. |
2 | Change general | Authority able to change other ACL and ACE details (for example, inserting an ACE into an ACL or changing an ACL’s parent). That is, the specified authority has the special AclAuthorizationStrategy.CHANGE_GENERAL permission. |
You’ll learn a little more about how these constructor arguments work when we discuss programmatic ACL management, but the idea is that not just anybody can manage (create, modify, and delete) ACLs. We already mentioned in connection with table 7.6 that one way to manage an object’s ACL is to have the administrative permission on that object. Another way is to have the authority or authorities injected into the AclAuthorizationStrategyImpl constructor, because each entails a special ACL management permission. (These aren’t to be confused with the normal permissions that appear inside the ACLs. You can think of the special permissions as metapermissions that sit outside the ACLs, determining who can change the ACLs.) In practice, the authority you pass into all three constructor slots is a system-wide administrative authority, and indeed that’s what you’ve configured here.
That covers the ACL configuration. Now let’s look at some optimizations you can make to your ACL definitions.
In the first pass, we skipped over the parent_object and entries_inheriting columns in the acl_object_identity table. These columns allow you to simplify the management of your ACLs and also to save what could potentially be a lot of storage space by creating OID hierarchies and then allowing OIDs to inherit ACEs from parent OIDs.
For example, in the sample app, you want the administrator to have the write permission (among others) for all messages in all forums, and you want forum moderators to have the write permission for all messages in forums they moderate. Although you could create one ACE for every <SID, OID> pair, this approach doesn’t scale well. There are lots of users and lots of messages, and if you have to create a new set of ACEs for every new user or new message, things will get out of control in a hurry.
Instead you can do the following:
- Establish a parent-child relationship between forums and messages using the parent_object column on message OIDs.
- Set entries_inheriting true on the message OIDs so that messages automatically inherit ACEs from their parent forums.
- Give the site admin the write permission on the individual forums, and give forum moderators the write permission on the forums they moderate. The messages will inherit ACEs from the forum ACLs, allowing you to avoid creating lots of message ACEs.
The preceding is easier to understand with a diagram. First see figure 7.11.
In figure 7.11, your user has the write (or edit) permission on each message, and you implement this using one ACE per message. Using this approach, if you want to give the user read permission on the messages, you need to create another set of ACEs granting the read permission. If you decide to revoke the write permission, you’ll need to delete all the ACEs.
Compare the approach from figure 7.11 to the superior approach in figure 7.12.
In figure 7.12, you establish parent/child relationships between the forum and its messages using the parent_object column. Then you give the user the write permission on the forum. Finally you use inheritance to grant the user the write permission on the messages by setting entries_inheriting to true. Notice that this solves the issues we mentioned: you can add and revoke permissions on the messages by adding and revoking a single permission on the forum.
We need to cover one additional topic: manipulating ACLs programmatically.
Because applications create, update, and delete domain objects, you need to ensure that you keep the various ACL schema objects in sync. If you create a message, you need to create a corresponding OID and ACL. If you delete a message, you need to delete the corresponding OID and ACL as well.
Spring Security makes this possible via an ACL management API called MutableAclService. You included a JdbcMutableAclService in the configuration in listing 7.4. The following listing shows how you can use a MutableAclService to manage the creation, updating, and deletion of messages.

Listing 7.5 is ForumServiceImpl, which we referenced earlier when going over the security annotations. Like the other service beans, you declare it to be @Transactional , which matters here in part because you want your domain modifications to execute in the same transactional context as your ACL modifications.
You inject a MutableAclService at because this is your API into the Spring Security ACL module.
You have different message modification methods that create, update, and delete messages. Each, in addition to modifying the domain model, makes a call as appropriate to createAcl() , updateAcl()
, or deleteAcl()
to keep the ACL model in sync with the domain model.
The createAcl() implementation is the most interesting. You create a forum OID, then use it to issue a forum ACL lookup against the ACL service
. Then you create a new message ACL and corresponding OID
. By default, the JdbcMutableAclService assigns OID ownership to the current principal, which may or may not be the author, as you’ll see. Ownership is back-ended by the owner_sid column of the acl_object_identity table, which you saw in figure 7.9. Spring Security doesn’t specify what it means to own a domain object, but by default the owner is allowed to perform administrative actions on the associated ACL in precisely the same way the admin ACL permission (see table 7.6) and the AclAuthorizationStrategyImpl constructor authorities (see table 7.10) can.
Now that you’ve created the message ACL, you make the forum ACL its parent. The current principal can do this because it owns the current OID, as noted. Any principal with the AclAuthorizationStrategy.CHANGE_GENERAL metapermission (see table 7.10) can change an OID’s parent.
At you give the author write permission on the message if the message is visible. The idea is that the author can edit their own messages as long as an administrator hasn’t put an administrative block on the message (that is, an administrator hasn’t made it invisible). This change requires the AclAuthorizationStrategy.CHANGE _GENERAL metapermission.
You change the message ACL owner to the author at . This requires the AclAuthorizationStrategy.CHANGE_OWNERSHIP metapermission, which the current principal has because it’s the current owner. In most cases, the author will already be the owner, because in most cases it’s the author who invokes the createAcl() method by posting a message. But you’ll see momentarily that in some cases an administrator is creating the ACL, and in such cases you need the administrator to relinquish ownership to the author.
You update the ACL in the persistent store at . You now have a new message OID and ACL with the right parent, author write permission, and owner.
In addition to creating ACLs, you have to be able to delete them. At you delete an ACL with a single deleteAcl() call against the ACL service.
You also have to be able to update ACLs . This can happen if the original author updates the message (not shown in listing 7.5, but it’s in the code download), or it can happen if an administrator blocks the message. Either way, the most straightforward way to update the ACL is to delete the old ACL and create a new one. In the case of an administrative block, the current principal will be the administrator when you call the createAcl() method, which is why you have to make the author the owner as mentioned.
With that, you’re able to manage ACLs alongside your domain objects.
In this recipe, you learned how to add fine-grained authorization to your application. With the earlier recipes you had to be content with fairly crude rules, such as the rule that normal users can read and create messages in general and that the site admin can also edit, block, unblock, and delete messages in general. But now you can create more specific rules, such as the rule that relevant authors and forum moderators should also be allowed to edit specific messages.
But there’s still a gap. You’d like forum moderators to be able to block, unblock, and delete messages in their forums, but the app doesn’t yet support this. Under the hood you have the ACLs in place for it, but on the display side, the JSP doesn’t yet know how to take the ACLs into account. The display of the block/unblock/delete options still hinges on coarse-grained permissions rather than on fine-grained ACLs. Also, the app always shows the Edit Message option, even if the user doesn’t have that permission for that message. The final recipe in this chapter, recipe 7.5, addresses these issues.
Recipe 7.4 Authorizing method invocations based on ACLs
Spring Security, Spring Security tag library
In addition to protecting URLs from being accessed and methods from being called, it’s often useful to show or hide page navigation and content according to a user’s authorization to view them. Spring Security’s tag library allows you to display page navigation and content based on ACL data.
Show or hide web navigation and content based on domain object ACLs. Specifically, you need to show or hide the edit, block, unblock, and delete message options depending on whether the user has permission to perform those operations on the messages in question.
In previous recipes, the sample app always displays the Edit Message link, even if the user doesn’t have permission to perform that operation. And it uses crude, general permissions to decide whether to display the block/unblock/delete options:
Instead, you want to show or hide those options based on the ACLs you created in recipe 7.4. The basic approach is to use the <security:accesscontrollist> JSP tag to decide whether to hide or show the edit link. The tag references the ACLs you created in the previous recipe.
Now that we’ve discussed the structure of the Spring Security ACL module, you’re in a good place to understand the JSP that contains the ACL-based JSP tags. Let’s look at that so you can keep the goal in mind.
The following listing shows the relevant part of the JSP that displays individual forum posts.
The part shown is the list of options at the bottom of the message. Under normal circumstances, the only thing a user would see is the Reply link. But as you can see, there are other possibilities.
First you declare the Spring Security tag library because you’re going to use the <security:accesscontrollist> tag. Next you have the tag itself
. It has exactly two attributes: domainObject and hasPermission. The idea behind the tag is simple. The domainObject attribute points to a domain object (no surprises there), and hasPermission describes individually sufficient permissions that the current user must have with respect to the domain object. In other words, you enter the body tag if and only if the current user has at least one of the listed permissions. Here you’re basically displaying the <ul> only if there’s at least one option to show.
The user role doesn’t directly come into the picture here. Instead, it’s all about having the right permissions on the specific message referenced by the domainObject attribute.[16] If you have them, that’s it—you’re in. Otherwise, you aren’t.
16 User roles are indirectly involved, though, because they factor into which general permissions are in place, and those in turn factor into specific permissions. In this specific case, the site admin role has all ACL permissions on the site object, and those propagate down to forums and messages through the ACL inheritance mechanism.
At ,
, and
are controls for specific permissions: write (2), admin (16), and delete (8). Note that in
, even though the JSP generates HTML for both the block and unblock options, JavaScript ensures that exactly one is visible.
How it works: AccessControlListTag
The <security:accesscontrollist> tag is backed by the AccessControlListTag class. AccessControlListTag looks for an AclService on the application context, which it uses to find the ACL attaching to the domain object in question. Then AccessControlListTag delegates the access decision to Acl.isGranted(...) in much the same way that AbstractSecurityInterceptor delegates to an AccessDecisionManager.
The Acl interface specifies the semantics that access is granted if—and only if—the user has at least one of the required permissions. This is different than how the AccessDecisionManager makes its decisions. We noted that AccessDecision-Managers (at least, the ones that ship with Spring Security) use a voting mechanism (in the form of AccessDecisionVoter) combined with a conflict-resolution mechanism (in the form of AccessDecisionManager) to yield access decisions. With Acl there is no such thing. If the user has at least one of the permissions, access is granted. Otherwise access is denied.
Point your browser at http://localhost:8080/sip/home.html, and try it out. Log in to the application as user julia, and go to the Algebra I forum, which she moderates. Julia should be able to perform all operations on the messages in that forum. Then go into the Calculus II forum, which she doesn’t moderate. She can edit messages that she wrote, but she can’t do anything other than read messages that somebody else wrote.
Log out, and then log back in as user juan, the site admin. You should be able to perform all operations on all messages across all forums.
As with role-based authorization, ACL-based authorization involves collaboration between an underlying authorization model and view-related controls based on that model. In this recipe, you learned how to use the <security:accesscontrollist> JSP tag to make display decisions based on an underlying ACL apparatus. All the hard work goes into the ACL model. Once that’s in place, showing or hiding page content based on ACLs is a piece of cake.
Take our tour and find out more about liveBook's features:
- Search - full text search of all our books
- Discussions - ask questions and interact with other readers in the discussion forum.
- Highlight, annotate, or bookmark.
With this chapter, we’ve completed our two-chapter tour of security-related problems. The issues we’ve examined are of a general nature and reappear in application after application. You’ve also seen that Spring Security provides a nice framework for solving such problems, providing services around authentication and authorization, including a rich ACL infrastructure.
In the next chapter, we switch gears and discuss how to build features for communicating with customers and end users.