Deadbolt 2 Java

This is a collection of examples using Deadbolt 2 at both the controller and template level to implement authorisation in a Play 2 application.

Configuration

For the purposes of these examples, except where stated otherwise, the user has the following roles:

  • foo
  • bar

The user also has the following permissions:

  • printers.edit

Controller authorisation

Protecting your controllers against unauthorised use is a key element of good application security. Here, you'll find examples of each of the controller-level authorisations provided by Deadbolt 2.

For each example, the action is shown on the left, and the result is loaded into an iframe on the right.

SubjectPresent

This is one of the simplest constraints in Deadbolt. It simply requires that a user be present (i.e. logged in).

Specification
Result
@SubjectPresent
public static Result subjectPresent() {
    return ok(accessOk.render());
}
@SubjectPresent(handler = NoUserDeadboltHandler.class)
public static Result subjectPresent_notLoggedIn() {
    return ok(accessOk.render());
}

SubjectNotPresent

The counterpart to SubjectPresent. This constraint requires that a user isn't present (i.e. no-one is logged in).

Specification
Result
@SubjectNotPresent
public static Result subjectNotPresent_loggedIn() {
    return ok(accessOk.render());
}
@SubjectNotPresent(handler = NoUserDeadboltHandler.class)
public static Result subjectNotPresent() {
    return ok(accessOk.render());
}

Restrict

Restrict uses an ANDed set of roles to determine access to an action. For example, a user with the roles "foo" and "bar" could access a Restrict-protected action that specified any of the following:

  • foo
  • bar
  • foo AND bar

However, a Restrict that required "foo", "bar" and "hurdy" would deny access to the user.

Specification
Result
@Restrict({"foo", "bar"})
public class RestrictController extends Controller
@Restrict("foo")
public static Result restrictOne() {
    return ok(accessOk.render());
}
@Restrict({"foo", "bar"})
public static Result restrictTwo() {
    return ok(accessOk.render());
}
@Restrict({"foo", "!bar"})
public static Result restrictThree() {
    return ok(accessOk.render());
}
@Restrict({"hurdy"})
public static Result restrictFour() {
    return ok(accessOk.render());
}
@CustomRestrict(value = {MyRoles.foo, MyRoles.bar}, config = @Restrict(""))
public static Result customRestrictionOne() {
    return ok(accessOk.render());
}
@CustomRestrict(value = MyRoles.hurdy, config = @Restrict(""))
public static Result customRestrictionOne() {
    return ok(accessOk.render());
}

Restrictions

A Restrictions constraint allows you to OR role groups together. For example, you could allow access to a user that matches at least one of the following restrictions:

  • foo
  • hurdy AND gurdy
Specification
Result
@Restrictions({@And("foo"),
                @And("bar")})
public class RestrictionsController extends Controller
@Restrictions({@And({"foo", "bar"})})
public static Result restrictionsOne() {
    return ok(accessOk.render());
}
@Restrictions({@And({"hurdy", "gurdy"}), @And("foo")})
public static Result restrictionsTwo() {
    return ok(accessOk.render());
}
@Restrictions({@And("foo"), @And("!bar")})
public static Result restrictionsThree() {
    return ok(accessOk.render());
}
@Restrictions(@And({"hurdy", "foo"}))
public static Result restrictionsFour() {
    return ok(accessOk.render());
}
@Restrictions(@And({"foo", "!bar"}))
public static Result restrictionsFive() {
    return ok(accessOk.render());
}
@CustomRestrictions(value = { @RoleGroup({MyRoles.foo, MyRoles.bar}),
                               @RoleGroup(MyRoles.hurdy)},
                     config = @Restrictions({}))
public static Result customRestrictionOne() {
    return ok(accessOk.render());
}
@CustomRestrictions(value = { @RoleGroup({MyRoles.hurdy, MyRoles.foo}),
                               @RoleGroup({MyRoles.hurdy, MyRoles.bar})},
                     config = @Restrictions({}))
public static Result customRestrictionOne() {
    return ok(accessOk.render());
}

Dynamic

Dynamic is the most powerful constraint in Deadbolt. It enforces arbitrary rules. See the documentation for a full overview.

In these examples, the action is shown on the left, the rule specified in the relevant DynamicResourceHandler is in the center and the result is in an iframe on the right.

Specification
Rule
Result
@Dynamic("pureLuck")
public static Result pureLuck() {
    return ok(accessOk.render());
}
public boolean isAllowed(String name,
                         String meta,
                         DeadboltHandler deadboltHandler,
                         Http.Context context) {
    return System.currentTimeMillis() % 2 == 0;
}
@Dynamic(value = "pureLuck", handler = MyAlternativeDeadboltHandler.class)
public static Result noWayJose() {
    return ok(accessOk.render());
}
public boolean checkPermission(String permissionValue,
                               DeadboltHandler deadboltHandler,
                               Http.Context ctx) {
    // Computer says no
    return false;
}
@Dynamic(value = "pureLuck", handler = MyAlternativeDeadboltHandler.class)
public static Result noWayJose() {
    return ok(accessOk.render());
}
public boolean isAllowed(String name,
                         String meta,
                         DeadboltHandler deadboltHandler,
                         Http.Context context) {
    Subject subject = deadboltHandler.getSubject(context);
    boolean allowed;
    if (DeadboltAnalyzer.hasRole(subject, "admin")) {
        allowed = true;
    } else {
        // a call to view profile is probably a get request, so
        // the query string is used to provide info
        // See the Deadbolt documentation on why this is harder to do with path parameters
        Map queryStrings = context.request().queryString();
        String[] requestedNames = queryStrings.get("userName");
        allowed = requestedNames != null
                  && requestedNames.length == 1
                  && ((AuthorisedUser)subject).userName.equals(requestedNames[0]);
    }
    return allowed;
}
@Dynamic(value = "viewProfile")
public static Result viewProfile(String userName) {
    return ok(accessOk.render());
}
public boolean isAllowed(String name,
                         String meta,
                         DeadboltHandler deadboltHandler,
                         Http.Context context) {
    Subject subject = deadboltHandler.getSubject(context);
    boolean allowed;
    if (DeadboltAnalyzer.hasRole(subject, "admin")) {
        allowed = true;
    } else {
        // a call to view profile is probably a get request, so
        // the query string is used to provide info
        // See the Deadbolt documentation on why this is harder to do with path parameters
        Map queryStrings = context.request().queryString();
        String[] requestedNames = queryStrings.get("userName");
        allowed = requestedNames != null
                  && requestedNames.length == 1
                  && ((AuthorisedUser)subject).userName.equals(requestedNames[0]);
    }
    return allowed;
}

Pattern

Pattern allows you to use regular expressions to determine access.

Specification
Result
@Pattern("printers.edit")
public static Result editPrinter() {
    return ok(accessOk.render());
}
@Pattern("printers.detonate")
public static Result detonatePrinter() {
    return ok(accessOk.render());
}
@Pattern(value = "(.)*\\.edit", patternType = PatternType.REGEX)
public static Result editPrinterRegex() {
    return ok(accessOk.render());
}

Unrestricted

Using Unrestricted allows you to ignore wider constraints. For example, an entire controller may be protected with the Dynamic constraint, but methods in that controller may be freed from constraints by marking them as @Unrestrcted.

Specification
Result
@Restrict("hurdy")
public class UnrestrictedController extends Controller {

    public static Result index() {
        return ok(accessOk.render());
    }
}
@Restrict("hurdy")
public class UnrestrictedController extends Controller {

    @Unrestricted
    public static Result unrestrictedWithinAConstrainedController() {
        return ok(accessOk.render());
    }
}

Template authorisation

Deadbolt tags does not offer any real protected against misuse on your server side, but it does allow you to customise your UI according to the privileges of the current user.

Each tag has an "Or" variant, e.g. restrictOr, that allows you to pass in a alternative body for when authorisation fails.

For each example, the unprotected content is on the left, the Deadbolt tag is in the center and the result of the authorisation is on the right.

subjectPresent

This is one of the simplest constraints in Deadbolt. It simply requires that a user be present (i.e. logged in).

Unprotected content
Specification
Result
This content should be visible
@subjectPresent() {
  This content should be visible
}
This content should be visible
This content should NOT be visible
@subjectPresent(new security.NoUserDeadboltHandler()) {
  This content should NOT be visible
}
This content should be visible
@subjectPresentOr() {
  This content should be visible
}{Sorry, no access}
This content should be visible
This content should NOT be visible
@subjectPresentOr(new security.NoUserDeadboltHandler()) {
  This content should be NOT visible
}{Sorry, no access}
Sorry, no access

subjectNotPresent

The counterpart to subjectPresent. This constraint requires that a user isn't present (i.e. no-one is logged in).

Unprotected content
Specification
Result
This content should NOT be visible
@subjectNotPresent() {
  This content should NOT be visible
}
This content should be visible
@subjectNotPresent(new security.NoUserDeadboltHandler) {
  This content should be visible
}
This content should be visible
This content should NOT be visible
@subjectNotPresentOr() {
  This content should NOT be visible
}{Sorry, no access}
Sorry, no access
This content should be visible
@subjectNotPresentOr(new security.NoUserDeadboltHandler) {
  This content should be visible
}{Sorry, no access}
This content should be visible

restrict

restrict uses an ANDed set of roles within an array to determine if a part of a template is rendered. For example, a user with the roles "foo" and "bar" could see a restrict-protected area of template that required any of the following:

  • foo
  • bar
  • foo AND bar

However, a restrict that required "foo", "bar" and "hurdy" would not render the protected area.

Giving multiple arrays in the list gives the equivalent of the Restrictions controller action.

As a convenience for creating Array[String] instances, you can use the TemplateUtils#as(String...) method.

Unprotected content
Specification
Result
This content should be visible
@restrict(la(as("foo", "bar"))) {
  This content should be visible
}
This content should be visible
This content should NOT be visible
@restrict(la(as("foo", "bar", "hurdy"))) {
  This content should NOT be visible
}
This content should be visible
@restrict(List(as("hurdy"), as("foo", "bar"))) {
  This content should be visible
}
This content should be visible
This content should be visible
@restrictOr(la(as("foo", "bar"))) {
  This content should be visible
}{Sorry, you're not allowed to see this}
This content should be visible
This content should NOT be visible
@restrictOr(la(as("foo", "bar", "hurdy"))) {
  This content should NOT be visible
}{Sorry, you're not allowed to see this}
Sorry, you're not allowed to see this

dynamic

dynamic is the most powerful constraint in Deadbolt. It enforces arbitrary rules. See the documentation for a full overview.

Unprotected content
Specification
Result
This content may be visible, depending on your luck
@dynamic(handler, "pureLuck") {
  This content may be visible, depending on your luck
}
This content should NOT be visible
@dynamic(new MyDeadboltHandler("pureLuck", "", new MyAlternativeDynamicResourceHandler())) {
  This content should NOT be visible
}
This content may be visible, depending on your luck
@dynamicOr("pureLuck") {
  This content may be visible, depending on your luck
}{Guess you were unlucky}
Guess you were unlucky
This content should NOT be visible
@dynamicOr("pureLuck", "", new security.MyAlternativeDeadboltHandler()) {
  This content should NOT be visible
}{Guess you were unlucky}
Guess you were unlucky

pattern

pattern allows you to use regular expressions to determine access.

Unprotected content
Specification
Result
This content should be visible
@pattern(handler, "printers.edit") {
  This content should be visible
}
This content should be visible
This content should NOT be visible
@pattern(handler, "printers.foo") {
  This content should not visible
}
This content should be visible
@pattern(handler, "(.)*\\.edit", PatternType.REGEX) {
  This content should not visible
}
This content should be visible