Authorization and Access Control
Access control is a fundamental aspect of system security, ensuring that users can only access resources and perform actions they are authorized for. In the context of Shesha, access control is implemented through a combination of Role-Based Access Control (RBAC) and Scoped RBAC. These mechanisms allow administrators to define roles, assign permissions, and enforce security policies based on user roles and their associated scopes.
Core Concepts
Shesha's access control framework is built around a few key concepts that form the foundation of how users, roles, and permissions interact. Understanding these concepts is essential for effective access control management:
- Users → Individual accounts representing system actors (people or integrations). For example, an employee logging into the HR system or a backend integration account for an external service.
- Persons →
Person
is one of the standard entities provided out-of-box with Shesha to store and manage the most common data found in enterprise applications. It represents individuals in the system, whether or not they are linked to aUser
. EachUser
is associated with aPerson
entity which provides additional information about the user, such as their name, contact details, and other personal attributes. This association is useful for scenarios where a user needs to log in and interact with the system. However, aPerson
can exist independently of aUser
, such as in cases where the individual does not need to log into the system. This separation between security-related concerns and user-related information provides flexibility in representing entities like clients who do not require login access. - Roles → Named sets of permissions that define what a user can do. For example, a "Manager" role might have approval rights, while a "Viewer" role has read-only access.
- Permissions → Granular controls over specific features or actions. For example,
Account-View
orAccount-Update
permissions assigned to roles. - Role Type - Defines the scope and context in which roles are applicable, allowing for more granular control over permissions and access levels within the system.
Roles
Shesha implements a Role-Based Access Control (RBAC) security model to manage user access and permissions within the system. This model allows Configurators to define roles with specific permissions, which can then be assigned to users. By doing so, users can only perform actions that are permitted by their assigned roles.
Standard Roles
A new Shesha application starts with a set of standard roles for managing basic user access. The standard roles are designed to cover common use cases and provide a foundation for access control.
Role | Description | Permissions Assigned |
---|---|---|
User | Role assigned to most users, providing access to standard application features such as viewing and updating business data as well as viewing and updating their own profile information. | ViewProfile, UpdateProfile, ViewData |
Administrator | Provides access to administrative functions, including user management, role assignment, viewing of audit trails, and managing basic system settings. | ManageUsers, AssignRoles, ViewAuditTrail |
Configurator | Provides access to the Configuration Studio allowing the user to configure the system, including creating and managing forms, lists, and other configuration settings. | ConfigureSystem, ManageForms, ManageLists |
The user management interface allows administrators to assign roles to users. A user may be assigned one or more roles, which collectively determine their permissions within the system.
Creating Roles
New roles can be created to meet specific organizational needs entirely through the Configuration Studio where new roles can be created, existing ones can be modified, or deleted as necessary.
TODO: Include GuideFlow that shows how to create and manage roles in the Configuration Studio
Entity Scoped Roles
Entity Scoped Roles extend traditional roles by introducing a scope tied to a specific entity, enabling more granular control over user permissions. When assigning a scoped role to a user, the scope is defined by a particular entity, limiting the permissions granted to the user within that context. For example:
- A Departmental System Administrator can manage user accounts only within their assigned department, while a Global Administrator can manage user accounts across the entire system.
- A Project Manager can create and update tasks, but only within projects they are assigned to as Project Manager, while a Global Project Manager can manage tasks across all projects.
Whether a Role is scoped or not depends on entirely on its Role Type. Roles which are not scoped (including all the default roles) use the 'Standard Role' type.
By default, Shesha comes with 'Organization Specific' and 'Account Specific' role types. As the names suggest, these role types allow roles to be assigned and scoped to specific organizations or accounts.
New Role Types can also be configured to scope roles by any other type of entity. Additionally, they allow you to specify and configure the form and validations to apply on assignment of any role of that type. You can create new Role Types through the Configuration Studio, as demonstrated below.
TODO: Insert Guideflow showing process of creating a new Role Type configuration
Permissions
Permissions represent the specific actions that can be performed within the system. For example, a permission might allow a user to view, create, update, or delete an entity such as a user profile or a work order. A Permission can be assigned to one or more Roles, which are in turn assigned to Users. Users will thereby inherit all the Permissions assigned to the assigned Roles allowing for fine-grained control over what users can do.
Creating Permissions
To create a new permission, follow these steps:
TODO: Include GuideFlow that shows how to create and manage permissions in the Configuration Studio
Once a permission is created, it must be integrated into the application's behavior. This involves configuring the application to validate the permission before granting access to specific data or actions. By doing so, the application ensures that only users with the appropriate permissions can perform certain operations, thereby maintaining security and compliance.
The sections later in this document detail the steps for integrating permissions into application behavior at the UI, API, and data levels.
Permission Naming Conventions
Ultimately permission names can be anything as long as they are unique within a module. However, it is recommended to follow a consistent naming convention to ensure clarity and maintainability.
We suggest the following naming convention {Name of thing to secure}-{Action name}
. For example:
User-View
User-Create
User-Update
User-Delete
User-ResetPassword
User-Suspend
Naming of Scoped Permissions
When defining permissions that are scoped to specific entities or conditions, it is important to use clear and descriptive names that indicate the scope of the permission. This helps in understanding the context in which the permission applies and ensures that permissions are easily identifiable.
The following conventions are recommended:
- Use the
-if-{condition}
suffix to indicate that the permission is scoped by a condition. For example:- A Ticketing system has a
Support Agent
role defined - The
Support Agent
role is assignedTicket-View-if-Assigned
permission, whilst theTicket
entity has anAssignedAgent
property indicating the agent assigned to the ticket - Sam has been assigned the
Support Agent
role and has been set as theAssignedAgent
for Tickets 1 and 2 - Sam can view details of Tickets 1 and 2, but not any other tickets
- A Ticketing system has a
- Use the
-where-Scoped
suffix to indicate that the permission is scoped to the entities specified directly on role assignment. For example:- A CRM system has
Account Manager
role defined which requires anAccount
to be specified on assignment - The
Account Manager
role is assignedAccount-View-where-Scoped
permission - John is assigned
Account Manager
roles for Account A and Account B - John can view details of Account A and Account B, but not any other accounts
- Note: The key difference between
-if-{condition}
and-where-Scoped
is that the former is based on a condition (e.g. assigned to a ticket), while the latter is based on the assignment of a role scoped to the entity itself.
- A CRM system has
- Use the
-where-Scoped-to-{entity name}
suffix to indicate that the permission is scoped to entities through its relationship to another type of entity. For example:- A CRM system has
Regional Sales Manager
role defined which requires aRegion
to be specified on assignment - The
Regional Sales Manager
role is assignedAccount-View-where-Scoped-to-Region
permission - Jane is assigned
Regional Sales Manager
role for Region X - Jane can view details of all accounts within Region X, but not any other accounts
- A CRM system has
Permission Granularity
To simplify permission management, it is not always necessary to create separate permissions for every single action on an object. For example, if users who can create other users should also be able to update, delete, reset passwords, and suspend them, these actions can be combined into a single User-Manage
permission. This approach results in two broader permissions:
User-View
User-Manage
This allows roles to be defined with either read-only access or full user management capabilities. The level of granularity for permissions should be determined by whether specific rights need to be assigned independently.
UI-Level Access Control
On the frontend, security is enforced by controlling the visibility of UI elements (such as menu items, forms, buttons and other components) based on the user's permissions, ensuring users only see options that they are authorized to use.
Hiding UI elements does not prevent users from accessing the underlying functionality through APIs or direct URL access. Therefore, it is crucial to also secure the APIs and data access as described in the other sections.
Restricting Access to Forms
To restrict access to specific forms based on user permissions, you can configure the security settings of the form in the Configuration Studio. This allows you to specify which permissions are required for a user to access a particular form.
TODO: Include GuideFlow that shows how to configure permissions required to access the forms
Show/Hide Menu Items Based on Permissions
To restrict access to certain views from the main menu based on the user's permissions, you can configure the visibility of menu items in the Configuration Studio. This allows you to specify which permissions are required for a user to access a particular view.
TODO: Include GuideFlow that shows how to configure menu item visibility based on permissions
Hide/Disable Form Components Based on Permissions
To restrict the visibility of or access to form components based on a user's permissions you can configure the security settings of the component directly in the Configuration Studio.
TODO: Include GuideFlow that shows how to configure IsVisible and IsEditable security settings (not currently implemented)
Complex Scenarios with Business Logic
In some cases, you may need to implement custom visibility logic for UI components based on more complex conditions. For example, you might want to show a button only if the user has a specific permission and is assigned to a work order.
To achieve this, you can use a Js
configuration on the Hidden property of the component and implement the logic in JavaScript as illustrated below.
TODO: The snippet below is based on the existing 'getHidden' method. Moving forward we want to replace this with IsVisible. Snippet should be updated accordingly when the change has been made
const getHidden = () => {
return (() => {
// Check if the user has the permission to perform the action
const canActionIfAssigned = await user.hasPermissionAsync("WorkOrder-Action-if-Assigned");
if(canActionIfAssigned && data.assignedTo === application.user.personId){
return false; // Show the button if the user has the permission and is assigned
} else {
return true; // Hide the button otherwise
}
})();
};
API-Level Access Control
To enforce security at the API level, you can use a combination of configuration and attributes to restrict access to specific API endpoints based on user permissions. This ensures that only authorized users can perform certain actions or access sensitive data. If a user attempts to access an API endpoint without the required permissions, they will receive a 403 Forbidden error, with a message indicating that they do not have the necessary permissions to perform the action.
Securing APIs through Configuration
Shesha allows you to limit access to APIs based on user permissions through the Configuration Studio. This is done by specifying which permissions are required to access a particular API endpoint.
TODO: Include GuideFlow that show how to configure API security in the configuration environment
Securing APIs with Attributes
To secure APIs programmatically, you can use the [ShaAuthorize]
attribute in your AppService methods. This attribute allows you to specify which permissions are required for a user to access the method.
[ShaAuthorize("WorkOrder-Action")]
[HttpPost, Route("[action]")]
public async Task<CompleteWorkOrderResponse> CompleteWorkOrder(CompleteWorkOrderRequest input)
{
// Logic to complete the work order ...
}
In this example, the CompleteWorkOrder
method is secured with the WorkOrder-Action
permission. Only users with this permission will be able to access this API endpoint.