In the previous article we explore RPS in depth. I will now present an implementation of RPS. RPS has four components. All components are interfaced and two have default implementations.
PermissionService
Permission service is dual purposed:
- Consume the permission configuration.
- Provide a set of permissions when given a resource, a set of roles and a scope.
A default RRSP (resource role scope permission) implementation is provided. RRSP expects a json file tiered by resources, roles, scopes and permissions respectively.
PrincipleRoleService
Provide a set of roles available to a principal when given a scope and a list of respective ScopeIds.
EntityScopeService
Provide a list of scopeIds when given a resourceId and a scope.
PermissionEvaluator
Given a resourceId and a specific permission, determine whether a principal possesses the given permission. The RPSevaluator accomplishes this by using the three above components.
EntityScopeService: ScopeIdFunc(scope, resourceId) = ScopeIds
PrincipleRoleService: RolesFunc(principal, ScopeIds) = Roles
PermissionService: RPfunction(Roles, Scope) = RPs
PermissionEvaluator: RP exists in RPs ?
Example:
Suppose there is a resource `truck` with resourceId `t1`. We want to determine if a user with id `u1` may drive the truck. User `u1` has the `owner` role at the `user` scope.
`truck`: { #resource `owner`: {` #role `user`: #scope [`drive`, `sell`]}}} #permissions
ScopeIdFunc(`truck`,`t1`) = `u1` (user is associated with the truck)
RolesFunc(u1, `user`, `u1` ) = `owner` (u1 is the owner of the truck at the user scope)
RPfunction([`owner`], `user`) = [`drive`, `sell`] (u1 may drive, sell the truck t1)
`drive` exists in [`drive`, `sell`] = true (u1 may indeed drive the truck)
FAQ
What’s the meaning of global scope?
Global when referring to a RP it means the role may perform the said permission against all resourceIds of the given resource. When referring to the scope of a role it means all roles.
How do I define custom scopes?
Handle the scope in your implementation of `EntityScopeService` and `PrincipalRoleService`. Bind the scopes to the container. `authorization.test.ts` has a complete implementation of this.
May I use my own `PermissionService`?
Yes. Simply provide your own implementation and inject into the service.
For a principal, how do I represent a role that’s associated with multiple scopes?
Make sure the role is associated with the applicable scopes and scopeIds.
How do I allow one user access resources belonging to another user, another group?
- Define a new scope. For the targeted resources, add the assessor userIds. Give the assessor users the necessary permissions at the new scope. The same logic can be applied for organizations, teams etc.
- Share the resource. For the targeted resources, add the assessor userIds.
Well that’s it. You may find an implement of RPS in Typescript on Github and NPM. A in-depth example is provided in the test folder. Feel free to post any questions or concerns.