Under the hood: Authorization

This post is about the current status of the authorization system and will focus on the parts that are nessecary to understand to write API-servlets.

Permissions

In order to understand the following concept, we first have to clearify how we manage permissions. A permission by itself is a key-value pair, declared on servlet-level. Think something like this:

allowed-to-download : true

max-downloads : 10

We currently have three levels on which permissions get set:

Base-User-Roles

We have a small set of hardcoded roles, we call them base-user-roles, which get permissions assigned directly in the java code.

These permissions can be seen as default permissions. They can be overritten for user-roles or individual users.

We currently have the following base-user-roles:

ANONYMOUS, // the lowest user-roles, usually for not logged-in users
USER, // normal user-roles
PRIVILEGED, // user-roles with special privileges like moderators
ADMIN // admin-roles

User-Roles

Not hardcoded but fully configurable, we have user-roles. Each user-role has a parent from which it inherits permissions. The parent can either be a base-user-role or another user-role. In the end, there must always be a base-user-role at the root of the tree.

Each user-role can override permissions inherited from it’s parent, making them strongly configurable.

By default, the user-roles are directly derived from the base-user-roles and do not have any overrides.

Users

At the end, there’re the individual users. Each user has a user-role, from which she inherits permissions. But of course, she can again have individual overrides.

 

Servlets

In order to use the AAA-system (Authentication, Authorization, Accounting), a servlet has to extend the AbstractAPIHandler class. It therefor has to override four methods:

public BaseUserRole getMinimalBaseUserRole()
public JSONObject getDefaultPermissions(BaseUserRole baseUserRole)
public String getAPIPath()
public JSONObject serviceImpl(Query post, 
Authorization rights, final JSONObjectWithDefault permissions)

The third  is just about the path of the servlet. The fourths is the actual implementation of the servlet, we will come back to that shortly.

The first two are exclusevly for the authorization system. Here’s some example implementation:

@Override
public BaseUserRole getMinimalBaseUserRole() {
   return BaseUserRole.PRIVILEGED;
}

This means, that the user-role of the user accessing the servlet must be derived atleast from the PRIVILEGED-base-user-role. Of course, ADMIN would also be ok. All other users get a 401-HTTP-Error. This method is intended to make it very explicit and hard to confuse if a servlet should be limited to, for example, admins only. For more sophisticated permission management, we use the second method:

@Override
public JSONObject getDefaultPermissions(BaseUserRole baseUserRole){
   JSONObject result = new JSONObject();

   switch(baseUserRole){
      case ADMIN:
         result.put("list_users", true);
         result.put("list_users-roles", true);
         result.put("edit-all", true);
         result.put("edit-less-privileged", true);
         break;
      case PRIVILEGED:
         result.put("list_users", true);
         result.put("list_users-roles", true);
         result.put("edit-all", false);
         result.put("edit-less-privileged", true);
         break;
      default:
         result.put("list_users", false);
         result.put("list_users-roles", false);
         result.put("edit-all", false);
         result.put("edit-less-privileged", false);
         break;
   }
   return result;
}

Here we define default permissions based on the base-user-role. The example is from the user-management servlet, so we only allow administrators and special priviledged users anyway. The default values would not be used in this example.

In this method we should declare all keys we want to use in the servlet. By default, we allow privileged users to edit the profiles of users with the base-user-role USER or ANONYMOUS.

We maybe want a user-role that is able to list the users, but is not able to edit any user. We could archive that by overriding ‘edit-less-privileged’ to ‘false’. This will be possible via a the user-management servlet, for which we’ll have a graphical app.

So how do we use it? Here’s is how the ‘serviceImpl` could look like:

@Override
public JSONObject serviceImpl(Query post, Authorization authorization,
final JSONObjectWithDefault permissions) throws APIException {

   JSONObject result = new JSONObject();

   switch (post.get("show","")){
      case "user-list":
         if(permissions.getBoolean("list_users", false)){
            result.put("user-list", DAO.authorization.getPersistent());
         } else throw new APIException(403, "Forbidden");
         break;
      default: throw new APIException(400, "No 'show' parameter specified");
   }

   return result;
}

The ‘permission’ object contains all the values for this servlet, from the base-user-roles, the overrides from the user-role(s) and the overrides for the specific user.

It’s actually a ‘JSONObject’, but given as ‘JSONObjectWithDefault’, which just extends the ‘get’ methods of ‘JSONObject’ with default values. This is just to avoid security issues because of errors.

We can also get the permissions for this or other servlets from the Authorization servlet, by calling ‘authorization.getPermissions(this);’ or ‘authorization.getPermissions(new SignUpService());’ We actually have to initialize a object for it, as Java does not support methods that are static and abstract at the same time.

I hope that gives you an idea how to currently use authorization in servlets 🙂

Note: from here on, Michael will take over the further development of the AAA-system, so some things might change in the future.

Under the hood: Authorization