Role-based access control
Introduction
Waldur authorization system determines what user can do. It consists of permissions and roles. Permission is unique string designating action to be executed. Role is named set of permissions. This functionality is implemented in waldur_core.permissions
application.
First thing to remember is to use PermissionEnum
to define permissions instead of using plain string or standalone named constant, otherwise they would not be pushed to frontend.
1 2 3 4 5 |
|
Next, let's assign that permissions to role.
1 2 3 4 5 6 |
|
Now, let's assign customer owner role to particular user and customer:
1 2 3 4 5 6 7 8 |
|
Finally, we can check whether user is allowed to create offering in particular organization.
1 2 3 4 |
|
Please note that this function accepts not only customer, but also project and offering as a scope. Consider these models as authorization aggregates. Other models, such as resources and orders, should refer to these aggregates to perform authorization check. For example:
1 |
|
Migration example
Previously we have relied on hard-coded roles, such as customer owner and project manager. Migration to dynamic roles on backend is relatively straightforward process. Consider the following example.
1 2 |
|
As you may see, we have relied on selectors with hard-coded roles. The main drawback of this approach is that it is very hard to inspect who can do what without reading all source code. And it is even hard to adjust this behaviour. Contrary to its name, by using dynamic roles we don't need to care much about roles though.
1 2 3 4 5 6 7 |
|
Here we use permission_factory
function which accepts permission string and list of paths to scopes, either customer, project or offering. It returns function which accepts request and raises an exception if user doesn't have specified permission in roles connected to current user and one of these scopes.
Permissions for viewing
Usually it is implemented filter backend, such as GenericRoleFilter
, which in turn uses get_connected_customers
and get_connected_projects
function because customer and project are two main permission aggregates.
1 2 3 4 5 6 |
|
Although this approach works fine for trivial use cases, often enough permission filtering logic is more involved and we implement get_queryset
method instead.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Permissions for object creation and update
Usually it is done in serializer's validate method.
1 2 3 4 5 6 7 8 9 10 |
|