Introducing a security layer in your application architecture

Though of course it varies, in most applications you will encounter at least a view layer, a service layer and a data layer. Security will typically be applied on both the business layer as well as the view layer.

On the business layer security restricts access to your data and on the view layer security ensures the user in question only sees those view elements relevant to him/her. Quite often this results in security being implemented twice, violating the DRY (Don’t Repeat Yourself) principle. In this post we will discuss how we can introduce a security layer in your application architecture to facilitate re-use of security code in all layers.

In my previous post I discussed how to use Spring Expression Language (SpEL) in combination with Spring Security to implement complex (beyond role-based), unit-testable security logic. Some of you may have already anticipated that this pattern offers some hidden treasures not yet disclosed. In this post I will describe how we can put the techniques of my previous post to work to create a separate security layer in your applications that is useable in both the view layer and the business layer. In my examples I am using Apache Wicket for my view layer but the general idea should translate to any view technology you might be using.

Suppose we are adding a link in the view layer:
add(new TestSecurityLink("link1", "Possible non-working link") {
@Override
public String callSecuredMethod() {
return testService.getSecuredString(argument);
}
});

The service call is as follows (please refer to my previous post to understand what’s going here to secure the function):
@PreAuthorize("securityBean.isUserAllowedToGetSecuredString(#argument, principal)")
public String getSecuredString(String argument) {
return CLEARANCE_GRANTED;
}

And the security code reads:
public boolean isUserAllowedToGetSecuredString(String argument, User user) {
if (user.hasRole(SystemRoleName.ROLE_ADMIN)) {
if (argument.equals("foo")) {
return true;
}
}
return false;
}

In the current situation a user could potentially see the link even if he/she does not have the proper authentication to call the underlying service, resulting in an unfriendly user interface. So we need to add some logic to the view layer to ensure the link is only presented to the user when it is actually relevant. This is where the danger of duplication of security logic rears its ugly head. Let’s see how we can prevent this.

Reusing business layer security constraints in the view


Should we be implementing security on the business layer in a more traditional fashion, the security logic would be implemented both in the business layer and then once again in the methods determining visibility in the view layer. This is clearly undesirable as it introduces a maintenance nightmare and opens the door to a whole slew of security issues.

But remember that we introduced a mechanism to encapsulate our security code in a separate Java method in my previous post! In my example above you can see that I implemented this pattern in the @PreAuthorize annotation on the service call. We can now re-use this method call to determine the visibility of our sample link:
add(new TestSecurityLink("link1", "Working link") {
@Override
public String callSecuredMethod() {
return testService.getSecuredString(argument);
}

public boolean mayCallSecuredMethod(User user) {
return securityBean.isUserAllowedToGetSecuredString(argument, user);
}
});

The link is now using the same code as is being called from the SpEL expression in the business layer. You can imagine how this is a tremendous help in keeping your applications maintainable and keeping nasty security leaks out the door. You could take this concept even further and re-use the SpEL expression in your view layer… but I’ll leave that as a cliffhanger for a next blog post.