Modeling matrix resource permissions
There are many different kinds of access control models as detailed in the knowledge base article choosing the best access control strategy. When modeling existing access permissions with Authress, you might need to convert from a legacy authorization schema to a more robust one. Part of the challenge can be figuring out how to resolve some of the more esoteric authorization checks. In this article well review a complicated matrix resource permission, and how to effectively convert it to a simpler and easy to reason about resource based access model.
Backgroundโ
Here we'll use the example where you have:
- multiple geographic locations, where users in each location have access to the office resources in that location
- and multiple verticals, one of these being resource manufacturing, and users in the manufacturing vertical should have access to all manufacturing related resources in every location
You have a legacy app that contains an existing authorization check of the following format:
function HasAccessToManufacturingInOffice(user, office) {
// if user has access to geographic location give access
if (user.hasAccessToLocation(office.location)) {
return true;
}
// if user has access to manufacturing for all locations also give access
if (user.hasAccessToResourceType(Type.Manufacturing)) {
return true;
}
// Otherwise they don't have access
return false;
}
At first glance it might seem it is really complicated to abstract this. Where the result would be easy to reason about and create the necessary Access Records. First we'll review the improved authorization check, and then we'll investigate possible access record configurations.
The authorization checkโ
Everything comes down to checking if a user has access, and with Authress, the authorization check should be as simple as possible. For instance, let's say an engineer comes and in wants to get access to the manufacturing building resource in your platform to do maintenance on a piece of machinery. Let's start by writing that authorization check first. Doing so will remove all the complexity:
import { AuthressClient } from '@authress/sdk';
const authressClient = new AuthressClient({ authressApiUrl: 'https://auth.yourdomain.com' });
function HasAccessToManufacturingInOffice(user, office) {
const hasAccess = await authressClient.userPermissions.authorizeUser(
user.userId,
`offices/${officeId}/buildings/${manufacturing}/machines/${machineId}`,
'Fix-Machine');
return hasAccess;
}
And that's it, really simple. We know that all machines are in manufacturing buildings and buildings are all associated with a particular office. Hierarchies are supported as first-class resources, and the hierarchy used here makes it easy for check permissions for an office, a building in a location, or the machines in those buildings. It also doesn't matter what kind of person you want to do the access check for, it always looks the same. This is how Authress creates intuitive and simple authorization checks.
Creating the user rolesโ
The next step with Authress is identify the users roles that exist. In this case, we have two different kinds of users, let's call them Office Employee
and Manufacturing Engineer
. These are also great names for Authress roles, so we would go and create these two Authress Roles.
Office Employee
- an employee of any location that has access to location based resources, we might include the following permissions in the role:
office:change-name
office:access
office:delete
employee:hire
machine:operate
And
Manufacturing Engineer
- an engineering role for someone who should have access to the resources of a manufacturing office and needs to repair and do maintenance on machines in many different offices
office:access
machine:operate
machine:repair
machine:replace
Assigning permissions using Access Recordsโ
The next step is to actually give users the appropriate permissions by assigning these roles to specific resources in the relevant location. We'll create one access record for the office employees whom have access to location based resources. And we'll create a separate access record for engineers. This is an important separation as the permissions and access statements in the records will be different:
Expanding the case furtherโ
That completes the full access every user in your platform needs. Everyone has the access they should have, and for most cases this is sufficient.
However, your use case may be more complicated and could involve, multiple locations. One complexity here is how to manage the engineers' access, if we want them to be able to access to multiple locations.
Creating additional access records for each location is easy, and you can even create groups of users if you want to assign the same user to multiple places. For simplicity, we'll add multiple locations to one access record:
And in more complex scenarios the wildcard โถ
can be used in multiple places within the ResourceUri to give someone access to specific resources in all offices:
The answer is scalability and management control. When possible it is better to have multiple records, but single records make it easy to manage in one place. If you have many different owners of different aspects of the record, create multiple records. If the users in the record should have different access, create multiple records. Records are free and simplify management, take advantage of this when possible.