Authorities
Every data store and object in Cloud CMS maintains access control lists so that you can finely describe the rights of any principal in the system against it. This lets you finely tune the rights of individual users against data stores and objects down to a single permission.
This access control is authority-based which means that it's applied by granting authorities (or roles) that a principal has over an object.
Let's buckle down on the terminology for a moment:
- A Permissioned entity is a data store or object that the permissions service knows how to work with. As noted, this includes absolutely everything within Cloud CMS.
- A Principal is the user or person acting upon a Permissioned.
- A Permission is a capability that you can grant to a principal.
- An Authority is a Role that packages together multiple permissions. When you grant a principal an authority over an object or data store, all of the permissions of that authority are in turn granted.
Let's take a look at the list of permissions:
Authority | Permissions | Description |
---|---|---|
connector | CONNECT | Someone who is able to connect to the object or data store. |
consumer | CONNECT READ |
Someone who is able to connect to the object or data store. |
contributor | CONNECT READ CREATE_SUBOBJECTS |
Someone who is able to connect to the object or data store. |
editor | CONNECT READ UPDATE DELETE |
Someone who is able to connect to the object or data store. |
collaborator | CONNECT READ CREATE_SUBOBJECTS UPDATE DELETE |
Someone who is able to connect to the object or data store. |
manager | CONNECT READ CREATE_SUBOBJECTS UPDATE DELETE MODIFY_PERMISSIONS MODIFY_CREDENTIALS |
Someone who is able to connect to the object or data store. |
owner | * (all permissions) | Someone who is able to connect to the object or data store. |
impersonator | IMPERSONATE | Someone who is able to impersonate another user. |
Group Inheritance of Authorities
Cloud CMS supports group-based inheritance of authorities.
If you grant an authority to a Domain Group, all principal members of that Domain Group will also be granted that authority. This is the concept of "group inheritance". It makes it so that you don't have to go to every single member of the group, one by one, and grant the authority.
This is just one of the many benefits of groups.
A good way to think about this is to imagine a sales team with, say, five people on it. You might create a group called "Sales" and then add all five sales people as members of the team. You might also have a folder called "Sales Documents" which you want only the sales people to be able to collaborate upon.
Simple. All you have to do is grant the "Sales" group the "collaborator" authority to the folder. By the magic of group inheritance, all of the sales people on the "Sales" team will also be collaborators.
Container-based Propagation of Authorities
Cloud CMS supports container-based propagation of authorities.
This applies most directly in the case of Repositories. Within a Repository, you can create folders. Folders are a like folders on your desktop. They are directories inside of which you put your content.
If you grant a user the "collaborator" authority over a folder, he'll automatically receive "collaborator" authorities over the things contained inside that folder. This is because folders are "containers". Cloud CMS automatically propagates the rights of the user over the container as rights over the children.
Getting more into the details, what actually happens is that folders have associations of type a:child
with their contained nodes. This association type has a feature on it called f:propagates-authority
which indicates that this association should bestow its granted authorities to the target of the association.
You can disable this propagation by disabling the feature on the node. Or, you can model your own association types and take advantage of propagation as you see fit.
The folder scenario provided above works out-of-the-box but you're free to model content as you require.
Some Terminology
It's worth taking a moment to point out some terminology with respect to group inheritance and container-based propagation.
Terminology | Description |
---|---|
direct | Describes a grant that was made directly to a Permissioned. |
indirect | Describes a grant that was understood to be made against a Permissioned as a result of group-based inheritance. |
inherited | Describes a grant that is direct but which was created as a result of container-based propagation. Inherited grants cannot be revoked directly. They can only be revoked by revoking the original grant. |
Indirect and inherited authority grants will appear as you interrogate the access control set up of objects. They are flagged accordingly. Inherited grants contain references to their origination (i.e. the location of the original direct grant).
List Authorities
You can request a list direct authorities that a given principal has against an object or data store.
// suppose we have a domain
var domain = ...;
// and suppose we have a user ID
var userId = "<domainId>/<principalId>";
// find all of the authorities that the user has over the domain
domain.listAuthorities(userId, function(authorities) {
for (var i = 0; i < authorities.length; i++) {
console.log("The user has authority with role key: " + authorities[i]);
}
});
// This could print out:
//
// The user has authority with role key: MANAGER
// The user has authority with role key: CONSUMER
// The user has authority with role key: CONNECTOR
//
Check Authority
You can check whether a principal has been granted a given authority over a data store or an object by making a simple call over to the server to ask.
This method checks both the direct and indirect authorities. It is a fully evaluative check and is intended to answer the runtime question as to whether a user has a given authority.
It does not answer the question of whether the user was directly granted the authority over the data store or object.
Here is an example that checks whether a user has the "consumer" role over a domain.
// suppose we have a domain
var domain = ...;
// and suppose we have a user
var user = ...;
// check whether this user has the "consumer" role against this domain
domain.checkAuthority(user, "consumer", function(check) {
if (check) {
console.log ("The user has the consumer role");
}
});
// we can also look up by a domain qualified principal id
// this is of the format "domainId/principalId"
var principalId = user.getDomainQualifiedId();
// check whether this user has the "consumer" role against this domain
domain.checkAuthority(principalId, "consumer", function(check) {
if (check) {
console.log ("The user has the consumer role");
}
});
Grant Authority
You can grant a direct authority to other principals over a data store or object.
// assume we have a vault
var vault = ...;
// assume we have a user
var user = ...;
// give the user the "collaborator" role against the vault
vault.grantAuthority(user, "collaborator");
Bear in mind that you can only do this if you are authenticated to Cloud CMS as a user who has the MODIFY_PERMISSIONS
permission against the data store or object.
Revoke Authority
You can revoke a direct authority from other principals over a data store or object.
// assume we have a vault
var vault = ...;
// assume we have a user
var user = ...;
// take away from the user the "collaborator" role against the vault
vault.revokeAuthority(user, "collaborator");
Bear in mind that you can only do this if you are authenticated to Cloud CMS as a user who has the MODIFY_PERMISSIONS
permission against the data store or object.
Revoke All Authorities
If you want to completely revoke any direct authorities that a user might have been granted to an object, there is a shortcut method you can use.
// assume we have a vault
var vault = ...;
// assume we have a user
var user = ...;
// take away all of the roles that a user has against the vault
vault.revokeAllAuthorities(user);
Bear in mind that you can only do this if you are authenticated to Cloud CMS as a user who has the MODIFY_PERMISSIONS
permission against the data store or object.
In addition, one must consider that a user might receive the granted authority in multiple ways. They might have been granted it directly. But they may also belong to a group that has been granted it. In this case, if you revoke the direct authority, the user will still have the grant since they get it from the group.
Access Control List
At various times you may want to consult the full access control list (ACL) for a data store or an object. The access control list shows exactly which principals have been directly granted which authorities.
It's worth repeating. This only shows direct grants. If you want a fully evaluative list of authority grants, see the section below on Authority Grants.
Here is an example that retrieves the access control list for a node in the master branch of a repository. It then prints out the ACL to console.
// assume we have a repository
var repository = ...;
// assume we know what node we're interested in
var nodeId = ...;
// read the node
// load the acl for the node
// print out the full ACL
repository.master().readNode(nodeId).loadACL(function(acl) {
for (var i = 0; i < acl.rows.length; i++)
{
var row = acl.rows[i];
var domainId = row["domainId"];
var principalId = row["_doc"];
var principalName = row["name"];
var principalType = row["type"];
var authorities = row["authorities"];
for (var j = 0; j < authorities.length; j++)
{
console.log ("The principal [id=" + principalId + ", domainId=" + domainId + ", name=" + principalName + ", type=" + principalType + "] has authority: " + authorities[j]);
}
}
});
Full Authority Grants
In many applications, when rendering a page, you need to make a front-end decision about what rights one or more users has to elements being rendered. A good example of this is when you need to figure out what state to render buttons (i.e. active, disabled, hidden).
Cloud CMS lets you bulk all of these checks into a single "authority grant" request. You pass in the users that you're interested in and Cloud CMS hands back a list of every authority granted for those users.
This method also provides a fully evaluative list of all authorities for the set of users. This includes direct and indirect authority grants. And, as you would expect, among the direct authority grants are any inherited grants from container-based propagation.
Here is an example that displays the list of fully evaluative authority grants for a repository.
// assume we have a repository
var repository = ...;
// assume some users that we're interested in
var billy = ...;
var bob = ...;
var thorton = ...;
// a list of the user's domain qualified ids
var userIds = [billy.getDomainQualifiedId(), bob.getDomainQualifiedId(), thorton.getDomainQualifiedId()];
// get the report
this.loadAuthorityGrants(userIds, function(allGrants) {
report(allGrants, billy.getDomainQualifiedId());
report(allGrants, bob.getDomainQualifiedId());
report(allGrants, thorton.getDomainQualifiedId());
});
var report = function(allGrants, principalId) {
console.log("Reporting grants for principal: " + principalId);
for (var grantId in allGrants[principalId]) {
var grant = allGrants[principalId][grantId];
// the "role key" of the authority (i.e. consumer, collaborator)
var grantRoleKey = grant["role-key"];
// the id of the principal who was granted the right
var grantPrincipalId = grant["principal"];
// the id of the object that was granted against (i.e. repo id)
var grantPermissionedId = grant["permissioned"];
// NOTE: if the grant was made directly, then grantPrincipalId == userId1
// otherwise, grantPrincipalId == the id of the domain group that was granted the authority
// and to which the principal we're interested in belongs
var direct = (grantPrincipalId == principalId);
// if the grant was "propagated" via containment, the "inheritsFrom" field tell sus
var inheritsFrom = grant["inheritsFrom"];
//
// REPORT
//
if (inheritsFrom) {
// the id of the grant being masked
// this is usually the original association id that our propagated association is masking
var originalGrantId = inheritsFrom["id"];
// the id of the original principal
// this should be the same as userId1
var originalPrincipalId = inheritsFrom["principal"];
// the id of the original permissioned
// this may be something like the folder that our document sits inside of
var originalPermissionedId = inheritsFrom["permissioned"];
console.log("Inherited Grant, role: " + grantRoleKey + ", permissioned: " + grantPermissionedId + ", original principal: " + originalPrincipalId + ", original permissioned: " + originalPermissionedId);;
} else {
if (direct){
console.log("Direct Grant, role: " + grantRoleKey + ", permissioned: " + grantPermissionedId);
} else {
console.log("Indirect Grant, role: " + grantRoleKey + ", permissioned: " + grantPermissionedId + ", received from: " + grantPrincipalId);
}
}
}
};