Permissions are the core security functionality offered by Authress. They represent the most granular aspect. In extreme cases, permissions will directly reflect the API resource endpoints of a service application. For simplicity, the example used here will not be as granular, and we've adjusted the example to only understand a few actions allowed.
In this article, we'll be diving into the permissions for the Document Repository. The Document Repository is an example product application that can be found in the Authress Implementation examples. To sum it up there are a number of different user roles to handle the different user stories, and specific permissions are associated with each of those roles. Usually one
Role corresponds to one
User Persona. And each of those roles have any number of granular permissions that can be scoped to resources.
For the document repository, the user stories tell us that we'll at least need:
- Three types of users, Admin who can do anything, Editors which can create, read, update documents, and Users which can only read documents.
- Editors should be able to assign any user the User role.
- Editors should not be able to assign users the Editor role.
Allow, Grant, Delegate
In simple cases, users take actions in the Document Repository with regard to documents. The simple case is a user interacts only with documents that they create. However, what happens when a user wants to share a document with another user or an external entity? We could directly assign permissions to the user instead of using a role, however as your permissions and role management becomes more complex, a flat permissions list becomes problematic. A simple example is, separating the ability to perform and action, and the ability to grant others the ability to perform the action. In Authress, we separate these notions. The ability to perform an action is called
Allow, and above
Allow there is
Allowis the permission on the action. If a user has the permission
document:read, then the Authress authorization check will return success. Otherwise it will return forbidden.
Grantinvolves security. Can a user
grantthis permission action to other users? If a user has the
Grantpermission on an action, they'll be able to assign roles to users that contain the
Allowpermission on the same action. However, they cannot grant a role that contains
Grant. That means they cannot give other users this role.
Delegateprovides the level of security access where
Delegateallows users to give their role to other users.
With this pattern Authress providers users the ability to perform an action
Allow-based roles to others (
Delegate their role to others.
Roles contain a list of actions with their associated permission. There can be any number of permissions in a role, and the permissions in a role are scoped. For instance, a role may contain
documents:flat-documents:read. Any of which if applied in an access record to a resource would give
documents:flat-documents:read to the user. For this reason when defining permissions, it's valuable to put the least specific part of the permission scope at the beginning.
read:documents is great if you provide
read:*, however, it's usually better to have
Delegate permissions a user with a role that contains one of these can assign roles to other users. This is done through Access Records.
Roles are orthogonal to resources. The permissions added to roles, don't inherently impact your application or grant any permission, until they are joined with explicit resources. Therefore,
documents:read and just
read may operate the same or differently based upon which roles are added to access records, and which permissions are being checked in an application.
Reviewing the model
With this we can see why the roles look the way they do:
The admin has
star access to perform any action on specified resources. Just because the admin has
Allow: * which resources this applies to are restricted based on the Access Records. The admin also has the access to
Grant any user any permission role. From our list of three roles, this would only be the User role. Just looking at the
Grant permissions for the action
* a user would not be able to grant the Editor role because it also contains a
Grant. However, since the admin role also has
Delegate, an admin can
Delegate additionally the Admin and Editor roles. Additionally, even without the
Grant permission, the admin would be able to also delegate the User role.
The user role has only
Allow: document:read, meaning any check to read a document will be successful, if the user has the role on that document. They can neither give other users the User role nor any other role, since they don't have
The Editor is the most complex based on our example use cases. We know all the permission actions that the role needs, but to handle the additional cases, we need to configure the permission grants. The Editor role to manage documents needs
documents:update. Depending on the changes in an application over time, a single permission
documents:* may be sufficient. Additionally, the Editor role must be allowed to assign the User role, but not the Editor role. In this case since the User role has no
documents:read is all we need. Adding the
documents:udpate is unnecessary because there is no role with those permission actions without
Grant. So having Grant on them doesn't offer any additional value, until those roles exist. Additionally because Editor does not have
Delegate on any permission, it cannot assign any role which contains a
Grant including the Editor role. The only role which can assign the Editor role with the current configuration is the Admin role.
Expanding for many roles
As systems grow more complex use cases can arise. In these situations it makes sense to evaluate which roles should be created and how to optimize.
Mix and match roles
Since multiple roles can be applied for a user on a single resource, occasionally it makes sense to create roles that are independent without overlapping permissions. For example, let's say we wanted to add the resource
audit-trail and the permission
audit-trail:read. We need to answer the question of which roles to add this permission to.
- Since our Admin role already contains
Delegate: *, it is implicitly available there, so no change is necessary.
- If all Editors should also be able to read the
audit-trail, then we can just add
- Do Users need access to the audit trail?
Sometimes adding the new permission to existing roles works best. In other cases, we might think about creating a new role
Auditor, which will only contain the permission
audit-trail:read. This would result in four roles total. So the complexity of the system increases, however, it makes it easy to enable the user's access to audit trails, simply by giving them this additional role, without needing to think about whether to promote them to Editor or Admin.