Back in 2010, when I was young and full of beans, I wrote an authorization module called Deadbolt for the Play! framework in its 1.x incarnation. It was originally written to fulfil some needs I had for projects I was working on, but proved to be pretty popular with a wider audience. There’s no download counter at the Play module repository, unfortunately, so I have no idea how widely it’s used – but it is used, and that’s always nice to hear about.

Fast-forward to 2012, to when I’m old and full of gas, and Play is now at 2.0 RC3. It’s totally backwards-incompatible with the 1.x projects, which some people have complained about, but I personally applaud – as long as this doesn’t happen with every major release. It’s also totally backwards-incompatible with 1.x modules, which means that Deadbolt required some updating of its own.

Let’s get the negative issue out of the way before I get started on the nitty-gritty. In Play 1, you created a new module by typing “play new-module ” into your shell, and you were good to go. With Play 2 and its concept of modular applications, it seems the concept of modules has to some degree become blurred and there’s a lack of documentation to really address issues such as packaging, etc. It’s possible – or probable – that I’ve just missed the existing docs, so I’ll be following up on this with a future post that looks at creating a module from scratch.

And now, to the good bits.

The original Deadbolt was built in such a way that it had a few interfaces (it didn’t impose any persistence issues on you) and a few fairly monolithic classes that handled the authorization checks. You could apply static and dynamic checks with

@With(Deadbolt.class)
public class MyController extends Controller
{
    // static check - user must have the foo AND bars roles
    @Restrict({"foo", "bar"})
    public static void index() {...}

    // static check - user must have the foo OR bars role
    @Restrictions({@Restrict("foo"), @Restrict("bar")})
    public static void view() {...}

    // dynamic check - application-specific security check
    @RestrictedResource("foo")
    public static void edit() {...}
}

In the application, it was nice and unobtrusive – you add a few annotations (either at the view, controller or controller method level) and you have fine-grained authorization control over your application. Later additions let you give content type hints to make it easier to secure web services and ajax calls, or to unsecure or loosely secure elements.

In the actual implementation of Deadbolt however, there was a lot of monolithic code – the Deadbolt class itself covered all the dynamic and static checks, as well as the checks from the views. It worked well, but I was never particularly satisfied with the actual code that went into making it.

The re-write for Deadbolt 2 has taken – to my great joy and general happiness – a completely different approach thanks to the new architecture of Play 2. Each annotation – @Restrict, @Restrictions, @Dynamic, etc, – has an associated action which is invoked prior to the method. When mixing controller and method restrictions, the method restrictions are applied first which allows the more-specific restriction to apply to the resource. This behaviour was also present in the original Deadbolt, but it required a lot of framework-provided reflection and duplicate code. The result, to take a short example, is the @RoleHolderPresent annotation – this particular restriction will prevent access to anyone who isn’t logged into your application.

Here’s the annotation…

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Documented
@Inherited
public @interface RoleHolderPresent
{
}

and here’s the action…

public class RoleHolderPresentAction extends AbstractDeadboltAction<RoleHolderPresent>
{
    public Result call(Http.Context ctx) throws Throwable
    {
        Result result;
        // here we check if a more specific action has already processed the call
        if (isActionUnauthorised(ctx))
        {
            result = onAccessFailure(getDeadboltHandler(configuration.handler()),
                                     configuration.content(),
                                     ctx);
        }
        else
        {
            // and here we perform the specific check for the annotation
            DeadboltHandler deadboltHandler = getDeadboltHandler(configuration.handler());
            RoleHolder roleHolder = getRoleHolder(ctx,
                                                  deadboltHandler);

            if (roleHolder != null)
            {
                markActionAsAuthorised(ctx);
                result = delegate.call(ctx);
            }
            else
            {
                markActionAsUnauthorised(ctx);
                result = onAccessFailure(deadboltHandler,
                                         configuration.content(),
                                         ctx);
            }
        }

        return result;
    }
}

For comparison, the equivalent of RoleHolderPresent was a member of a 481-line class.

The result is a much cleaner, less repetitive implementation. What duplication there is comes as a result of Java annotations not being able to implement interfaces, which is a reasonable trade-off. The result of the cleaner code – apart from the increased ease of maintenance, etc, it that it’s easier to see how to extend and improve the feature set. I for one would rather work with five twenty-line classes than one of one hundred lines.

One thing that’s missing at the moment is the Scala API. Play 2 supports Java and Scala as first-class citizens, and I want to take advantage of this to widen the potential user base of Deadbolt.

The new architecture of Play 2 is – to my mind – the result of a carefully thought out evolution of the framework, and that’s why I support the lack of backwards compatibility.

Deadbolt-2 on github: https://github.com/schaloner/deadbolt-2

Leave a Reply

Your email address will not be published. Required fields are marked *