Action builders
Using the ActionsBuilders
class, you can quickly assemble constraints around your functions. To get started, inject ActionBuilders
into your controller.
class ExampleController @Inject() (actionBuilder: ActionBuilders) extends Controller
You now have builders for all the constraint types, which we'll take a quick look at in a minute. In the following examples I'm using the default handler, i.e. .defaultHandler()
but it's also possible to use a different handler with .key(HandlerKey)
or pass in a handler directly using .withHandler(DeadboltHandler)
.
SubjectPresent and SubjectNotPresent
Sometimes, you don't need fine-grained checks - you just need to see if there is a user present (or not present).
// DeadboltHandler#getSubject must result in a Some for access to be granted
def someFunctionA = actionBuilder.SubjectPresentAction().defaultHandler() { authRequest =>
Future {
Ok(accessOk())
}
}
// DeadboltHandler#getSubject must result in a None for access to be granted
def someFunctionB = actionBuilder.SubjectNotPresentAction().defaultHandler() { authRequest =>
Future {
Ok(accessOk())
}
}
Restrict
This uses the Subject
's Role
s 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 Array[String]
(or more correctly, String*
, OR is a List[Array[String]]
, and NOT is a rolename with a !
preceding it.
// subject must have the "foo" role
def restrictedFunctionA = actionBuilder.RestrictAction("foo").defaultHandler() { authRequest =>
Future {
Ok(accessOk())
}
}
// subject must have the "foo" AND "bar" roles
def restrictedFunctionB = actionBuilder.RestrictAction("foo", "bar").defaultHandler() { authRequest =>
Future {
Ok(accessOk())
}
}
// subject must have the "foo" OR "bar" roles
def restrictedFunctionC = actionBuilder.RestrictAction(List(Array("foo"), Array("bar"))).defaultHandler() { authRequest =>
Future {
Ok(accessOk())
}
}
That whole and/or/array/list thing looks pretty ugly, so instead you can use anyOf
, allOf
and allOfGroup
from the be.objectify.deadbolt.scala
package object instead.
allOf
can be used to define an AND relationship, e.g.Array("foo", "bar")
can be written asallOf("foo", "bar")
- this would then need to be placed in a list for use within a restriction.anyOf
can be used to define an OR relationship, e.g.List(Array("foo"), Array("bar"))
can be written asanyOf(allOf("foo"), allOf("bar"))
.allOfGroup
is a convenient way of defining a single AND relationship, e.g.List(Array("foo", "bar"))
can be written asallOfGroup("foo", "bar")
.
This means restrictedFunctionC
from the previous template can be rewritten as follows.
// subject must have the "foo" OR "bar" roles
def restrictedFunctionC = actionBuilder.RestrictAction(anyOf(allOf("foo"), allOf("bar"))).defaultHandler() { authRequest =>
Future {
Ok(accessOk())
}
}
Pattern
This uses the Subject
's Permission
s to perform a variety of checks.
// subject must have a permission with the exact value "admin.printer"
def permittedFunctionA = actionBuilders.PatternAction(value = "admin.printer",
patternType = PatternType.EQUALITY).defaultHandler() { authRequest =>
Future {
Ok(accessOk())
}
}
// subject must have a permission that matches the regular expression (without quotes) "(.)*\.printer"
def permittedFunctionB = actionBuilders.PatternAction(value = "(.)*\.printer",
patternType = PatternType.REGEX).defaultHandler() { authRequest =>
Future {
Ok(accessOk())
}
}
// the checkPermssion function of the current handler's DynamicResourceHandler will be used. This is a user-defined test
def permittedFunctionC = actionBuilders.PatternAction(value = "something arbitrary",
patternType = PatternType.CUSTOM).defaultHandler() { authRequest =>
Future {
Ok(accessOk())
}
}
// the checkPermssion function of the current handler's DynamicResourceHandler will be used. Additional information is passed to it via the meta parameter. This is a user-defined test
def permittedFunctionC = actionBuilders.PatternAction(value = "something arbitrary",
patternType = PatternType.CUSTOM,
meta = Some("this can be an Option[Any]")).defaultHandler() { authRequest =>
Future {
Ok(accessOk())
}
}
// subject must have no permissions with the exact value "admin.printer"
def permittedFunctionA = actionBuilders.PatternAction(value = "admin.printer",
patternType = PatternType.EQUALITY,
invert = true).defaultHandler() { authRequest =>
Future {
Ok(accessOk())
}
}
Dynamic
The most flexible constraint - this is a completely user-defined constraint that uses DynamicResourceHandler#isAllowed
to determine access.
def foo = actionBuilder.DynamicAction(name = "someClassifier").defaultHandler() { authRequest =>
Future {
Ok(accessOk())
}
}
You can also pass addition information to the constraint using the meta
parameter.
def foo = actionBuilder.DynamicAction(name = "someClassifier",
meta = Some("this can be an Option[Any]")).defaultHandler() { authRequest =>
Future {
Ok(accessOk())
}
}
Updated less than a minute ago