Observations

Notice the service methods have been annotated with @PreAuthorize and @PostFilter. Also, we're not actually performing any add, edit, or delete actions. Instead we're just returning a Boolean value to test whether the method is accessible.

The following declaration means check the domain object post and see if the current user has WRITE access to this object:

Run the Application

Let's run the application to see the results (To see the remaining XML configuration, please download the source code below):

We'll need to login first. Enter the following URL to login:

http://localhost:8080/spring-security-acl-expression/krams/auth/login

To access the Bulletin Page, enter the following URL:

http://localhost:8080/spring-security-acl-expression/krams/all/view

We will log-in first as an admin using john/admin as the username/password pair.

Next, we'll login as a user using jane/user as the username/password pair.

Then, we'll login as a visitor using mike/visitor as the username/password pair.

Notice the admin can see all posts while the user can see only the Personal and Public posts; whereas the visitor can only see the Public posts. We've also indicated at the top the name of the current user and the associated role.

If any of the three tries to access an unauthorized resource for their role, they will get the following:

This is the benefit of ACL. We're restricting access on the domain level, not just on the URL level. However if we use the normal intercept-url setup, we won't be able to display all three types of posts. It's either we see everything or we get denied. Try clicking on the remaining links, and verify if they are really protected. I'll bet you they are :)

Conclusion

That's it. We've finished our simple ACL application that leverages Spring Security's Expression-Based Access Control. It may look complicated at first but the concepts are really simple. Also, instead of going the heavyweight solution, we opted to use the lightweight solution using the hasPermission() expression and a custom PermissionsEvaluator implementation

In this tutorial we will study how to setup a simple Spring MVC 3 application with ACL-based security using Spring Security 3's Expression-Based Access Control. Our application is a simple Bulletin site where different types of users can read and post messages. It is composed of three sections: Admin Posts, Personal Posts, and Public Posts and three types of users: admin, user, and visitor.

Here's a sample screenshot:

This tutorial assumes you're familiar with setting-up a basic intercept-url based Spring Security application, and Spring MVC application. If you need a review, please read my other tutorials first regarding these topics.

What is Expression-Based Access Control?

Spring Security 3.0 introduced the ability to use Spring EL expressions as an authorization mechanism in addition to the simple use of configuration attributes and access-decision voters which have seen before. Expression-based access control is built on the same architecture but allows complicated boolean logic to be encapsulated in a single expression

Complex applications often will find the need to define access permissions not simply at a web request or method invocation level. Instead, security decisions need to comprise both who (Authentication), where (MethodInvocation) and what (SomeDomainObject). In other words, authorization decisions also need to consider the actual domain object instance subject of a method invocation.

An access control list (ACL), with respect to a computer file system, is a list of permissions attached to an object. An ACL specifies which users or system processes are granted access to objects, as well as what operations are allowed on given objects. Each entry in a typical ACL specifies a subject and an operation. For instance, if a file has an ACL that contains (Alice, delete), this would give Alice permission to delete the file.

Source: http://en.wikipedia.org/wiki/Access_control_list

Functional Specs

To understand more about ACL, let's compare it against a simple Spring Security intercept-url based configuration. If we have three sections, Admin Posts, Personal Posts, Visitors Posts, we'll probably pattern our configuration similar to the following:

1. It only works at the Controller level--that is at the URL level.
2. What happens if we have a domain object that doesn't correspond to a particular URL?
3. What if we need to display the same URL that contains our three domain objects together: Admin, Personal, and Public Posts? It's either we get an Access Denied or we see everything.

The Solution

We use ACL. The idea is we put the restriction on the domain object itself. It's similar to the way we access files in the computer. Various users have different READ and WRITE access to certain files. Some have READ access, but some have both READ and WRITE access.

The Application

We'll begin our application by configuring the required Spring Security configuration and the required custom classes. Then in Part 2, we'll build the Spring MVC section.

In Spring Security 3, there's the heavyweight solution of implementing ACL (See Spring Security 3 Reference Chapter 16). And there's also the lightweight solution of implementing ACL through the use of Expression-Based Access Control

To use it, we need to mark our methods with Method Security Expressions (see Chapter 15.3). They are @PreAuthorize, @PreFilter, @PostAuthorize and @PostFilter.

Then we need to use the hasPermission() expression inside these Method Security Expressions. For example:

The PermissionEvaluator can be a custom implementation or a default Spring Security implementation. For this tutorial, we will do a custom implementation.

Why custom implementation?

Because we want to stay away from the complexity of setting up an ACL database and to make this tutorial simple to learn. Also, the strength of the PermissionEvaluator interface and Expression-Based Access Control is it allows us to construct our own implementation. And since it's our own implementation, we know how it works.

The Custom Map

We'll declare a simple Map that contains a list of ROLES and OBJECTS. Whenever a user tries to access a protected object, it will be checked against this Map. For each ROLE, we assigned what objects it can owned and what permissions it can have.

We have three domain objects that correspond to an actual object in the application.