Permissions¶
The permissions system provides a way to assign permissions to specific users and groups of users.
The model driving this data is provided by django.contrib.auth.models.Permission
. Each
Permission
has a name, describing it and can be associated with one or more users or groups.
Two types of permissions exist: Model-Level and Object-Level.
- Model-Level
A permission that is associated with a specific model, but not an instance of that model. This allows you to express concepts like “Hilde can modify all FileRemotes”.
- Object-Level
A permission that is associated with a specific instance of a specific model. This allows you to express concepts like “Hilde can modify FileRemote(name=’foo remote’).
Model-Level Permissions¶
By default, each model receives four permissions:
The “add” permission limits the user’s ability to view the “add” form and add an object.
The “change” permission limits a user’s ability to view the change list, view the “change” form and change an object.
The “delete” permission limits the ability to delete an object.
The “view” permission limits the ability to view an object.
The Model-level permissions are created automatically by Django, and receive a name like:
<app_name>_<action>_<model_name>
. For example to change file remote the permission is named
file.change_fileremote
. You can view the Permissions on a system via the Django ORM with:
Permission.objects.all()
. See the Django Permissions Docs for more information on working with
permissions.
Here’s an example of the Permissions automatically created for the FileRemote
model:
file.add_fileremote
file.view_fileremote
file.change_fileremote
file.delete_fileremote
Object-Level Permissions¶
Object-level permissions are provided by django-guardian which is a dependency of Pulp and enabled by default. This extends the normal Django
calls has_perm(perm, obj=None) has_perms(perm_list, obj=None to give
meaning to the obj
portion of the call which Django otherwise would ignore.
Django-guardian has great docs on what it provides for interacting with object-level permissions:
Defining Custom Permissions¶
Any model can define a custom permission, and Django will automatically make a migration to add it for you. See the Django Custom Permissions Documentation for more information on how to do that.
Custom Permission for Repository Content Modification¶
The Repository subclass is one place where it’s recommended to create a custom permission that
manages the ability to modify RepositoryVersions underneath a Repository. While the add, create,
view, and delete default permissions apply to the Repository itself, this new custom permission
is intended to be required for any operations that produce RepositoryVersions, e.g. sync
,
modify
, or upload
.
Here’s an example of adding a permission like this for FileRepository
:
class FileRepository(Repository):
...
class Meta:
...
permissions = (
('modify_repo_content', 'Modify Repository Content'),
)
Note
It is not necessary to “namespace” this modify_repo_content
permission because by including
it in the meta class of your Detail view, it will already be namespaced on the correct object.
Permission Checking Machinery¶
drf-access-policy provides a feature to enable conditional checks to be globalls available as their
docs describe here. Pulp
enables the reusable_conditions
in its settings.py file, allowing a variety of condition
checks to be globally available. Pulp enables this as follows:
DRF_ACCESS_POLICY = {"reusable_conditions": "pulpcore.app.global_access_conditions"}
The pulpcore.app.global_access_conditions
provides the following checks that are available for
both users and plugin writers to use in their policies:
-
pulpcore.app.global_access_conditions.
has_model_or_obj_perms
(request, view, action, permission)¶ Checks if the current user has either model-level or object-level permissions.
The object in this case is the one the action is operating on, e.g. the URL
/pulp/api/v3/tasks/15939b47-6b6d-4613-a441-939ca4ba6e63/
is operating on the Task object withpk=15939b47-6b6d-4613-a441-939ca4ba6e63
.This is usable as a conditional check in an AccessPolicy. Here is an example checking for “file.view_fileremote” permission at either the model-level or object-level.
{ ... "condition": "has_model_or_obj_perms:file.view_fileremote", }
- Parameters
request (rest_framework.request.Request) – The request being made.
view (subclass rest_framework.viewsets.GenericViewSet) – The view being checked for authorization.
action (str) – The action being performed, e.g. “destroy”.
permission (str) – The name of the Permission to be checked. In the form app_label.codename, e.g. “core.delete_task”.
- Returns
- True if the user has the Permission named by the
permission
argument at the model-level or on the object being operated on at the object-level. False otherwise.
- True if the user has the Permission named by the
-
pulpcore.app.global_access_conditions.
has_model_perms
(request, view, action, permission)¶ Checks if the current user has a model-level permission.
This is usable as a conditional check in an AccessPolicy. Here is an example checking for “file.add_fileremote” permission at the model-level.
{ ... "condition": "has_model_perms:file.add_fileremote", }
- Parameters
request (rest_framework.request.Request) – The request being made.
view (subclass rest_framework.viewsets.GenericViewSet) – The view being checked for authorization.
action (str) – The action being performed, e.g. “destroy”.
permission (str) – The name of the Permission to be checked. In the form app_label.codename, e.g. “core.delete_task”.
- Returns
- True if the user has the Permission named by the
permission
argument at the model-level. False otherwise.
- True if the user has the Permission named by the
-
pulpcore.app.global_access_conditions.
has_obj_perms
(request, view, action, permission)¶ Checks if the current user has object-level permission on the specific object.
The object in this case is the one the action is operating on, e.g. the URL
/pulp/api/v3/tasks/15939b47-6b6d-4613-a441-939ca4ba6e63/
is operating on the Task object withpk=15939b47-6b6d-4613-a441-939ca4ba6e63
.This is usable as a conditional check in an AccessPolicy. Here is an example checking for the “file.view_fileremote” permissions at the object-level.
{ ... "condition": "has_obj_perms:file.view_fileremote", }
- Parameters
request (rest_framework.request.Request) – The request being made.
view (subclass rest_framework.viewsets.GenericViewSet) – The view being checked for authorization.
action (str) – The action being performed, e.g. “destroy”.
permission (str) – The name of the Permission to be checked. In the form app_label.codename, e.g. “core.delete_task”.
- Returns
- True if the user has the Permission named by the
permission
argument on the object being operated on at the object-level. False otherwise.
- True if the user has the Permission named by the
-
pulpcore.app.global_access_conditions.
has_remote_param_model_or_obj_perms
(request, view, action, permission)¶ Checks if the current user has either model-level or object-level permissions on the
remote
.The object in this case is the one specified by the
remote
parameter. For example when syncing theremote
parameter is passed in as an argument.This is usable as a conditional check in an AccessPolicy. Here is an example checking for “file.view_fileremote” permission at either the model-level or object-level.
{ ... "condition": "has_remote_param_model_or_obj_perms:file.view_fileremote", }
Since it is checking a
remote
object the permission argument should be one of the following:“file.change_fileremote” - Permission to change the
FileRemote
.“file.view_fileremote” - Permission to view the
FileRemote
.“file.delete_fileremote” - Permission to delete the
FileRemote
.
- Parameters
request (rest_framework.request.Request) – The request being made.
view (subclass rest_framework.viewsets.GenericViewSet) – The view being checked for authorization.
action (str) – The action being performed, e.g. “destroy”.
permission (str) – The name of the Permission to be checked. In the form app_label.codename, e.g. “core.delete_task”.
- Returns
- True if the user has the Permission named by the
permission
at the model-level or on the argument on the
remote
parameter at the object-level. False otherwise.
- True if the user has the Permission named by the
-
pulpcore.app.global_access_conditions.
has_remote_param_obj_perms
(request, view, action, permission)¶ Checks if the current user has object-level permission on the
remote
object.The object in this case is the one specified by the
remote
parameter. For example when syncing theremote
parameter is passed in as an argument.This is usable as a conditional check in an AccessPolicy. Here is an example checking for the “file.view_fileremote” permissions at the object-level.
{ ... "condition": "has_remote_param_obj_perms:file.view_fileremote", }
Since it is checking a
remote
object the permission argument should be one of the following:“file.change_fileremote” - Permission to change the
FileRemote
.“file.view_fileremote” - Permission to view the
FileRemote
.“file.delete_fileremote” - Permission to delete the
FileRemote
.
- Parameters
request (rest_framework.request.Request) – The request being made.
view (subclass rest_framework.viewsets.GenericViewSet) – The view being checked for authorization.
action (str) – The action being performed, e.g. “destroy”.
permission (str) – The name of the Permission to be checked. In the form app_label.codename, e.g. “core.delete_task”.
- Returns
- True if the user has the Permission named by the
permission
argument on theremote
parameter at the object-level. False otherwise.
- True if the user has the Permission named by the