Permissions in OutSystems — Part 1 — Go granular or go home!

Filipe Morais
Noesis Low-Code Solutions
6 min readFeb 5, 2019

Summary

Permissions are a core feature of most applications and OutSystems offers a very powerful and expandable Access Control subsystem out of the box. However, this system is greatly misused and what could have been great applications are crippled by unnecessarily lacking permission systems.

From my observations, on most OutSystems applications each role refers to a function, such as “Project Manager”, which from here on I will refer to as “functional roles”. However, on most big commercial b2c applications permissions are granular, i.e., each role provides access to an atomic operation such as “creating a customer” or “editing a customer”, which I will refer to from here on as “granular roles”.

On this first article I will try to support my argument that granular roles are better, I will describe how to implement them on a basic level, and on the following articles I will dive deeper into roles and permissions and finish on how to do granular access control in OutSystems by going beyond roles and using variables such as the user’s nationality and current location for access control.

Why go granular?

Granular permissions are scalable

If you are using functional roles and you want to add a new role, you will need to browse for and change EVERY INSTANCE of the code where that role would interact with the app. And you will then need to publish the app and then push it upstream to test -> pre-prod -> prod. The cost of this change is enormous, the risk is high and bugs WILL be created (see below).

Using functional roles, each role check is a train(wreck) of if conditions that must be individually modified and maintained

With granular permissions, you just add a new group and associate roles. Just that: no publishing, no testing cycles, no new bugs, no developer overhead: negligible to no cost.

Using granular roles, role checks are atomic and easy to maintain

This alone should be reason enough to use granular permissions: functional roles will cost your project THOUSANDS if a new role is needed.

Granular permissions are easier to test and maintain

With functional roles, the developers and testers will have to constantly monitor a list of what each functional role can and cannot do and test it for regression every time a page is modified. Implementation is confusing, if conditions are long, the logic is complicated.

With granular permissions you need only ONE if per functionality (eg: Display the button “Create” if create permission checks out). The logic is straightforward and both easy to implement and test (you test each permission individually instead of the functional role as a whole).

Granular permissions are more secure

With granular permissions there is less to think about, test and consider: either the user has the role or not. This simplicity has one big advantage that reflects in a better overall security: less bugs.

Granular permissions promote loose coupling

With granular permissions you may create your roles directly on your End-User eSpaces (as it should be) and you don’t need to republish anything because you have a new permission. Many implementations with the permissions on the core-services level end up requiring full republications because dependencies are broken each time a new role is added.

Granular permissions do everything functional roles do and do it better

In conclusion, that’s the gist of it: there are no tradeoffs and granular permissions are the better and saner choice. For your own sake: go granular or go home.

How to go granular?

Step 1: Identify your roles

So what roles should you create? As few as possible, as many as you need!

You should create a role for every action or group of actions that would fit under a common authorization pattern. What this means in practice is that, eg, if there are no specific Viewing/Editing permissions for a customer screen then it may be enough to have a Customer_Page role. If however, there are different people with different levels of authorization for viewing and editing, you will then need, at least, both a View_Customer and an Edit_Customer role.

And of course, if you have different people who can modify the customer in different ways, you can and should create roles to control those actions, such as, “Edit_Customer_IdDocument” or “Edit_Customer_BankAccounts”.

We can virtually give any group any level of access as long as we subdivide the user actions correctly

Now we can authorize any user or group to edit the customer in a number of different ways. This would be impossible with functional roles.

Step 2: Create your roles on the End-User modules

Roles and permissions are completely independent and agnostic of the backend. This is called “access control”, emphasis on “access”, and should be verified on access, not in a random core service module after the request already went through 4 or 5 actions.

Roles should exist on the espace they are used on and only under special circumstances referenced by consumer espaces, i.e. if and only if the roles are declared on an UI Core Service. The reason for this is to increase simplicity and maintainability. We don’t want to republish 10 espaces each time we add a role and we don’t want to be playing “Sherlock Holmes and the lost roleCheck” all the time.

Step 3: Create your groups

You can also use the default CRUD actions to create groups, users and roles, but bear in mind that the actions from the module “Users” do important validations!

To create your groups you just need to use the actions on the Users module to quickly wrap up a bootstrap on-publish timer that populates the system with *those* groups the customer asked for in the requirements. Then you can use the users module or build your own application customized group management page.

Step 4: Add roles to groups

Aggregate that filters for all roles on a specific application

And here again, just use the users for your MVP and create a custom page further ahead.

To build your custom page, you will need to use the system tables. On the example, you can see a query that lists roles filtered by application. Filtering by application is important when working on a factory with more than one application being served.

Step 5: Validate!

If you are doing it right, you should be having single expression role checks wrapping your functionalities and pages. Remember to add these roles to the web-screen role configuration and leverage on the built-in access control.

Some situations are not obvious and there are patterns you can apply to solve common permission problems, such as the “View_All” and “View” roles to distinguish between users who are able to view everything and users who are able to view only a limited set of results. We will be discussing those patterns on the next article.

Stay tuned!

If you are interested in learning more about granular permissions, stay in tune for the next article on granular permissions patterns, integrating with the menu, special cases and last but not least: real attribute based access control in OutSystems, i.e. how to seamlessly control user access using virtually any attribute from any table or available data source.

--

--