mirror of
https://github.com/ansible/awx.git
synced 2026-01-15 03:40:42 -03:30
Merge branch 'devel' of github.com:ansible/ansible-tower into explicit-implicit-parents
This commit is contained in:
commit
6039ad92e9
@ -1204,7 +1204,7 @@ class LabelAccess(BaseAccess):
|
||||
def can_read(self, obj):
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
return obj.organization and obj.organization.accessible_by(self.user, {'read': True})
|
||||
return obj.organization.accessible_by(self.user, {'read': True})
|
||||
|
||||
def can_add(self, data):
|
||||
if self.user.is_superuser:
|
||||
@ -1224,7 +1224,7 @@ class LabelAccess(BaseAccess):
|
||||
if self.can_add(data) is False:
|
||||
return False
|
||||
|
||||
return obj.organization and obj.organization.accessible_by(self.user, ALL_PERMISSIONS)
|
||||
return obj.organization.accessible_by(self.user, ALL_PERMISSIONS)
|
||||
|
||||
def can_delete(self, obj):
|
||||
return self.can_change(obj, None)
|
||||
|
||||
19
awx/main/migrations/0015_v300_label_changes.py
Normal file
19
awx/main/migrations/0015_v300_label_changes.py
Normal file
@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('main', '0014_v300_invsource_cred'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='label',
|
||||
name='organization',
|
||||
field=models.ForeignKey(related_name='labels', to='main.Organization', help_text='Organization this label belongs to.'),
|
||||
),
|
||||
]
|
||||
@ -24,11 +24,8 @@ class Label(CommonModelNameNotUnique):
|
||||
organization = models.ForeignKey(
|
||||
'Organization',
|
||||
related_name='labels',
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
help_text=_('Organization this label belongs to.'),
|
||||
on_delete=models.SET_NULL,
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
|
||||
def get_absolute_url(self):
|
||||
|
||||
@ -15,6 +15,7 @@ def test_custom_inv_script_access(organization, user):
|
||||
|
||||
custom_inv = CustomInventoryScript.objects.create(name='test', script='test', description='test')
|
||||
custom_inv.organization = organization
|
||||
custom_inv.save()
|
||||
assert not custom_inv.accessible_by(u, {'read':True})
|
||||
|
||||
organization.member_role.members.add(u)
|
||||
|
||||
47
docs/rbac.md
47
docs/rbac.md
@ -5,12 +5,11 @@ The intended audience of this document is the Ansible Tower developer.
|
||||
|
||||
## Overview
|
||||
|
||||
### Role Based Access Control System Basics
|
||||
### RBAC - System Basics
|
||||
|
||||
With Role Based Access Control Systems there are four main concepts to be
|
||||
familiar with, Roles, Resources, Users, and Permissions. Users can be members
|
||||
of a role, which gives them access to any permissions bestowed upon that Role.
|
||||
In order to access a Resource, a Permission must be granted to a Role enabling
|
||||
There are four main concepts to be familiar with, Roles, Resources, Users, and Permissions.
|
||||
Users can be members of a role, which gives them access to any permissions bestowed upon
|
||||
that Role. In order to access a Resource, a Permission must be granted to a Role enabling
|
||||
all members of that Role to access the Resource.
|
||||
|
||||
For example, if I have an organization named "MyCompany" and I want to allow
|
||||
@ -38,7 +37,7 @@ intuitive.)
|
||||
### Implementation Overview
|
||||
|
||||
The RBAC system allows you to create and layer roles for controlling access to resources. Any Django Model can
|
||||
be made into a `Resource` in the RBAC system by using the `ResourceMixin`. Once a model is accessible as a resource you can
|
||||
be made into a resource in the RBAC system by using the `ResourceMixin`. Once a model is accessible as a resource you can
|
||||
extend the model definition to have specific roles using the `ImplicitRoleField`. This role field allows you to
|
||||
configure the name of a role, any parents a role may have, and the permissions this role will grant to members.
|
||||
|
||||
@ -72,34 +71,38 @@ The RBAC system defines a few new models. These models represent the underlying
|
||||
|
||||
`Role` defines a single role within the RBAC implementation. It encapsulates the `ancestors`, `parents`, and `members` for a role. This model is intentionally kept dumb and it has no explicit knowledge of a `Resource`. The `Role` model (get it?), defines some methods that aid in the granting and creation of roles.
|
||||
|
||||
##### `grant(self, resource, permissions)`
|
||||
##### `visible_roles(cls, user)`
|
||||
|
||||
The `grant` instance method takes a resource and a set of permissions (see below) and creates an entry in the `RolePermission` table (described below). The result of this being that any member of this role will now have those permissions to the resource. The `grant` method considers a resource to be anything that is explicitly of type `Resource` or any model that has a `resource` field of type `Resource`.
|
||||
`visible_roles` is a class method that will lookup all of the `Role` instances a user can "see". This includes any roles the user is a direct decendent of as well as any ancestor roles.
|
||||
|
||||
##### `singleton(name)`
|
||||
##### `singleton(cls, name)`
|
||||
|
||||
The `singleton` static method is a helper method on the `Role` model that helps in the creation of singleton roles. It will return the role by name if it already exists or create and return the new role in the case it does not.
|
||||
The `singleton` class method is a helper method on the `Role` model that helps in the creation of singleton roles. It will return the role by name if it already exists or create and return the new role in the case it does not.
|
||||
|
||||
##### `get_absolute_url(self)`
|
||||
|
||||
`get_absolute_url` returns the consumable URL endpoint for the `Role`.
|
||||
|
||||
##### `rebuild_role_ancestor_list(self)`
|
||||
|
||||
`rebuild_role_ancestor_list` will rebuild the current role ancestory that is stored in the `ancestors` field of a `Role`. This is called for you by `save` and different Django signals.
|
||||
|
||||
#### `Resource`
|
||||
##### `is_ancestor_of(self, role)`
|
||||
|
||||
`is_ancestor_of` returns if the given `role` is an ancestor of the current `Role` instance.
|
||||
|
||||
`Resource` is simply a method to associate many different objects (that may share PK/unique names) with a single type. The `Resource` type ensure the objunique with respect to the RBAC implementation. Any Django model can be a resource in the RBAC implementation by adding a `resource` field of type `Resource`, but in most cases it is recommended to use the `ResourceMixin` which handles this for you.
|
||||
|
||||
#### `RolePermission`
|
||||
|
||||
`RolePermission` holds a `role` and a `resource` and the permissions for that unique set. You interact with this model indirectly when declaring `ImplicitRoleField` fields and also when you use the `Role.grant` method. Generally you will not directly use this model unless you are extending the RBAC implementation itself.
|
||||
`RolePermission` holds unique `role_permissions`. You interact with this model indirectly when declaring `ImplicitRoleField` fields. Generally you will not directly use this model unless you are extending the RBAC implementation itself.
|
||||
|
||||
### Fields
|
||||
|
||||
#### `ImplicitRoleField`
|
||||
|
||||
`ImplicitRoleField` fields are declared on your model. They provide the definition of grantable roles for accessing your
|
||||
`Resource`. Configuring the role is done using some keyword arguments that are provided during declaration.
|
||||
`ImplicitRoleField` fields are declared on your model. They provide the definition of grantable roles for accessing your resource. Configuring the role is done using some keyword arguments that are provided during declaration.
|
||||
|
||||
`parent_role` is the link to any parent roles you want considered when a user is requesting access to your `Resource`. A `parent_role` can be declared as a single string, `parent.readonly`, or a list of many roles, `['parentA.readonly', 'parentB.readonly']`. It is important to note that a user does not need a parent role to access a resource if granted the role for that resource explicitly. Also a user will not have access to any parent resources by being granted a role for a child resource. We demonstrate this in the _Usage_ section of this document.
|
||||
`parent_role` is the link to any parent roles you want considered when a user is requesting access to your resource. A `parent_role` can be declared as a single string, `parent.readonly`, or a list of many roles, `['parentA.readonly', 'parentB.readonly']`. It is important to note that a user does not need a parent role to access a resource if granted the role for that resource explicitly. Also a user will not have access to any parent resources by being granted a role for a child resource. We demonstrate this in the _Usage_ section of this document.
|
||||
|
||||
`role_name` is the display name of the role. This is useful when generating reports or looking the results of queries.
|
||||
|
||||
@ -124,19 +127,15 @@ permissions listed below set to `True`. Note that permissions default to
|
||||
{'read':True}
|
||||
```
|
||||
|
||||
#### `ImplicitResourceField`
|
||||
|
||||
The `ImplicitResourceField` is used by the `ResourceMixin` to give your model a `ForeignKey` to a `Resource`. If you use the mixin you will never need to declare this field explicitly for your model.
|
||||
|
||||
### Mixins
|
||||
|
||||
#### `ResourceMixin`
|
||||
|
||||
By mixing in the `ResourceMixin` to your model, you are turning your model in to a `Resource` in the eyes of the RBAC implementation. What this means simply is that your model will now have an `ImplicitResourceField` named resource. Your model will also gain some methods that aid in the checking the access a users roles provides them to a resource.
|
||||
By mixing in the `ResourceMixin` to your model, you are turning your model in to a resource in the eyes of the RBAC implementation. Your model will gain the helper methods that aid in the checking the access a users roles provides them to your resource.
|
||||
|
||||
##### `accessible_objects(cls, user, permissions)`
|
||||
|
||||
`accessible_objects` is a class method to use instead of `Model.objects`. This method will restrict the query of objects to only the objects that a user has the passed in permissions for. This is useful when you want to only filter and display a `Resource` that a users role grants them the `permissions` to. Note that any permission fields that are left blank will default to `False`. `accessible_objects` will only filter out resources where the expected permission was `True` but was returned as `False`.
|
||||
`accessible_objects` is a class method to use instead of `Model.objects`. This method will restrict the query of objects to only the objects that a user has the given permissions for. Note that any permission fields that are left blank will default to `False`. `accessible_objects` will only filter out resources where the expected permission was `True` but was returned as `False`.
|
||||
|
||||
```python
|
||||
objects = Model.accessible_objects(user, {'write':True})
|
||||
@ -156,7 +155,7 @@ By mixing in the `ResourceMixin` to your model, you are turning your model in to
|
||||
|
||||
##### `accessible_by(self, user, permissions)`
|
||||
|
||||
`accessible_by` is an instance method that wraps the `get_permissions` method. Given a user and a dictionary of permissions this method will return True or False if a users roles give them a set of permissions that match the provided permissions dict. Not that any permission fields left blank will default to `False`. `accessible_by` will only return `False` in a case where the passed in permission is expected to be `True` but was returned as `False`.
|
||||
`accessible_by` is an instance method that wraps the `get_permissions` method. Given a user and a dictionary of permissions this method will return `True` or `False` if a users roles give them a set of permissions that match the provided permissions dictionary. Note that any permission fields left blank will default to `False`. `accessible_by` will only return `False` in a case where the passed in permission is expected to be `True` but was returned as `False`.
|
||||
|
||||
```python
|
||||
>>> instance.accessible_by(admin, {'use':True, 'read':True})
|
||||
@ -177,7 +176,7 @@ After exploring the _Overview_ the usage of the RBAC implementation in your code
|
||||
)
|
||||
```
|
||||
|
||||
Now that your model is a `Resource` and has a `Role` defined, you can begin to access the helper methods provided to you by the `ResourceMixin` for checking a users access to your resource. Here is the output of a Python REPL session.
|
||||
Now that your model is a resource and has a `Role` defined, you can begin to access the helper methods provided to you by the `ResourceMixin` for checking a users access to your resource. Here is the output of a Python REPL session.
|
||||
|
||||
```python
|
||||
# we've created some documents and a user
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user