Subject, Role, Privilege – DeadBolt in Play! Framework

If you have a website on which users can register and login, then you also want to protect your application from attackers. We recommend you to protect your application’s actions not only from attackers, but from users, too. For example, if you want to make a user who can upload Excel files on a specific UI, then that user should neither see other UIs, nor should s/he be allowed to take any other actions.

Deadbolt in play framework - padlock

That’s why you should create Roles in your application. For example, that user-role could be something like “excel-uploader”, and you should give that role privileges like “view-excel-upload-view”, “upload-excel” etc.

You can connect Privileges to Roles, and Roles to Users. If you want to give a user more roles, of course you can. If you want that uploader user to detonate printers, then you should make a role called detonator, and give that role the privilege “detonate-printer”. After that you give the user the role detonator, and you are done.

Subject = The user

Role = Abstract stuff that collects privileges, like administrator, manager, etc

Privilege = Restriction to do a concrete action

(Disclaimer: Example taken from the original documentation. You shouldn’t detonate printers. Like… ever. But, if you ever need such a task completed, you should control it with roles and privileges.)

 

What is DeadBolt

DeadBolt is a free, open-source module for permission handling in Play! Framework. If you are a web developer, you must set up your application’s security to defend it from attackers. With this module you can easily handle user authorization for actions.

 

How to set up DeadBolt with Play! Framework 2.3.x

You have to add the following lines to the following files to load the module

build.sbt
resolvers += Resolver.url("Objectify Play Repository", url("http://schaloner.github.io/releases/"))(Resolver.ivyStylePatterns)
 
libraryDependencies ++= Seq(
  //...
  "be.objectify" %% "deadbolt-java" % "2.3.1"
  //...
)
 

Thanks to Steve Chaloner, we now know that

If you use Deadbolt 2.3.3 in place of 2.3.1, you don’t need to add the extra resolver. As of 2.3.2 onwards, artifacts were published to Maven central.

application.conf
deadbolt.java.handler=<mypackage.otherpackage.MyDeadboltHandler>
play.plugins
10000:be.objectify.deadbolt.java.DeadboltPlugin

 

How to set up DeadBolt with Play! Framework 2.4.x

You have to add the following lines to the following files to load the module (watch out for the version, it’s 2.4.3 here, and was 2.3.1 previously)

build.sbt
resolvers += Resolver.url("Objectify Play Repository", url("http://schaloner.github.io/releases/"))(Resolver.ivyStylePatterns)
 
libraryDependencies ++= Seq(
  //...
  "be.objectify" %% "deadbolt-java" % "2.4.3"
  //...
)

Again, thanks to Steve Chaloner, we now know that

If you use Deadbolt 2.3.3 in place of 2.3.1, you don’t need to add the extra resolver. As of 2.3.2 onwards, artifacts were published to Maven central.

application.conf
play {
  modules {
    enabled += be.objectify.deadbolt.java.DeadboltModule
  }
}

 

Fantastic Interfaces

Subject interface
public interface Subject {
    List<? extends Role> getRoles();
    List<? extends Permission> getPermissions();
}

You should implement this interface in your class representing the user. DeadBolt will call the two functions, contained in the interface as methods, to check the roles and/or permissions.

Role interface
public interface Role {
    public String getName();
}

Interface for DeadBolt to identify the roles.

Permission interface
public interface Permission {
   public String getValue()
}

Interface for DeadBolt to identify the permissions.

 

The DeadBoltHandler – Where awesomeness happens

MyDeadBoltHandler
@Transactional
public class MyDeadboltHandler extends AbstractDeadboltHandler {
   @Override
   public F.Promise<Result> beforeAuthCheck(Http.Context context) {
      return F.Promise.pure(null);
   }
   @Override
   public Subject getSubject(Http.Context context) {
      String sessionId = context.session().get("sessionId");
      return SessionStoreAdapter.getCurrentUser(sessionId);
   }
   @Override
   public F.Promise<Result> onAuthFailure(Http.Context context, String content) {
      final Http.Context c = context;
      return F.Promise.promise(new F.Function0<Result>() {
         @Override
         public Result apply() throws Throwable {
           String path = c.request().path();
           if(!"/".equals(path)) {
              c.flash().put("error", Messages.get("global.error.noauthorizationforthispage"));
           }
           return redirect(controllers.core.login.routes.LoginCtrl.login(path));
         }
      });
   }
}

Let’s talk about these functions a bit!

We don’t really use the beforeAuthCheck function in our applications. Returning null means everything is OK.

The getSubject function is to tell DeadBolt who your currently logged in user is. It will call this user’s getPersmissions and getRoles functions, to check whether the user is authorized to do that action. In our applications, we store the users’ data in the SessionStore (Play’s ehCache), so we don’t have to run a query… every…. time… Querying a database is soooo much slower than getting the data from the ehCache.

If you use any encoder library, like JWT, you can decode your encoded token in the getSubject function.

The onAuthFailure function is a callback function. DeadBolt calls onAuthFailure when the user doesn’t have permission for a specific action.

 

How to protect your Controller Actions

MyController.java
@SubjectPresent
public class MyController extends Controller {
    @Pattern(DO_THIS_ACTION)
    public static Result view(long id) {
        //...
    }
}

First of all: You should declare your permissions as

Permission
public static final String DO_THIS_ACTION = "do-this-action";

because you can only use constant values in the @Pattern annotation, and this will result in no typos in the permission string whatsoever.

Secondly, you should protect all your actions (except the login action ofcourse) by annotating the class with @SubjectPresent. This way, all of your functions in that class will be protected by default, so only users logged in will be able to call your functions. You can override this default protection method by annotating the function with @Pattern. Use @Pattern for permissions, and @Restrict for roles.

These annotations will call your MyDeadboltHandler’s functions to check authorization.

Available annotations:

  • SubjectPresent
  • SubjectNotPresent
  • Restrict
  • Unrestricted (to unrestrict a function that is SubjectPresent restricted by the class annotation. Use this at the login action)
  • Pattern

 

How to protect your Scala Templates

my_template.scala.html
@pattern(Permissions.CLICK_AWSUM_BUTTON) {
    <button>AWSUM BUTTON!!!!</button>
}
 
@patternOr(Permissions.CLICK_AWSUM_BUTTON) {
    <button>AWSUM BUTTON!!!!</button>
}{
    <button>Not that awsum button, but still fine</button>
}

It’s as easy as it looks. You just wrap your code you want to protect into that annotation, and tadaaaa, it’s protected. Every annotation has an ‘Or’ ending version (like pattern patternOr). These Or annotations are like an if-else statement. If the user has permission to see that content, it will be shown to her, otherwise something else will be shown.

Available annotations:

  • SubjectPresent(Or)
  • SubjectNotPresent(Or)
  • Restrict(Or)
  • Pattern(Or)

 

To sum it up:

As you see, DeadBolt is an extremely easy to use plugin for Play! Framework handling user authorization for you. If you are a backend developer using Play! Framework, I totally recommend using DeadBolt, too (smile)

Alex Sükein

Alex Sükein

- Süxy, can you tell me about robust software development Nasa uses?
- Yes. If we have a final exam tomorrow.