Directory security

Flower directory implementations may provide user authentication and authorization to restrict access to the directory entries. This may be required if you wish to run multiple systems with different security domains on a single Flower instance. In this case you will need to securely separate the systems from each other. Flower roles and access control lists allow to do that.

Note: the default in-memory directory implementation doesn't support security; the SQL server implementation does.

Roles

You should know the following about Flower roles:
  • The roles are directory entries under '/Roles' path.
  • Role name is a path after '/Roles'. For example, default role 'Application' corresponds to '/Roles/Application'.
  • Each role has a list of associated user account. An account is identified by the user's domain qualified name.
  • A user may have multiple roles.
  • The roles may be nested. The nesting relationship is the parent-child relationship of the corresponding directory entries. Depth of the nesting is unlimited.
  • If something is permitted to a parent role, it is permitted to its children, grandchildren etc.
  • If something is permitted to a child, it is permitted to its parent, grandparent etc.
  • Permissions of the siblings are independent.

Access control lists

Each directory entry has an access control list (ACL) which is a set of entries associating a role with permissions. Each permission allows some action to the corresponding role. So, for an entry with an empty ACL any action will be denied for all. However, there is a special role 'Administrator' that has all permissions for all entries regardless of their ACL.

There are following permissions:
  • Read - allows to see an entry. If one have no permission to read an entry, the directory behaves as if the entry doesn't exist.
  • Write - allows to update and delete an entry.
  • Create Children - allows to create child entries of an entry (both by inserting or moving to).

There are the following default roles:
  • Application - all external applications should have this role.
  • Processor - the role of all processors.
  • Administrator - the role having all permissions. It should be used by the directory administrators only.

Separating two systems from each other

To be separated by security boundaries, systems must access the directory under different application accounts and their processes must be executed by different processors with different accounts as well.

First, create roles for the applications and processors.

createOrUpdateRole({
    name: 'Application/MyApp1',
    users: [ 'domain\\MyApp1User' ]
});

createOrUpdateRole({
    name: 'Application/MyApp2',
    users: [ 'domain\\MyApp2User' ]
});

createOrUpdateRole({
    name: 'Processor/MyApp1',
    users: [ 'domain\\MyApp1ProcessorUser' ]
});

createOrUpdateRole({
    name: 'Processor/MyApp2',
    users: [ 'domain\\MyApp2ProcessorUser' ]
});


You can add/remove users of an existing role by using 'addUsersToRole' and 'removeUsersFromRole' functions.

addUsersToRole('Application/MyApp1', [ 'domain\\MyApp1User1', 'domain\\MyApp1User2' ] );
removeUsersFromRole('Application', [ 'domain\\MyApp1User1', 'domain\\MyApp1User2' ] );


Create two processors.

createOrUpdateProcessor({
    name: 'MyApp1Processor',
    role: 'Processor/MyApp1',
    allowSchedulingTo: [ 'Processor/MyApp1', 'Application/MyApp1' ]
});

createOrUpdateProcessor({
    name: 'MyApp2Processor',
    role: 'Processor/MyApp2',
    allowSchedulingTo: [ 'Processor/MyApp1', 'Application/MyApp2' ]
});


Here 'role' is the role of the processor, 'allowSchedulingTo' is the roles which are allowed to assign processes to this processor. If 'role' and 'allowSchedulingTo' are not specified, by default the processor will be assumed to have the role 'Processor' and the scheduling will be allowed to 'Application' and 'Processor'.

In this case you don't have to specify preferred processors to control scheduling. As long as an application is not permitted to schedule a process to a processor, it has no read permission on that processor hence behaves as if the processor doesn't exist.

If you wish to change permissions of a processor that already exists, use the following call:

changeProcessorPermissions({
    name: 'MyApp2Processor',
    role: 'Processor/MyApp2',
    allowSchedulingTo: [ 'Processor/MyApp1', 'Application/MyApp2' ]
});


This call overwrites the corresponding ACLs, so if you don't specify some of the existing permissions, they will be revoked.

Make sure the corresponding processor service is running as 'domain\MyApp1ProcessorUser' and 'domain\MyApp2ProcessorUser'.

Finally, grant read permissions for the workflows to the application roles (if they were not already granted by default via AllowStartTo attribute, see "Workflow permissions"). It is convenient if workflows of different applications are deployed to different namespaces. Suppose, in our case each application deploys its workflows to '/Workflows/<app. name>'.

var workflows = $dir.find('/Workflows/MyApp1/**', DET_WORKFLOW);
var i;

for (i = 0; i < workflows.length; i++) {
    workflows[i].acl = {
        { role: 'Application/MyApp1', permission: READ }
    };
    
    $dir.save(null, workflows[i]);
}

workflows = $dir.find('/Workflows/MyApp2/**', DET_WORKFLOW);

for (i = 0; i < workflows.length; i++) {
    workflows[i].acl = {
        { role: 'Application/MyApp2', permission: READ }
    };
    
    $dir.save(null, workflows[i]);
}

Managing sets permissions

While local sets with their permissions are managed by workflow authors (see "Workflow permissions"), the directory administrators are responsible for managing shared sets. As sets are represented by single directory entries, access to them can be granted and revoked with two general ACL management functions 'grant' and 'revoke'.

First, you need to create a shared set.

createOrUpdateSet({
    at: '/Sets/Shared/MySet',
    messageType: 'MyMessageType, MyAssembly'
});


Then, call 'grant' to grant permissions.

grant({
    permission: READ | CREATE_CHILDREN,
    on: '/Sets/Shared/MySet',
    to: [ 'Application', 'Processor' ]
});


To revoke a permission, call 'revoke'.

revoke({
    permission: CREATE_CHILDREN,
    on: '/Sets/Shared/MySet',
    from: [ 'Processor' ]
});


To allow a role to read messages in a set, grant READ permission to the set; to allow to put and remove the messages, grant CREATE_CHILDREN. This, however, will be enough only for empty sets. If a set already contain messages, you need to grant READ permission on each particular message and subset (folder) to read; to put, grant CREATE_CHILDREN on each subset and, to remove the messages, grant WRITE on each message.

Last edited Apr 19, 2013 at 6:32 PM by dbratus, version 2

Comments

No comments yet.