Controller constraints

Controller constraints are defined through annotations. These annotations can be applied at the class level, in which case they are applied to every action within the controller, or on specific action methods.

If you prefer to add authorization constraints outside the controllers, take a look at Authorized routes.

SubjectPresent and SubjectNotPresent

Sometimes, you don't need fine-grained checked - you just need to see if there is a user present (or not present).

@SubjectPresent
public CompletionStage<Result> someMethodA() {
    // method will execute if the current DeadboltHandler's getSubject returns Some
}

@SubjectNotPresent
public CompletionStage<Result> someMethodB() {
    // method will execute if the current DeadboltHandler's getSubject returns None
}

Restrict

This uses the Subject's Roles to perform AND/OR/NOT checks. The values given to the builder must match the Role.name of the subject's roles.

AND is defined as an @Group, OR is an array of @Group, and NOT is a rolename with a ! preceding it.

@Restrict(@Group("foo"))
public CompletionStage<Result> someMethodA() {
    // method will execute of subject has the "foo" role
}

@Restrict(@Group("foo", "bar"))
public CompletionStage<Result> someMethodB() {
    // method will execute of subject has the "foo" AND "bar" roles
}

@Restrict({@Group("foo"), @Group("bar")})
public CompletionStage<Result> someMethodC() {
    // method will execute of subject has the "foo"OR "bar" roles
}

Pattern

This uses the Subject's Permissions to perform a variety of checks.

@Pattern("admin.printer")
public CompletionStage<Result> someMethodA() {
    // subject must have a permission with the exact value "admin.printer"
}

@Pattern(value = "(.)*\.printer", patternType = PatternType.REGEX)
public CompletionStage<Result> someMethodB() {
    // subject must have a permission that matches the regular expression (without quotes) "(.)*\.printer"
}

@Pattern(value = "something arbitrary", patternType = PatternType.CUSTOM)
public CompletionStage<Result> someMethodC() {
    // the checkPermssion method of the current handler's DynamicResourceHandler will be used.  This is a user-defined test
}

If you want to invert the result, i.e. deny access if there's a match, set the invert attribute to true.

@Pattern(value = "admin.printer", invert = true)
public CompletionStage<Result> someMethodA() {
    // subject with a permission with the exact value "admin.printer" will by denied
}

Dynamic

The most flexible constraint - this is a completely user-defined constraint that uses DynamicResourceHandler#isAllowed to determine access.

@Dynamic(name = "name of the test")
public CompletionStage<Result> someMethod() {
    // the method will execute if the user-defined test returns true
}

RoleBasedPermissions

This is similar to using @Pattern, except that you can only constraint access with a single permission this way, whereas @RoleBasedPermissions allows you to constraint access with any of the permissions linked to a role. Let's assume that a role foo gives these permissions:

  • admin.pr.blog.post.create
  • admin.pr.blog.post.delete
  • admin.pr.blog.post.update
  • admin.pr.twitter.post

Using @RoleBasedPermissions("foo"), you can constrain access to a subject with any of those permissions. However, if you want to have an access to an action constrained to subjects with admin.pr.twitter permissions, you can target a subset of subjects with the foo role using @Pattern("admin.pr.twitter.*"). In practice, you may not want to mix the different approaches but the possibility is there.

@RoleBasedPermissions("foo")
public CompletionStage<Result> someMethod() {
    // the method will execute if the subject has a permission 
    // that is matched by at least one of the permissions obtained
    // from DeadboltHandler.getPermissionsForRole("foo")
}

This still doesn't provide a mechanism for assigning those permissions to a subject when a role is assigned, but my feeling here is this logic should be handled by the application itself. This could be done by injecting the handler cache into your user management code, which can then be used to obtain the default handler, and when a subject is given a role, use DeadboltHandler#getPermissionsForRole to find out which permissions to assign the subject at the same time. This make a small assumption: even if you have multiple handlers, the result of DeadboltHandler#getPermissionsForRole would always be the same for any given role.

Equally, when removing a role from a subject, DeadboltHandler#getPermissionsForRole could be used to determine the subset of permissions to remove from the subject, e.g. (permissions of removed role) \ (permissions of all other roles held by subject).

Using non-default DeadboltHandler implementations

Each annotation has a handlerKey parameter. If you don't specify anything, the default DeadboltHandler will be used. If you want to use another implementation, the value of the handlerKey argument can be anything defined in your HandlerCache. See Integrating Deadbolt for information on how to define this configuration.