ZK Router Security

| December 9, 2014 | Reply

Since the ZK Hash Router was recently updated, the security part was moved to a seperate plugin. In this post I will explain how the plugin works and how to configure it.

Defining security constraints

The security constraints are currently very simple to use with the ZkRouteSecutiyConstraint class. All the needed data is a path expression and a comma-separated list of roles which have access to the resources matching the expression. Here’s the code:

public class ZkRouteSecurityConstraint {

	private Pattern pattern;
	private String roles;
	
	public ZkRouteSecurityConstraint(String path, String roles) {
		if(path == null || path.trim().isEmpty()) {
			throw new IllegalArgumentException("You must a provide a non empty path!");
		}
		if(roles == null || roles.trim().isEmpty()) {
			throw new IllegalArgumentException("You must define at least 1 role for path " + path);
		}
		
		path = path.trim().toLowerCase();
		String regexp = path.replaceAll("\\*", ".*");
		pattern = Pattern.compile(regexp);
		
		this.roles = roles.trim().toUpperCase();
	}
	
	public boolean matches(String url) {
		return pattern.matcher(url).matches();
	}
	
	public boolean hasAccess() {
		return SecurityUtil.isAnyGranted(roles);
	}
}

Path expressions look like this:

  • /foo
  • /foo/*
  • /foo/*/bar
  • *

The asterisk symbol means that ANYTHING can be placed there. The last path expression in the example is the catch-all rule.
Also, SecurityUtil here is actually org.zkoss.spring.security.SecurityUtil which can be found in the zkspring-security package.

The actual plugin

public class SecurityPlugin extends EmptyPlugin {

	private List<ZkRouteSecurityConstraint> securityConstraints = new LinkedList<>();
	
	@Override
	public void beforeRouting(ZkRouter router, Component content, String url) throws RouterException {
		ZkRouteSecurityConstraint securityConstraint = findSecurityConstraint(url);
		if(securityConstraint != null && !securityConstraint.hasAccess()) {
			throw new RouteAccessDeniedException();
		}
	}
	
	private ZkRouteSecurityConstraint findSecurityConstraint(String url) {
		for(ZkRouteSecurityConstraint securityConstraint : securityConstraints) {
			if(securityConstraint.matches(url)) {
				return securityConstraint;
			}
		}
		return null;
	}
	
	public void addSecurityConstraint(String path, String roles) {
		path = RouterUtil.removeFirstAndLastSlash(path);
		securityConstraints.add(new ZkRouteSecurityConstraint(path, roles));
	}
}

This is the entirety of the security plugin. It implements the beforeRouting() plugin method which is called right at the beginning of the dispatch procedure. Basically, it tries to find whether there is a registered security constraint matching the route. If there is, it is checked. If the current user does not have permissions to visit the selected route a RouteAccessDenied exception is thrown. That’s all there is to it.

Spring Configuration

Similar to the way the ZK Hash Router has a ZkRouterFactoryBean, the security plugin provides a SecurityPluginFactoryBean. It enables your security configuration to look like this:

<bean name="securityPlugin" class="com.pastelstudios.zk.router.security.spring.SecurityPluginFactoryBean" >
    <property name="securityConstraints">
        <list>
            <value>/foo => ROLE_USER</value>
            <value>/foo/* => ROLE_EDITOR</value>
            <value>* => ROLE_ADMIN</value>
        </list>
    </property>
</bean>

And don’t forget to add the plugin to the router!

<bean id="routerFactory" class="com.pastelstudios.zk.router.spring.ZkRouterFactoryBean">
	<property name="plugins">
		<list>
			<ref bean="securityPlugin" />
		</list>
	</property>
</bean>

All source code can be found at github: zk-router-security

Tags: , , ,

Category: Development

About the Author ()

Leave a Reply