Overview

This module creates a REST API to assign new roles to identities and to query the roles already assigned on Fedora objects.

In roles-based access control users or groups are not granted specific actions on resources; rather, users and groups have roles assigned to them on resources, and these roles are mapped onto permitted actions elsewhere. This makes it much easier to manage permissions globally: rarely will masses of objects need to be updated if their permissions change. Only the role-to-permission mapping will be updated. Role-based access control is a common pattern in security, providing extensible role-specific behavior while retaining straightforward management.

This module does not defined any specific roles or enforce permissions granted to roles. For roles to be effective, this module must be configured alongside a Policy Enforcement Point (PEP) that is aware of roles. Two roles-aware PEPs are provided as reference implementations, the Basic Roles-Based PEP and the XACML PEP.

 

Roles names are custom. The module does not define the set of role names that may be assigned in Fedora. If you choose to configure a set of supported roles, then the roles assigned via this API will be validated.

This module assigns one or more roles to a string, which represents a security principal, i.e. any class that implements java.security.Principal. Roles are serialized and matched against the principal name, a string property of the principal. All the principals used in your repository environment must have unique names. Other than that, you may use whatever principals you wish. This module does not validate principal names.

 

Example data

root/  (default content roles, i.e. no roles for anyone)
├── object A  (EVERYONE => reader; johndoe => admin)
│   ├── datastream 1  (johndoe => admin)
│   └── object Q  (EVERYONE => reader; johndoe => admin)
│       └── object R (janedee => admin)    
├── object B  (EVERYONE => reader; johndoe => admin)
│   └── object T
│       └── object V
└── object C 

Order of operation:

Examples:

  1. Unauthenticated user requests to see Object A.
    1. The user is assigned the user principal "EVERYONE".
    2. The PEP intercepts the request, gets the ACLs for object A:  "EVERYONE" => "reader" and "johndoe" => "admin".
    3. The PEP compares the user principal "EVERYONE" to the principals in object A's ACLs, and sees that "EVERYONE" matches.  The effective role for this request is "reader", the role paired with the principal "EVERYONE" on the object.
    4. The PEP sees if the role "reader" can view the object;  it can.
    5. The PEP returns "yes", and the request proceeds.
  2. Unauthenticated user requests to see datastream 1 on Object A.
    1. The user is assigned the user principal "EVERYONE".
    2. The PEP intercepts the request, gets the ACLs for datastream 1: "johndoe" => "admin".
    3. The PEP compares the user principal "EVERYONE" to the principals in datastream 1's ACLs, but does not find a match.
    4. The PEP returns "no", and the request is denied.
  3. Unauthenticated user requests to delete Object B.
    1. The user is assigned the user principal "EVERYONE".
    2. The PEP intercepts the request, gets the ACLs for object B:  "EVERYONE" => "reader" and "johndoe" => "admin".
    3. The PEP compares the principal "EVERYONE" to the principals in object B's ACLs, and sees that "EVERYONE" matches.  The effective role for this request is "reader", the role paired with the principal "EVERYONE" on the object.
    4. The PEP sees if the role "reader" can delete the object;  it cannot.
    5. The PEP returns "no", and the request is denied.
  4. John Doe requests to update datastream 1 on Object A.
    1. The user is assigned the user principals "johndoe" and "EVERYONE".
    2. The PEP intercepts the request, gets the ACLs for datastream 1:  "johndoe" => "admin".
    3. The PEP compares the user principals "johndoe" and "EVERYONE" to the principals in datastreams's ACLs, and sees that "johndoe" matches.  The effective role for this request is "admin", the role paired with the principal "johndoe" on the object.
    4. The PEP sees if the role "admin" can update the object;  it can.
    5. The PEP returns "yes", and the request proceeds.

Inheritance

Descendent nodes inherit the content ACLs of ancestor nodes only if they have no ACLs themselves.  If a node has content ACLs, the node ACLs override ALL ancestor ACLs.

The following examples, based on the graph shown above, demonstrate how inheritance plays out.

  1. Datastream 1 of object A only allows one principal to access the node:  johndoe.  He will have admin privileges.  None of the ACLs on object A will be applied; the datastream will not inherit the EVERYONE => reader ACL on object A.
  2. Object R, a child of object Q, has its own content ACL:  janedee has admin privileges on object R.  No one else has any access to the node, not even the parent node (object Q) principals (EVERYONE and johndoe).
  3. Object T, a child of object B, has no content ACLs.  So it inherits the ACLs of its most immediate ancestor with content ACLs:  object B.  EVERYONE has reader privileges on object T, and johndoe has admin privileges on the object.
  4. Object V also inherits the ACLs of object B (its most immediate ancestor with content ACLs).
  5. Object C has no content ACL;  it inherits the ACLs of the root node, which is to say, nothing.  No one other than fedoraAdmin has any access to this object.

Deletions

When deleting a node, the user must have an effective role that will allow them to delete ALL the descendant objects under the node (datastreams and child objects).  If any descendant node cannot be deleted, then the entire delete transaction will be denied.

For example, in the graph shown above, the principal johndoe cannot delete object A, although he has an admin role on it and its datastream;  that is because he does not have an effective role on object R, the node's grandchild, that will permit him to delete it.  If he wants to delete object A, he will first have to ask janedee to delete object R.