Adding New Permission Types to Spring Security ACL

Domain object level security is probably least used feature of Spring Security compared to url based and method level security features for enterprise Java web applications. However, when you have a security requirement something like “I want to restrict some operations which is allowed for some roles based on criteria that can be obtained from domain objects passed into, or returned from those operations.” This could be something like that. “Save operation could be called by every ROLE_USER, but each user should only be allowed to save its own User object”.

ACL support provides some Permission objects, namely READ, WRITE, CREATE, DELETE, ADMINISTRATION based on bit masks, and you need to somehow associate related Permission objects and principals or roles with your domain objects on which you want to perform authorization checks. Later your methods with, for example Pre/PostAuthorize annotations, will be intercepted by MethodSecurityInterceptor and Spring Security will control if current user or his assigned GrantedAuthorities has enough Permissions in order to execute that method or get its result.

One of my clients recently asked for ACL configuration in his project and later he extended the requirement with the need of introducing new Permission types in addition to default available types I listed above. In order to add new Permission types you can just extend from BasePermission class and define new instances for each of your Permission type like below;

public class CustomPermission extends BasePermission {

	public static final Permission REPORT   = new CustomPermission(1<<5,'O');
	public static final Permission AUDIT    = new CustomPermission(1<<6,'T');

	protected CustomPermission(int mask) {
		super(mask);
	}

	protected CustomPermission(int mask, char code) {
		super(mask, code);
	}
}

After that, you need to make Spring Security ACL module to be aware of your new Permission objects. This is achieved by registering them to PermissionFactory bean. Just extend from DefaultPermissionFactory class, and call its available registerPublicPermissions method with the Permission class you defined new Permission objects as input argument.

public class CustomPermissionFactory extends DefaultPermissionFactory {
	public CustomPermissionFactory() {
		super();
		registerPublicPermissions(CustomPermission.class);
	}
}

Finally, you have to define your custom PermissionFactory as bean in your ApplicationContext and inject it into permissionEvaluator and lookupStrategy beans of ACL configuration.

 

<bean id="permissionEvaluator" class="org.springframework.security.acls.AclPermissionEvaluator">
    <constructor-arg ref="aclService"/>
    <property name="permissionFactory" ref="permissionFactory"/>
</bean>

<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
...
    <property name="permissionFactory" ref="permissionFactory"/>
</bean>

<bean id="permissionFactory" class="tr.com.harezmi.security.CustomPermissionFactory"/>

 

During registration field names are stored as “permission name” which can later is used in Pre/PostAuthorize annotations. For example;

@PreAuthorize("hasPermission(#user,'report')")
public void report(User user) {
...
}

BasePermission is based on integer bit masks, therefore it can support up to 32 different kind of permissions in a system including 5 built-in permissions. If you need much more than this number you can define permission object based on completely different integer identifiers. In short, bit masking is not compulsory.