10. Scala controller constraints
Controller-level constraints can be added in two different ways - through the use of action builders and through action composition. The resulting behaviour is identical, so choose whichever suites your style best.
10.1 Controller constraints with the action builder
To get started, inject ActionBuilders into your controller.
1 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).
10.2 Controller constraints with action composition
Using the DeadboltActions class, you can compose constrained functions. To get started, inject DeadboltActions into your controller.
1 class ExampleController @Inject() (deadbolt: DeadboltActions) extends Controller
You now have functions equivalent to those of the builders mentioned above. In the following examples I’m using the default handler, i.e. no handler is specified, but it’s also possible to use a different handler with handler = <some handler, possibly from the handler cache>.
10.3 SubjectPresent
Sometimes, you don’t need fine-grained checks - you just need to see if there is a user present.
Action builder
1 def someFunctionA = actionBuilder.SubjectPresentAction().defaultHandler() { Ok(accessOk())\
2 }
Action composition
| Parameter | Type | Default | Notes |
|---|---|---|---|
| handler | DeadboltHandler | HandlerCache.apply() | The DeadboltHandler instance to use. |
1 def someFunctionA = deadbolt.SubjectPresent() {
2 Action {
3 Ok(accessOk())
4 }
5 }
10.4 SubjectNotPresent
Sometimes, you don’t need fine-grained checks - you just need to see if there is no user present.
Action builder
1 def someFunctionB = actionBuilder.SubjectNotPresentAction().defaultHandler() { Ok(accessOk\
2 ()) }
Action composition
| Parameter | Type | Default | Notes |
|---|---|---|---|
| handler | DeadboltHandler | HandlerCache.apply() | The DeadboltHandler instance to use. |
1 def someFunctionB = deadbolt.SubjectNotPresent() {
2 Action {
3 Ok(accessOk())
4 }
5 }
10.5 Restrict
Restrict uses a 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 Array[String] (or more correctly, String*), OR is a List[Array[String]], and NOT is a rolename with a ! preceding it.
Action builder
| Parameter | Type | Default | Notes |
|---|---|---|---|
| roles | List[Array[String]] | Allows the definition of OR’d constraints by | |
| having multiple arrays in the list. | |||
| roles | String* | A short-hand of defining a single role or AND | |
| constraint. |
1 def restrictedFunctionA = actionBuilder.RestrictAction("foo")
2 .defaultHandler() { Ok(accessOk()) }
1 def restrictedFunctionB = actionBuilder.RestrictAction("foo", "bar")
2 .defaultHandler() { Ok(accessOk()) }
1 def restrictedFunctionC = actionBuilder.RestrictAction(List(Array("foo"), Array("bar")))
2 .defaultHandler() { Ok(accessOk()) }
Action composition
| Parameter | Type | Default | Notes |
|---|---|---|---|
| roleGroups | List[Array[String]] | Allows the definition of OR’d constraints by | |
| having multiple arrays in the list. | |||
| handler | DeadboltHandler | HandlerCache.apply() | The DeadboltHandler instance to use. |
1 def restrictedFunctionA = deadbolt.Restrict(List(Array("foo")) {
2 Action {
3 Ok(accessOk())
4 }
5 }
1 def restrictedFunctionB = deadbolt.Restrict(List(Array("foo", "bar")) {
2 Action {
3 Ok(accessOk())
4 }
5 }
1 def restrictedFunctionB = deadbolt.Restrict(List(Array("foo"), Array("bar")) {
2 Action {
3 Ok(accessOk())
4 }
5 }
10.6 Pattern
Pattern uses a Subject’s Permissions to perform a variety of checks. The check depends on the pattern type.
- EQUALITY - the subject must have a permission whose value is exactly the same as the
valueparameter - REGEX - the subject must have a permission which matches the regular expression given in the
valueparameter - CUSTOM - the
DynamicResourceHandler#checkPermissionfunction is used to determine access
It’s possible to invert the constraint by setting the invert parameter to true. This changes the meaning of the constraint in the following way.
- EQUALITY - the subject must NOT have a permission whose value is exactly the same as the
valueparameter - REGEX - the subject must have NO permissions that match the regular expression given in the
valueparameter - CUSTOM - the
DynamicResourceHandler#checkPermissionfunction, where the OPPOSITE of the Boolean resolved from the function is used to determine access
Action builder
| Parameter | Type | Default | Notes |
|---|---|---|---|
| value | String | The value of the permission. | |
| patternType | PatternType | PatternType.EQUALITY | One of EQUALITY, REGEX or CUSTOM. |
| invert | Boolean | false | Invert the result of the test |
1 def permittedFunctionA = actionBuilders.PatternAction(value = "admin.printer",
2 patternType = PatternType.EQUALITY)
3 .defaultHandler() { Ok(accessOk()) }
1 def permittedFunctionB = actionBuilders.PatternAction(value = "(.)*\.printer",
2 patternType = PatternType.REGEX)
3 .defaultHandler() { Ok(accessOk()) }
1 // the checkPermssion function of the current handler's DynamicResourceHandler
2 // will be used. This is a user-defined test
3 def permittedFunctionC = actionBuilders.PatternAction(value = "something arbitrary",
4 patternType = PatternType.CUSTOM)
5 .defaultHandler() { Ok(accessOk()) }
1 def permittedFunctionB = actionBuilders.PatternAction(value = "(.)*\.printer",
2 patternType = PatternType.REGEX,
3 invert = true)
4 .defaultHandler() { Ok(accessOk()) }
Action composition
| Parameter | Type | Default | Notes |
|---|---|---|---|
| value | String | The value of the permission. | |
| patternType | PatternType | PatternType.EQUALITY | One of EQUALITY, REGEX or CUSTOM. |
| handler | DeadboltHandler | HandlerCache.apply() | The DeadboltHandler instance to use. |
| invert | Boolean | false | Invert the result of the test |
1 def permittedFunctionA = deadbolt.Pattern(value = "admin.printer",
2 patternType = PatternType.EQUALITY) {
3 Action {
4 Ok(accessOk())
5 }
6 }
1 def permittedFunctionB = deadbolt.Pattern(value = "(.)*\.printer",
2 patternType = PatternType.REGEX) {
3 Action {
4 Ok(accessOk())
5 }
6 }
1 // the checkPermssion function of the current handler's DynamicResourceHandler
2 // will be used.
3 def permittedFunctionC = deadbolt.Pattern(value = "something arbitrary",
4 patternType = PatternType.CUSTOM) {
5 Action {
6 Ok(accessOk())
7 }
8 }
1 def permittedFunctionB = deadbolt.Pattern(value = "(.)*\.printer",
2 patternType = PatternType.REGEX,
3 invert = true) {
4 Action {
5 Ok(accessOk())
6 }
7 }
10.7 Dynamic
The most flexible constraint - this is a completely user-defined constraint that uses DynamicResourceHandler#isAllowed to determine access.
Action builder
| Parameter | Type | Default | Notes |
|---|---|---|---|
| name | String | The name of the constraint. | |
| meta | String | Additional information for the constraint | |
| implementation to use. |
1 def foo = actionBuilder.DynamicAction(name = "someClassifier")
2 .defaultHandler() { Ok(accessOk()) }
Action composition
| Parameter | Type | Default | Notes |
|---|---|---|---|
| name | String | The name of the constraint. | |
| meta | String | Additional information for the constraint | |
| implementation to use. | |||
| handler | DeadboltHandler | HandlerCache.apply() | The DeadboltHandler instance to use. |
1 def foo = deadbolt.Dynamic(name = "someClassifier") {
2 Action {
3 Ok(accessOk())
4 }
5 }