Handle permissions with Spring Security

Suppose you have your fancy authentication all up and running with Spring Security, but you have to manage also authorization. You don't want to handle permissions based only on the authorities granted to the user, but want something like hasPermission('some_domain', 'permission') to check. This is where the Spring PermissionEvaluator comes into play.

The Permission Evaluator

A permission evaluator is an interface that defines two methods to check against a specific permission. They receive the authentication object and the permission to check as parameters. Usually you use the authentication object to access logged user data which contains the full list of granted permissions or an identifier useful to check the required permission from a suitable source (a database for example).

An example implementation is the following:

@Component
public class CustomPermissionEvaluator implements PermissionEvaluator {
    
    public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
        return ((CustomUser)authentication.getPrincipal()).hasPermission(targetDomainObject, permission);
    }
    
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
        return ((CustomUser)authentication.getPrincipal()).hasPermission(targetId, targetType, permission);
    }
}

Nothing really exciting, isn't it. The two methods are already well documented in Spring Security docs. The principal used for my authentication system is a custom implementation of the UserDetails interface which extends the normal user in the security context of Spring Security with extra informations and custom methods, like this hasPermission() you see. It's up to you implementing this evaluator to fit your security architecture. I, for example, having to check for lot of permissions at once, I pre-load all the user permission at the login phase, and store it in a fast access data structure inside the CustomUser class to quickly evaluate those permissions. You could eventually call a DAO and check user permissions against some sort of database values. Your choice.

Furthermore, the permission target domain and the permission itself are defined as generic Object, so you could use complex POJO classes to define your permissions. As for myself, having a simple security design, my permissions are strings with the usual CRUD operations. So my calls are something like this: hasPermission('articles', 'write').

Why two methods? For increase flexibility: the first should directly send the target domain where to apply the asked permission (e.g. the article, the user, etc.), while the second one send you an identifier of the target domain object (like a database PK or ID).

The configuration file

Let's make the spring security configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-3.1.xsd">
    

    <!-- Enable the use of pre/post annotation -->
    <global-method-security pre-post-annotations="enabled">
        <expression-handler ref="expressionHandler" />
    </global-method-security>
    
    <!-- Enable permission evaluator in annotation -->
    <beans:bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
          <beans:property name="permissionEvaluator" ref="customPermissionEvaluator" />
    </beans:bean>
    
    <!-- Declare a custom PermissionEvaluator interface -->
    <beans:bean id="customPermissionEvaluator" class="it.massimilianosciacco.project.spring.security.CustomPermissionEvaluator"/>
    
    <!-- your other security configurations... -->
    ...

</beans:beans>

The first block enables the @PreAuthorize and @PostAuthorize annotation.
The second block enables the use of hasPermission() expression in such annotations (so you can use something like @PreAuthorize("hasPermission('article', 'write')").
The third block simply defines your custom permission evaluator specifing the classpath.

Enabling the permission evaluator expressions in jsf security tag

So you have read somewhere that you can use something like this:

<sec:authorize access="hasPermission('article', 'write')">
    <some protected randomness>
</sec:authorize>

in your .xhtml pages (the namespace for the security tag is xmlns:sec="http://www.springframework.org/security/tags"), but it won't work.

That's because you need to setup some further configuration.

1. Add this configuration in you spring security configuration file:

<!-- Enable permission evaluator in tag -->
<beans:bean id="webExpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler">
    <beans:property name="permissionEvaluator" ref="customPermissionEvaluator"/>
</beans:bean>

2. Add this springsecurity.taglib.xml file in your WEB-INF folder:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE facelet-taglib PUBLIC "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN" "http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
<facelet-taglib>
    <namespace>http://www.springframework.org/security/tags</namespace>
    <tag>
        <tag-name>authorize</tag-name>
        <handler-class>org.springframework.faces.security.FaceletsAuthorizeTagHandler</handler-class>
    </tag>
    <function>
        <function-name>areAllGranted</function-name>
        <function-class>org.springframework.faces.security.FaceletsAuthorizeTagUtils</function-class>
        <function-signature>boolean areAllGranted(java.lang.String)</function-signature>
    </function>
    <function>
        <function-name>areAnyGranted</function-name>
        <function-class>org.springframework.faces.security.FaceletsAuthorizeTagUtils</function-class>
        <function-signature>boolean areAnyGranted(java.lang.String)</function-signature>
    </function>
    <function>
        <function-name>areNotGranted</function-name>
        <function-class>org.springframework.faces.security.FaceletsAuthorizeTagUtils</function-class>
        <function-signature>boolean areNotGranted(java.lang.String)</function-signature>
    </function>
    <function>
        <function-name>isAllowed</function-name>
        <function-class>org.springframework.faces.security.FaceletsAuthorizeTagUtils</function-class>
        <function-signature>boolean isAllowed(java.lang.String, java.lang.String)</function-signature>
    </function>
</facelet-taglib>

3. Import the taglib in your web.xml:

<context-param>
    <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
    <param-value>/WEB-INF/springsecurity.taglib.xml</param-value>
</context-param>

4. Import the spring-faces libraries as described here:

<dependency>
    <groupId>org.springframework.webflow</groupId>
    <artifactId>spring-faces</artifactId>
    <version>2.3.0.RELEASE</version>
</dependency>

5. Makes sure you also have the spring security taglibs library:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-taglibs</artifactId>
    <version>3.1.4.RELEASE</version>
</dependency>

You should good to go now.

For more information about permission evaluator, you can check this good article of Jakub Nabrdalik.