Roles and Permissions

In the complex realm of application security, roles and permissions play a foundational role. While seemingly straightforward, their effective implementation can often be shrouded in confusion. This article aims to shed light on this critical duo, exploring common patterns surrounding user, roles, and permissions. Through practical insights and clear explanations, we’ll unveil the secrets of constructing a robust authorization model – a vital piece of the security puzzle safeguarding your applications.

Users

The concept of a user is an Authentication (AuthN) term that refers to a natural person or service principal inside of a system. As a user is core to AuthN, their purpose is to answer the “Who” questions, for example, a user represents who they are.

Permission

The concept of a permissions belongs to Authorisation (AuthZ), the purpose of a permissions is to authorise an action. The most basic permissions set is

  • Create : Permits the requestor to add new content and resources
  • Read : Permits the requestor to view content and resource
  • Update : Permits the requestor to modify existing content and resources
  • Delete : Permits the requestor to removing content and resources

Role

The concept of a Role is to define a function, for example Sales Manager or Sales Assistant, In enterprise systems arole often maps to a job role. I would not recommend creating Roles for smaller sets of actions, for example Order Modifier ideally you want to minimise the number of roles in a system, the average user should only require one role. Permissions are usually granted to roles and then Users are assigned to those roles this becomes very useful when a person join or leaves a team, instead of needing a large list of permissions that are required by the user to perform their role, the user can be added or removed from roles as required, just as if additional responsibilities are assigned to all of the Sales Assistants, then the permissions can be granted to the Role instead of each individual user.

Implementation

Trying to stay pure in these areas is very important.

A common anti-pattern would be as follows:

if(User.IsInRole("Admin"))
{
    //Allow Action
}
else
{
    //Block action
}

While this could be interpreted as the admin role has permissions to perform action, this will distribute the AuthZ concerns through the codebase, whilst reducing the ability to easily ascertain the permissions assigned to each role has, and cause issues in the future when permission changes are required.

Instead consider the following

var usersPermissions = PermissionsService.GetPermissionsForRoles(User.Roles);
if(usersPermissions.Contains("Orders::Update"))
{
    //Allow users to update the order
}
else
{
    //Block user from updating order
}

The above uses a PermissionsService that aggregates all of the permissions for a user’s roles, this is a far simpler to audit and has the added benefit of removing the need to search through the codebase for all places roles are evaluated when a new role is added.

Roles in Azure

I felt it was worth mentioning the azure implementation of roles as it is one that I’ve seen that I quite like.

The following is the build in Role definition for the Azure Service Bus Data Receiver role in Azure

{
    "id": "/providers/Microsoft.Authorization/roleDefinitions/4f6d3b9b-027b-4f4c-9142-0e5a2a2247e0",
    "properties": {
        "roleName": "Azure Service Bus Data Receiver",
        "description": "Allows for receive access to Azure Service Bus resources.",
        "assignableScopes": [
            "/"
        ],
        "permissions": [
            {
                "actions": [
                    "Microsoft.ServiceBus/*/queues/read",
                    "Microsoft.ServiceBus/*/topics/read",
                    "Microsoft.ServiceBus/*/topics/subscriptions/read"
                ],
                "notActions": [],
                "dataActions": [
                    "Microsoft.ServiceBus/*/receive/action"
                ],
                "notDataActions": []
            }
        ]
    }
}

In Azure there are 2 Types of Permissions, Actions and DataActions both of which have a Not variant which will negate any actions that are in the allow list. I am a fan of this approach as it is generally very clear what each permissions uses and allows for wildcards to reduce the overheard in the assignment of permissions, for instance, a contributor role generally has access to everything under the namespace, if a new permission as added, the role already would automatically inherit it. For more information on Azure Role Definitions Click Here