Action composition

Using the DeadboltActions class, you can compose constrained functions. To get started, inject DeadboltActions into your controller.

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>.

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 = deadbolt.SubjectPresent()() { authRequest =>
  Future {
    Ok("Content accessible")
  }
}

// DeadboltHandler#getSubject must result in a None for access to be granted
def someFunctionB = deadbolt.SubjectNotPresent()() { authRequest =>
  Future {
    Ok("Content accessible")
  }
}

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 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 = deadbolt.Restrict(List(Array("foo")))() { authRequest =>
  Future {
    Ok("Content accessible")
  }
}

// subject must have the "foo" AND "bar" roles 
def restrictedFunctionB = deadbolt.Restrict(List(Array("foo", "bar")))() { authRequest =>
  Future {
    Ok("Content accessible")
  }
}

// subject must have the "foo" OR "bar" roles 
def restrictedFunctionC = deadbolt.Restrict(List(Array("foo"), Array("bar")))() { authRequest =>
  Future {
    Ok("Content accessible")
  }
}

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 as allOf("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 as anyOf(allOf("foo"), allOf("bar")).
  • allOfGroup is a convenient way of defining a single AND relationship, e.g. List(Array("foo", "bar")) can be written as allOfGroup("foo", "bar").

This means the previous template can be rewritten as follows.

// subject must have the "foo" role 
def restrictedFunctionA = deadbolt.Restrict(allOfGroup("foo"))() { authRequest =>
  Future {
    Ok("Content accessible")
  }
}

// subject must have the "foo" AND "bar" roles 
def restrictedFunctionB = deadbolt.Restrict(allOfGroup("foo", "bar"))() { authRequest =>
  Future {
    Ok("Content accessible")
  }
}

// subject must have the "foo" OR "bar" roles 
def restrictedFunctionC = deadbolt.Restrict(anyOf(allOf("foo"), allOf("bar")))() { authRequest =>
  Future {
    Ok("Content accessible")
  }
}

Pattern

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

// subject must have a permission with the exact value "admin.printer" 
def permittedFunctionA = deadbolt.Pattern(value = "admin.printer",
                                          patternType = PatternType.EQUALITY)() { authRequest =>
  Future {
    Ok("Content accessible")
  }
}

// subject must have a permission that matches the regular expression (without quotes) "(.)*\.printer" 
def permittedFunctionB = deadbolt.Pattern(value = "(.)*\.printer",
                                          patternType = PatternType.REGEX)() { authRequest =>
  Future {
    Ok("Content accessible")
  }
}

// the checkPermssion function of the current handler's DynamicResourceHandler will be used.  This is a user-defined test in DynamicResourceHandler#checkPermission 
def permittedFunctionC = deadbolt.Pattern(value = "something arbitrary",
                                          patternType = PatternType.CUSTOM)() { authRequest =>
  Future {
    Ok("Content accessible")
  }
}

// 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 in DynamicResourceHandler#checkPermission 
def permittedFunctionC = deadbolt.Pattern(value = "something arbitrary",
                                          patternType = PatternType.CUSTOM,
                                          meta = Some("this can be an Option[Any]"))() { authRequest =>
  Future {
    Ok("Content accessible")
  }
}

// subject must have no permissions with the exact value "admin.printer" 
def permittedFunctionA = deadbolt.Pattern(value = "admin.printer",
                                          patternType = PatternType.EQUALITY,
                                          invert = true)() { authRequest =>
  Future {
    Ok("Content accessible")
  }
}

Dynamic

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

def foo = deadbolt.Dynamic(name = "someClassifier")() { authRequest =>
  Future {
    Ok("Content accessible")
  }
}

You can also pass addition information to the constraint using the meta parameter.

def foo = deadbolt.Dynamic(name = "someClassifier",
                          meta = Some("this can be an Option[Any]"))() { authRequest =>
  Future {
    Ok("Content accessible")
  }
}