Authorization in Joey's application

Minimal Talos introduction

The Talos documentation is very small and can be read in under five minutes, but what's on this page will get you through the remaining of this tutorial. Here's an excerpt from the Talos overview:

Authorization refers to the process of deciding if someone (subject) can do something (action) on something (object).

Permissions

For each action, we test if the subject has permission(s) to do it. Talos represents all permissions (and everything else) with unique names.

In MUM, we have very few permissions, let me introduce them to you:

Subject Action Predicate
Admin create, list, view, modify, delete Zone
Admin create, list, view, modify, delete, change_members, move Group
Admin create, list, view, modify, delete, change_password User
Normal User list, view Zone
Normal User list Group
Normal User list, view User
Normal User list, view, modify, delete, change_password User (itself)

We create a special permission called "add event" that we add to all subjects on their own user objects. For the other operations, we will use the permissions already existing in MUM.

Objects

Talos calls the object of an action for which there is authorization a secure object.

MUM users, zones and groups are Marbles objects (as are Joey's Event objects). They are represented in Talos by secure objects with unique names using the convention Object:[persistent id], where persistent id is the object's unique identifier in the Marbles repository.

Subjects

They are provided by the authorization interceptor based on the authenticated user. Currently, they are of the form User:[persistent id].

Teaching Talos to handle new objects

In Joey's event tracking application, the subjects are everytime MUM users. The actions he added are the operations on event, and the objects are events themselves. Here are the authorization rules that Joey designed:

  1. User A can create an event for himself.
  2. User A can modify and/or delete events created by A.
  3. User A can see an event created by user B if it can see B's profile.

Something like this:

Subject Action Predicate
Admin add_event, list, view, modify, delete Event (itself)
Admin list, view Event (if he can see the owner's profile)
Normal User add_event, list, view, modify, delete Event (itself)
Normal User list, view Event (if he can see the owner's profile)

It's not deja-vu, the TalosCreator (org.mum.installation.TalosCreator) interface looks just like the Model Creator we've seen in chapter 2:

isUpdateNeeded(Talos talos):boolean
returns true if the authorization needs changes to be considered complete.
update(Talos talos, Repository repo):void
if an update is needed, this method will be called to grant, revoke and change access rights. You also get a repository instance to query the data model and find out which objects needs more access rights.

With Talos, we have made it. It is sooooo easy that Joey can do it while talking to Karen on the phone.
What you did in chapter 2 for the ModelCreator, is what you need to do for the TalosCreator as well:

  1. Subclass the default TalosCreator implementation (org.mum.installation.MumTalosCreator).
  2. Make MUM use your TalosCreator. Define it in ApplicationContext.xml

Letīs start with the first point. Create org.mumtutorial.installation.TutorialTalosCreator. This is how the code looks like:

public void update(Talos talos, Repository repo) {
  if (super.isUpdateNeeded(talos)) {
    super.update(talos, repo);
  }
  if (!talos.allPermissions().contains("add event")) {
    talos.createSimplePermissions("add event");
  }
}
public boolean isUpdateNeeded(Talos talos) {
  return super.isUpdateNeeded(talos) ||
    !talos.allPermissions().contains("add event");
}

Adding permissions to existing users

Joey, hang up! You forgot to add the permission for all users that might already be there. "Allright," he says, "how do I get the user keys?"

Now we use the repository to query some the user objects and get keys of the form Object:[id]. The method looks like this:

protected List<String> fetchUserKeys(Repository repo) {
  List<String> names = new ArrayList<String>();
  for (PObject obj : repo.createFilter("User").list()) {
    names.add("Object:" + obj.getId());
  }
  return names;
}

With this piece of code, we can grant existing users the add event access right in org.mumtutorial.installation.TutorialTalosCreator.update():

if (!talos.allPermissions().contains("add event")) {
  talos.createSimplePermissions("add event");
  List<String> names = fetchUserKeys(repo);
  if (!names.isEmpty()) {
    talos.allSubjects()
      .andObject(names.toArray(new String[names.size()]))
      .grant("add event");
  }
}

I should let Joey himself explain it to you, but since he doesn't exist, I'll tell you what he'd say:

— In my app, a subject is always a user. So all subjects means "all users". I'm giving permissions on users, so the objects I'm manipulating are also users. The Talos code says "grant add event and save event on the objects with the name in names to all subjects."

He's right. By the time the first grant is called, we're working on a set of pairs (subject, object) which represents all subjects matched to all objects. Further details on the Talos documentation

Adding permissions to new users

Now to the users that don't exist yet. Once again, we edit the SaveUser (org.mum.action.user.SaveUser) action. Currently, the user creation action creates a subject for the user, then a secure object (i.e. a Talos object) that belongs to the "users" category. Then it grants rights to change the password and modify himself, then list and view all zones, users and groups.

Here's what it will look like after we're done:

protected void setAccessRights() {
  //create a subject for the user
  SubjectContainer subject = getentenTalos().createSubject("User:" + user.getId());
  //name of the user's secure object
  String objectName = "Object:" + user.getId();
  //create a secure object and add to the users category
  getTalos().createObject(objectName)
    .addCategories("users");
  //grant some rights
  subject.andObject(objectName)
      .grant(AuthorizationConstants.ALL_PERMISSION)
      .grant("add event");
  subject.andCategory("zones", "users", "groups")
    .grant("list", "view");
  if(getCurrentUser() != null){
    getTalos().withSubjects("User:" + getCurrentUser().getId())
      .andObject("Object:"+ getUser().getId())
      .grant("change password", "modify", "delete", "move");
  }
}

We just added the add event permission to the grants for the user on itself.

Adding permissions to existing events

This section is a spoiler somehow, because we introduce the rights for events on the next page. But since this is TalosCreator related, it fits here better.
What we did for existing users previously is needed for existing events as well. We need to add rights to an event which permit the author to modify and delete the event.
To get all existing events add another method to org.mumtutorial.installation.TutorialTalosCreator:

protected List<Long> fetchEventIds(Repository repo) {
  List<Long> ids = new ArrayList<Long>();
  for (PObject obj : repo.createFilter("Event").list()) {
    ids.add(obj.getId());
  }
  return ids;
}

Ok, let`s add the necessary rights for the old events then:

public void update(Talos talos, Repository repo) {
  if (super.isUpdateNeeded(talos)) {
    super.update(talos, repo);
  }
  if (!talos.allPermissions().contains("add event")) {
    talos.createSimplePermissions("add event");
  }
  List<String> names = fetchUserKeys(repo);
  if (!names.isEmpty()) {
    talos.allSubjects().andObject(
      names.toArray(new String[names.size()]))
      .grant("add event");
  }
  List<Long> objectsIds = fetchEventIds(repo);
  for (Long objectId : objectsIds) {
    ObjectContainer oc = talos.createObject("Object:" + objectId);
    PObject author = repo.load(objectId).get("author");
    oc.andSubject("User:" + author.getId()).grant("modify", "delete");
  }
}

Wiring the TalosCreator

We'll have to add our creator to the ApplicationContext. Open the file /config/ApplicationContext.xml and change the class of the talos creator:

<bean
  class="org.mum.installation.MumTalosCreator"
  id="talosCreator"
  name="TalosCreator"
  singleton="true" />

to look like this:

<bean
  class="org.mumtutorial.installation.TutorialTalosCreator"
  id="talosCreator"
  name="TalosCreator"
  singleton="true" />

Now let's restart the application and secure our event management actions!

Please send us comments, questions, criticism:

Please send us comments, questions, criticism!