loading table of contents...

5.6.1. Example Rights Policy

This example describes the implementation of a rights policy. The aim of the policy is to implement a very simple rights policy that can grant rights to the user who started a process instance. The policy should be usable with very large user sets, in an intranet for instance. To this end, the policy computes the members of a group only when necessary. The policy can be used as a replacement of the default ACLRightsPolicy in the standard simple publication workflow. It is available bundled with its Unified API equivalent in the examples distribution, which also contains the adapted workflow definition example-publication.xml. To try the example workflow, deploy the cap-plugin.jar from the examples in the lib directories of the Workflow Server and all clients you want to use, for example in the Site Manager.

The new class OnlyOwnerWfRightsPolicy will be serializable by means of the interface WfRightsPolicy. One field holds the optional id of the group that is granted create rights and one field denotes whether a group was actually set.

public class OnlyOwnerWfRightsPolicy implements WfRightsPolicy {
  private static final long 
  serialVersionUID = 7389049258655067247L;
  private int groupId;
  private boolean groupIdSet = false;

The standard callback for setting the set of rights is unused: the policy grants or denies all rights

public void setRights(String[] rights) {}

Some methods for managing the policy configuration are needed.

public void setGroupId(int groupId) {
    this.groupId = groupId;
    this.groupIdSet = true;
  }
  public int getGroupId() {
    return groupId;
  }
  public boolean isGroupIdSet() {
    return groupIdSet;
  }
  public void setGroup(String groupAtDomain) throws WfException {
    int pos = groupAtDomain.indexOf('@');
    WfGroup group;
    if (pos < 0) {
      group = WfServer.getDirectoryServiceAdapter().
        getGroup(groupAtDomain, "");
    } else {
      String name = groupAtDomain.substring(0, pos);
      String domain = groupAtDomain.substring(pos+1);
      group = WfServer.getDirectoryServiceAdapter().
        getGroup(name, domain);
    }
    setGroupId(group.getId());
  }

Note that the last method is never actually called from Java code. It is called dynamically during the process definition parsing.

Because the policy grants special access to the owner of a process instance, you can make use of a utility method for determining that user.

private WfUser getOwner(WfInstance instance) throws WfException 
   {
    if (instance instanceof WfTaskInstance) {
      instance = ((WfTaskInstance)instance).getProcessInstance();
    }
    return ((WfProcessInstance)instance).getOwner();
  }

Now you can write the methods from the interface WfRightsPolicy. Some group-related methods are not shown. They are only called in the context of delegation to a group, which is not an appropriate use case for this class.

public boolean hasPermission(WfInstance instance, 
    WfDirectoryServiceAdapter adapter, WfUser user, 
    String rights)
  throws WfException {
    return hasPermission(instance, adapter, user);
  }
  ...
  public boolean hasPermission(WfInstance instance,
    WfDirectoryServiceAdapter adapter, WfUser user, 
    String[] rights)
  throws WfException {
    return hasPermission(instance, adapter, user);
  }
  ...

Now have a look at the central method for permission computation. First of all, you must make sure to grant all rights to the internal server user, which performs certain automated actions. The super administrator also needs all rights.

private boolean hasPermission(WfInstance instance,
    WfDirectoryServiceAdapter adapter, WfUser user)
  throws WfException {
    if (user.isInternalServerUser()) return true;
    if (user.getId() == Id.ADMIN) return true;
    if (instance == null) {

You are being asked for rights on the definition. This can only be a create operation that needs to be checked.

if (!isGroupIdSet()) return false;
      WfGroup group = adapter.getGroup(getGroupId());
      return user.isMember(group);
    } else {

You already checked for the admin and for the internal server user, so that the remaining code is simple.

WfUser owner = getOwner(instance);
      return owner != null && owner.getId() == user.getId();
    }
  }

When computing a worklist, you sometimes need to compute the set of all users. Expensive group operations are only needed in the case of rights on the definition.

public WfUser[] getUsers(WfInstance instance,
    WfDirectoryServiceAdapter adapter, String right) throws 
     WfException {
    if (instance == null) {
      if (isGroupIdSet()) {
        WfGroup group = adapter.getGroup(groupId);
        return group.getUsers();
      } else {
        return new WfUser[0];
      }
    } else {
      WfUser owner = getOwner(instance);
      WfUser admin = adapter.getUser(Id.ADMIN);
      if (owner == null || owner.getId() == Id.ADMIN) {
        return new WfUser[]{admin};
      } else {
        return new WfUser[]{admin, owner};
      }
    }
  }
  ...

Finally, you must provide a marshaller for transferring the rights policy to clients,

public WfRightsPolicyMarshaller getMarshaller() {
    return new OnlyOwnerWfRightsPolicyMarshaller();
  }
}

The marshaller itself is implemented in a separate class. It is identified by its policy id.

public class OnlyOwnerWfRightsPolicyMarshaller
implements WfRightsPolicyMarshaller {
  public String getPolicyID() {
    return "coremedia:///cap/workflow-rights-policy/OnlyOwner";
  }

The main methods affect the marshalling an unmarshalling of the policy group parameter, which has to be encoded as an array of bytes.

public byte[] marshal(WfRightsPolicy policy) {
    OnlyOwnerWfRightsPolicy onlyOwner =
      (OnlyOwnerWfRightsPolicy) policy;
    int groupId = onlyOwner.getGroupId();
    return new byte[] {
      (byte)(groupId), (byte)(groupId>>8),
      (byte)(groupId>>16), (byte)(groupId>>24),
      (byte)(onlyOwner.isGroupIdSet() ? 1 : 0)
    };
  }
  public WfRightsPolicy unmarshal(byte[] data) {
    OnlyOwnerWfRightsPolicy result = new OnlyOwnerWfRightsPolicy();
    if (data[4] == 1) {
      result.setGroupId((data[0] & 0x000000ff) +
        (data[1]<<8 & 0x0000ff00) +
        (data[2]<<16 & 0x00ff0000) +
        (data[3]<<24));
    }
    return result;
  }
}

This policy has also been implemented using the Unified API. For details see the Unified API Developer Manual.