Java Programming: Proxies and Access Control 
As a result of my last post -
Java Programming: Proxies and References - I received an email asking how could access control be implemented using the same proxy mechanism.
This post's goal is to answer that question. I'll show a possible solution, provide example source code and discuss the advantages and disadvantages of using such mechanism.
Since I already explained what a proxy is I'll skip that part. Anyone interested in reading about proxies should read my previous post,
Java Programming: Proxies and References.
First let's define clearly what I mean by access control. When using the term
access control I'm referring to a mechanism that is able to enforce policies. A policy is nothing more than a rule or a set of rules, example of policies may be "Only editors can edit object" or "Only authenticated users can read and write object" among others.
Design
The idea of using access control with proxies isn't new and most of the times is implemented - with minor variations - using the design pattern
intercepting filter.
In this particular case where proxies are used, the interception is done by the InvocationHandler.
The InvocationHandler is an interface that makes the JVM translate all the methods invocations into a single method named
invoke. This method receives the object, the method name and the arguments.
Such behaviour ensures that all methods invoked will be intercepted, as long as they're being invoked in the proxy object instead of the actual object. That is why the application needs to assure that the object itself is only accessible through a proxy.
The interception algorithm in the invocation handler is quite simple and is the following:
- Retrieve all existing policies that affect the current invocation
- Execute each one of those policies. If at least one fails deny access, otherwise allow the invocation on the object being proxied.
The flowchart can be found at the left.
ImplementationAs I usually say there are no perfect solutions, the implementation I'm suggesting isn't an exception. There are various ways of implementing the design presented above and I chose one.
It may have flaws but allows me to show how access control should be separated from the application's domain code and also how to use annotations (readers interested in knowing how to create custom annotations should read
Java Programming: Doing your own annotations).
The guide lines for this specific implementation are the following:
- The policies, called rules in this example, implement an interface that is named AccessControlRule. This interface forces the implementation of a single method, verify.
Show AccessControlRule source code
package net.pabrantes.accessControl;
public interface AccessControlRule {
public boolean verify(ApplicationContext context);
}
- There is a custom annotation - named AccessControlCheck - that is used in methods and classes, which allows as argument an array of strings, where each string is a class that implements the AccessControlRule interface. Since this annotation will be searched at runtime it's retention policy needs to be RUNTIME.
Show AccessControlCheck source code
package net.pabrantes.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({METHOD,TYPE})
public @
interface AccessControlCheck {
public String[] value()
default {};
}
- The custom InvocationHandler, named AccessControlHandler, is responsible for finding the acustom annotation, create instances of the rules, execute them and finally decide if access to the object should be allowed or denied.
Below can be found the implemented model.

Looking at the model there are two classes that haven't been presented yet, they are the
ApplicationContext - which actually could be previously seen in the
AccessControlRule interface - and the
AccessControlGenerator.
The
ApplicationContext, like the name indicates, represents the application's context in a given invocation, in this particular example it holds things like the method that is being invoked, who invoked it and the arguments.
This context is then used by
AccessControlRules to decide if the requested invocation is allowed or not.
The
AccessControlGenerator can be seen as a factory class. It contains a single static method, named
newAccessControlInstance, responsible for creating proxies which will be using the custom InvocationHandler,
AccessControlHandler. Although the signature of the method states Object as argument, only objects that implement at least one interface will be accepted, since the proxy needs at least one interface to implement.
Show AccessControlGenerator source code
package net.pabrantes.accessControl;
import java.lang.reflect.Proxy;
public class AccessControlGenerator {
public static Object newAccessControlInstance(
Object object) {
Class[] interfaces = object.getClass().getInterfaces();
if(interfaces.length == 0) {
throw new IllegalArgumentException(object.getClass().getName() +
" must implement at least one interface");
}
return Proxy.newProxyInstance(object.getClass().getClassLoader(),interfaces,
new AccessControlHandler(object));
}
}
Finally let's take a look at the core class, the
AccessControlHandler.
It all starts when a method is invoked over the proxy and method
invoke is executed.
The method
invoke implements the algorithm that was already presented, here's the source code:
public Object invoke(Object arg0, Method method, Object[] arguments)
throws Throwable {
AccessControlCheck annotation = findAnnotation(method, arguments);
if (annotation != null) {
checkRules(annotation.value(), method, arguments);
}
return method.invoke(interceptedObject, arguments);
}
The first thing to do is to locate the custom annotation in the given object,
findAnnotation method will access the Class of the object being proxied, retrieve the method that is being invoked and see if it contains the custom annotation, if it can't find it then defaults to finding the annotation in the Class object.
Show findAnnotation method source code
private AccessControlCheck findAnnotation(Method method, Object[] arguments) {
AccessControlCheck annotation = null;
try {
Method actualMethod = interceptedObject.getClass().getMethod(
method.getName(), getClasses(arguments == null ? Collections.EMPTY_LIST.toArray() : arguments));
annotation = actualMethod.getAnnotation(AccessControlCheck.class);
} catch (Exception e) {
e.printStackTrace();
}
return annotation != null ? annotation : interceptedObject.getClass()
.getAnnotation(AccessControlCheck.class);
}
If the annotation is found then the policies specified in it must be executed.
The method
checkRules receives the array of strings specified in the annotation and also the method and arguments that the proxy received which are needed to created the
ApplicationContext. Each string will be proccessed into a class, an instance will be created and the
verify method will be ran. If any of verifications fail then a SecurityException is thrown.
As I said before the
ApplicationContext contains information related with the context, which, among other things holds the user that originated the request. Since this implementation is only a simple example a mock object is being used to provide the requesting user.
Show checkRules method source code
private void checkRules(String[] classes, Method method, Object[] arguments)
throws ClassNotFoundException, InstantiationException,
IllegalAccessException {
ApplicationContext context = new ApplicationContext(method,
UserMockObject.readCurrentUser(false), arguments);
for (String className : classes) {
Class clazz = Class.forName(className);
AccessControlRule rule = (AccessControlRule) clazz.newInstance();
if (!rule.verify(context)) {
throw new SecurityException(
"Denied to perform the operation by: "
+ rule.getClass().getName());
}
}
}
In the end if there were no rules to check or all rules allowed the invocation, the requested method is invoked over the object that is being proxied.
Advantages and disadvantageThe main advantages, in my opinion, are:
- Access control code is separated from domain specific code.
- Simplicity of this particular implementation.
- In this particular implementation is possible to define generic rules for example a rule that verifies any method in Class A which starts by set can only be executed by an admin (for more information see GenericSetAdminAccess rule in code).
The main disadvantage of using this mechanism are already known from the previous post they are the explosion of interfaces and possible performance and memory issues. This disadvantages are mostly related with the fact that proxies are used in this implementation.
ConclusionsThis example showed a way of implementing access control but there are various other solutions. Many Java Frameworks already offer this kind of features out of the box, although I think it's always important to know how things work inside the
black box.
It might not be the best solution for large applications but small ones may use it very well, SnipSnap - this bliki's software - is an example of an application that implements access control using proxies.
Finally, for the ones interested in the full source code I made it
available for downloaded.