Spring security is really powerful library in its current version and I like it much. You can secure your application on method level several years now (this feature was introduced by Spring Security 2 in 4/2008) but we’ve upgraded from old Acegi Security only recently. When using method access control in larger scale I started to think about security rules encapsulation into standalone annotation definitions. It’s something you can live without but in my opinion it could help readibility and maintainability of the code. Let’s present some options we have now …

Problem decomposition – how to organize our rules?

Have no system at all

This is usually the first approach one can take after reading documentation of Spring Security framework and start to use it in own code. All rules are represented by Strings of SpEL as follows:

After a while you might notice that certain rules keep repeating. You can see these rules repeat in our example class:

principal.userObject.administrator
// means administrator with super rights is logged in
principal.userObject.isOwnerOf(#organization.id)
// means user that is owner of particular organization
//(has super rights related to his organization) is logged in
branch.isPartOf(organization) and principal.userObject.isManagerOf(#branch.id)
// means user that is manager of particular branch
// (has rights for operations connected with his branch) is logged in

As we all know Strings are evil – you can’t refactor them safely and they tend to break your code much more often. So after a while you start to …

Bad things happen when you’d like to share some rules across different libraries. For example we have a legacy system using its own security solution for accessing backend administration. SuperAdministrators are authenticated by this legacy system and have supervisor rights in most of our simple applications – so when such admin is authenticated all Spring Security rules should be overriden and all methods should become accessible for such user. But how to share this common rule across different customer installations? I can make up only single solution possible with standard Spring Security behaviour:

And I don’t see this kind of notation much more readable than our first attempt with raw SpEL strings. What could be done with this?

Extract rules into custom annotations

You can extract your rules into custom annotations and Spring would find them. If you look at AnnotationUtils class you would realize that Spring tries to find annotation not only on method itself but also on annotations of this method. So you can have following custom annotation:

Compositing security annotations

Let’s define following composition system:

if there are multiple security annotation placed on the same place (ie. method or class) they represent disjunction (ie. logical OR) … but we might have a way how to change composition behavior to logical AND if necessary

@AllowedForAdministrator
public class MyManager {
public void approveOrganization(Organization organization) {
//has no method annotation - class annotation will be used instead
}
@AllowedForOrganizationOwner
public void updateOrganization(Organization organization) {
//method and class annotations are combined with OR relation
}
@AllowedForOrganizationOwner
@AllowedForBranchManager
public void updateOrganizationBranch(Organization organization, Branch branch) {
//method annotations are combined by default with OR relation
//result it then combined with class annotation with OR relation
//results in administrator or organization owner or branch manager
}
@AllowedForAnyone
public Organization getOrganizationById(Integer id) {
//we want to let this method to by called by anyone but if we would
//not annotate it at all class annotation will deny execution to all
//but the administrator - so we need to add following annotation:
//AllowedForAnyone => @PreAuthorize("true")
}
@RulesRelation(BooleanOperation.AND)
@IsAuthenticatedFully
@AllowedForOrganizationOwner
public void removeOrganizationById(Integer id) {
//when we want to change relationship to require all rules to be satisfied
//we have to use special annotation @RulesRelation changing default relationship among rules
//execution of this method requires user to be manually logged in in current session
//and to represent an organization owner, of course administrator could call this
//method too because class annotations are always added with OR relation
}
}

Tweaking the Spring Security

If you integrate Spring Security into your project you’d probably use the shortcut way represented by security namespace. Unfortunatelly interface that needs to be overriden is was not exposed by this namespace and is somehow supported by the most recent version 3.1 somehow (see issue SEC-1383). But I wasn’t able to make it running and was forced to initialize method security in the old way as a set of aspects:

Note:you need to declare AspectJ pointcuts as follows if you want to find not only methods annotated directly with certain annotation type but also methods annotated with annotations annotated with such annotation type:

As you can see – all classes except one are taken from Spring codebase. The single exception is class ExperimentalPrePostAnnotationSecurityMetadataSource that is meant to be used instead of original PrePostAnnotationSecurityMetadataSource that looks up for annotations of @PreAuthorize, @PreFilter, @PostAuthorize and @PostFilter. My experimental version finds all annotations that represents above mentioned security annotations or are annotated with them. It retrieves all SPeL security rules that these annotations contain and combine them into a single one in context initialization time. Principles of the rules combinations are stated in the beginning of the previous chapter.

Source code of all used extension classes are available in form of GIST (implementation details are not so important for this article as the main idea is): https://gist.github.com/2081353

How do YOU test access control of your application? Many of complex applications put on top of their complexity access control logic for securing data and to limit access to certain functions. No matter if you have fully configurable... Many of complex applications put on top of their complexity access control logic for securing data and to limit access to certain functions. No matter […]...

When does your Spring @Transactional attribute apply on CgLib proxies Testing transactional aspect of your application is not easy as we usually use Springs‘ transaction rollback on tear down testing approach. Though there are solutions to test aspect oriented logic...Testing transactional aspect of your application is not easy as we usually use Springs‘ transaction rollback on tear down testing approach. Though there are solutions to […]...

This approach is almost exactly what I need. But I tried to configure secutiry context the way you wrote but got no security handling. I see that my methods are called w/o interception. Could you please help me out what can be wrong?