1
0
mirror of https://github.com/ansible/awx.git synced 2024-10-27 17:55:10 +03:00

Merge pull request #2634 from wwitzel3/issue-2560

Disallow non-admin of a user to add a user to Roles
This commit is contained in:
Wayne Witzel III 2016-06-27 11:28:38 -04:00 committed by GitHub
commit f0418d8841
21 changed files with 62 additions and 60 deletions

View File

@ -425,7 +425,7 @@ class SubListCreateAttachDetachAPIView(SubListCreateAPIView):
sub = get_object_or_400(self.model, pk=sub_id)
if not request.user.can_access(self.parent_model, 'unattach', parent,
sub, self.relationship):
sub, self.relationship, request.data):
raise PermissionDenied()
if parent_key:

View File

@ -1643,11 +1643,11 @@ class CredentialSerializer(BaseSerializer):
owner_teams = reverse('api:credential_owner_teams_list', args=(obj.pk,)),
))
parents = obj.owner_role.parents.exclude(object_id__isnull=True)
parents = obj.admin_role.parents.exclude(object_id__isnull=True)
if parents.count() > 0:
res.update({parents[0].content_type.name:parents[0].content_object.get_absolute_url()})
elif obj.owner_role.members.count() > 0:
user = obj.owner_role.members.first()
elif obj.admin_role.members.count() > 0:
user = obj.admin_role.members.first()
res.update({'user': reverse('api:user_detail', args=(user.pk,))})
return res
@ -1656,7 +1656,7 @@ class CredentialSerializer(BaseSerializer):
summary_dict = super(CredentialSerializer, self).get_summary_fields(obj)
summary_dict['owners'] = []
for user in obj.owner_role.members.all():
for user in obj.admin_role.members.all():
summary_dict['owners'].append({
'id': user.pk,
'type': 'user',
@ -1665,7 +1665,7 @@ class CredentialSerializer(BaseSerializer):
'url': reverse('api:user_detail', args=(user.pk,)),
})
for parent in obj.owner_role.parents.exclude(object_id__isnull=True).all():
for parent in obj.admin_role.parents.exclude(object_id__isnull=True).all():
summary_dict['owners'].append({
'id': parent.content_object.pk,
'type': camelcase_to_underscore(parent.content_object.__class__.__name__),
@ -1719,9 +1719,9 @@ class CredentialSerializerCreate(CredentialSerializer):
team = validated_data.pop('team', None)
credential = super(CredentialSerializerCreate, self).create(validated_data)
if user:
credential.owner_role.members.add(user)
credential.admin_role.members.add(user)
if team:
credential.owner_role.parents.add(team.member_role)
credential.admin_role.parents.add(team.member_role)
return credential

View File

@ -1332,7 +1332,7 @@ class CredentialOwnerUsersList(SubListAPIView):
model = User
serializer_class = UserSerializer
parent_model = Credential
relationship = 'owner_role.members'
relationship = 'admin_role.members'
new_in_300 = True
@ -1349,7 +1349,7 @@ class CredentialOwnerTeamsList(SubListAPIView):
raise PermissionDenied()
content_type = ContentType.objects.get_for_model(self.model)
teams = [c.content_object.pk for c in credential.owner_role.parents.filter(content_type=content_type)]
teams = [c.content_object.pk for c in credential.admin_role.parents.filter(content_type=content_type)]
return self.model.objects.filter(pk__in=teams)
@ -1382,7 +1382,7 @@ class TeamCredentialsList(SubListCreateAPIView):
self.check_parent_access(team)
visible_creds = Credential.accessible_objects(self.request.user, 'read_role')
team_creds = Credential.objects.filter(owner_role__parents=team.member_role)
team_creds = Credential.objects.filter(admin_role__parents=team.member_role)
return team_creds & visible_creds
@ -1759,7 +1759,7 @@ class GroupChildrenList(SubListCreateAttachDetachAPIView):
sub = get_object_or_400(self.model, pk=sub_id)
if not request.user.can_access(self.parent_model, 'unattach', parent,
sub, self.relationship):
sub, self.relationship, request.data):
raise PermissionDenied()
if sub.parents.exclude(pk=parent.pk).count() == 0:

View File

@ -170,8 +170,8 @@ class BaseAccess(object):
return bool(self.can_change(obj, None) and
self.user.can_access(type(sub_obj), 'read', sub_obj))
def can_unattach(self, obj, sub_obj, relationship):
return self.can_change(obj, None)
def can_unattach(self, obj, sub_obj, relationship, data=None):
return self.can_change(obj, data)
def check_license(self, add_host=False, feature=None, check_expiration=True):
reader = TaskSerializer()
@ -613,7 +613,7 @@ class CredentialAccess(BaseAccess):
if self.user in obj.organization.admin_role:
return True
return self.user in obj.owner_role
return self.user in obj.admin_role
def can_delete(self, obj):
# Unassociated credentials may be marked deleted by anyone, though we
@ -1590,10 +1590,14 @@ class RoleAccess(BaseAccess):
def can_attach(self, obj, sub_obj, relationship, data,
skip_sub_obj_read_check=False):
return self.can_unattach(obj, sub_obj, relationship)
return self.can_unattach(obj, sub_obj, relationship, data, skip_sub_obj_read_check)
@check_superuser
def can_unattach(self, obj, sub_obj, relationship):
def can_unattach(self, obj, sub_obj, relationship, data=None, skip_sub_obj_read_check=False):
if not skip_sub_obj_read_check and relationship in ['members', 'member_role.parents']:
if not check_user_access(self.user, sub_obj.__class__, 'read', sub_obj):
return False
if obj.object_id and \
isinstance(obj.content_object, ResourceMixin) and \
self.user in obj.content_object.admin_role:

View File

@ -33,7 +33,7 @@ class Command(BaseCommand):
c = Credential.objects.create(name='Demo Credential',
username=superuser.username,
created_by=superuser)
c.owner_role.members.add(superuser)
c.admin_role.members.add(superuser)
i = Inventory.objects.create(name='Demo Inventory',
organization=o,
created_by=superuser)

View File

@ -143,18 +143,18 @@ class Migration(migrations.Migration):
),
migrations.AddField(
model_name='credential',
name='owner_role',
name='admin_role',
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'singleton:system_administrator'], to='main.Role', null=b'True'),
),
migrations.AddField(
model_name='credential',
name='use_role',
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'owner_role'], to='main.Role', null=b'True'),
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'admin_role'], to='main.Role', null=b'True'),
),
migrations.AddField(
model_name='credential',
name='read_role',
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'singleton:system_auditor', b'use_role', b'owner_role'], to='main.Role', null=b'True'),
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'singleton:system_auditor', b'organization.auditor_role', b'use_role', b'admin_role'], to='main.Role', null=b'True'),
),
migrations.AddField(
model_name='custominventoryscript',

View File

@ -15,7 +15,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='credential',
name='use_role',
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'organization.admin_role', b'owner_role'], to='main.Role', null=b'True'),
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'organization.admin_role', b'admin_role'], to='main.Role', null=b'True'),
),
migrations.AlterField(
model_name='team',

View File

@ -20,7 +20,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='credential',
name='read_role',
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'singleton:system_auditor', b'use_role', b'owner_role', b'organization.auditor_role'], to='main.Role', null=b'True'),
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'singleton:system_auditor', b'use_role', b'admin_role', b'organization.auditor_role'], to='main.Role', null=b'True'),
),
migrations.RunPython(migration_utils.set_current_apps_for_migrations),
migrations.RunPython(rbac.rebuild_role_hierarchy),

View File

@ -164,7 +164,7 @@ def _discover_credentials(instances, cred, orgfunc):
cred.organization = None
cred.save()
cred.owner_role, cred.use_role = None, None
cred.admin_role, cred.use_role = None, None
for i in orgs[org]:
i.credential = cred
@ -198,11 +198,11 @@ def migrate_credential(apps, schema_editor):
logger.info(smart_text(u"added Credential(name={}, kind={}, host={}) at organization level".format(cred.name, cred.kind, cred.host)))
if cred.deprecated_team is not None:
cred.deprecated_team.member_role.children.add(cred.owner_role)
cred.deprecated_team.member_role.children.add(cred.admin_role)
cred.save()
logger.info(smart_text(u"added Credential(name={}, kind={}, host={}) at user level".format(cred.name, cred.kind, cred.host)))
elif cred.deprecated_user is not None:
cred.owner_role.members.add(cred.deprecated_user)
cred.admin_role.members.add(cred.deprecated_user)
cred.save()
logger.info(smart_text(u"added Credential(name={}, kind={}, host={}) at user level".format(cred.name, cred.kind, cred.host, )))
else:

View File

@ -212,7 +212,7 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique, ResourceMixin):
default='',
help_text=_('Tenant identifier for this credential'),
)
owner_role = ImplicitRoleField(
admin_role = ImplicitRoleField(
parent_role=[
'singleton:' + ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,
],
@ -220,14 +220,14 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique, ResourceMixin):
use_role = ImplicitRoleField(
parent_role=[
'organization.admin_role',
'owner_role',
'admin_role',
]
)
read_role = ImplicitRoleField(parent_role=[
'singleton:' + ROLE_SINGLETON_SYSTEM_AUDITOR,
'organization.auditor_role',
'use_role',
'owner_role',
'admin_role',
])
@property

View File

@ -40,7 +40,6 @@ role_names = {
'auditor_role' : 'Auditor',
'execute_role' : 'Execute',
'member_role' : 'Member',
'owner_role' : 'Owner',
'read_role' : 'Read',
'update_role' : 'Update',
'use_role' : 'Use',
@ -54,7 +53,6 @@ role_descriptions = {
'auditor_role' : 'Can view all settings for the %s',
'execute_role' : 'May run the job template',
'member_role' : 'User is a member of the %s',
'owner_role' : 'Owns and can manage all aspects of this %s',
'read_role' : 'May view settings for the %s',
'update_role' : 'May update project or inventory or group using the configured source update system',
'use_role' : 'Can use the %s in a job template',

View File

@ -387,7 +387,7 @@ class BaseTestMixin(QueueTestMixin, MockCommonlySlowTestMixin):
user = opts['user']
del opts['user']
cred = Credential.objects.create(**opts)
cred.owner_role.members.add(user)
cred.admin_role.members.add(user)
return cred
def setup_instances(self):

View File

@ -159,7 +159,7 @@ def machine_credential():
@pytest.fixture
def org_credential(organization, credential):
credential.owner_role.parents.add(organization.admin_role)
credential.admin_role.parents.add(organization.admin_role)
return credential
@pytest.fixture

View File

@ -16,7 +16,7 @@ def test_credential_migration_user(credential, user, permissions):
rbac.migrate_credential(apps, None)
assert u in credential.owner_role
assert u in credential.admin_role
@pytest.mark.django_db
def test_two_teams_same_cred_name(organization_factory):
@ -28,8 +28,8 @@ def test_two_teams_same_cred_name(organization_factory):
rbac.migrate_credential(apps, None)
assert objects.teams.team1.member_role in cred1.owner_role.parents.all()
assert objects.teams.team2.member_role in cred2.owner_role.parents.all()
assert objects.teams.team1.member_role in cred1.admin_role.parents.all()
assert objects.teams.team2.member_role in cred2.admin_role.parents.all()
@pytest.mark.django_db
def test_credential_use_role(credential, user, permissions):
@ -46,14 +46,14 @@ def test_credential_migration_team_member(credential, team, user, permissions):
# No permissions pre-migration (this happens automatically so we patch this)
team.admin_role.children.remove(credential.owner_role)
team.admin_role.children.remove(credential.admin_role)
team.member_role.children.remove(credential.use_role)
assert u not in credential.owner_role
assert u not in credential.admin_role
rbac.migrate_credential(apps, None)
# Admin permissions post migration
assert u in credential.owner_role
assert u in credential.admin_role
@pytest.mark.django_db
def test_credential_migration_team_admin(credential, team, user, permissions):
@ -104,7 +104,7 @@ def test_credential_access_admin(user, team, credential):
# credential is now part of a team
# that is part of an organization
# that I am an admin for
credential.owner_role.parents.add(team.admin_role)
credential.admin_role.parents.add(team.admin_role)
credential.save()
cred = Credential.objects.create(kind='aws', name='test-cred')

View File

@ -205,9 +205,9 @@ def test_job_template_access_org_admin(jt_objects, rando):
jt_objects.inventory.organization.admin_role.members.add(rando)
# Assign organization permission in the same way the create view does
organization = jt_objects.inventory.organization
jt_objects.credential.owner_role.parents.add(organization.admin_role)
jt_objects.cloud_credential.owner_role.parents.add(organization.admin_role)
jt_objects.network_credential.owner_role.parents.add(organization.admin_role)
jt_objects.credential.admin_role.parents.add(organization.admin_role)
jt_objects.cloud_credential.admin_role.parents.add(organization.admin_role)
jt_objects.network_credential.admin_role.parents.add(organization.admin_role)
proj_pk = jt_objects.project.pk
assert access.can_add(dict(inventory=jt_objects.inventory.pk, project=proj_pk))

View File

@ -269,14 +269,14 @@ class BaseJobTestMixin(BaseTestMixin):
password=TEST_SSH_KEY_DATA,
created_by=self.user_sue,
)
self.cred_sue.owner_role.members.add(self.user_sue)
self.cred_sue.admin_role.members.add(self.user_sue)
self.cred_sue_ask = Credential.objects.create(
username='sue',
password='ASK',
created_by=self.user_sue,
)
self.cred_sue_ask.owner_role.members.add(self.user_sue)
self.cred_sue_ask.admin_role.members.add(self.user_sue)
self.cred_sue_ask_many = Credential.objects.create(
username='sue',
@ -288,7 +288,7 @@ class BaseJobTestMixin(BaseTestMixin):
ssh_key_unlock='ASK',
created_by=self.user_sue,
)
self.cred_sue_ask_many.owner_role.members.add(self.user_sue)
self.cred_sue_ask_many.admin_role.members.add(self.user_sue)
self.cred_bob = Credential.objects.create(
username='bob',
@ -384,7 +384,7 @@ class BaseJobTestMixin(BaseTestMixin):
password='Heading0',
created_by = self.user_sue,
)
self.team_ops_north.member_role.children.add(self.cred_ops_north.owner_role)
self.team_ops_north.member_role.children.add(self.cred_ops_north.admin_role)
self.cred_ops_test = Credential.objects.create(
username='testers',

View File

@ -1434,7 +1434,7 @@ class InventoryUpdatesTest(BaseTransactionTest):
credential = Credential.objects.create(kind='aws',
username=source_username,
password=source_password)
credential.owner_role.members.add(self.super_django_user)
credential.admin_role.members.add(self.super_django_user)
# Set parent group name to one that might be created by the sync.
group = self.group
group.name = 'ec2'
@ -1521,7 +1521,7 @@ class InventoryUpdatesTest(BaseTransactionTest):
username=source_username,
password=source_password,
security_token=source_token)
credential.owner_role.members.add(self.super_django_user)
credential.admin_role.members.add(self.super_django_user)
# Set parent group name to one that might be created by the sync.
group = self.group
group.name = 'ec2'
@ -1543,7 +1543,7 @@ class InventoryUpdatesTest(BaseTransactionTest):
username=source_username,
password=source_password,
security_token="BADTOKEN")
credential.owner_role.members.add(self.super_django_user)
credential.admin_role.members.add(self.super_django_user)
# Set parent group name to one that might be created by the sync.
group = self.group
@ -1578,7 +1578,7 @@ class InventoryUpdatesTest(BaseTransactionTest):
credential = Credential.objects.create(kind='aws',
username=source_username,
password=source_password)
credential.owner_role.members.add(self.super_django_user)
credential.admin_role.members.add(self.super_django_user)
group = self.group
group.name = 'AWS Inventory'
group.save()
@ -1706,7 +1706,7 @@ class InventoryUpdatesTest(BaseTransactionTest):
credential = Credential.objects.create(kind='rax',
username=source_username,
password=source_password)
credential.owner_role.members.add(self.super_django_user)
credential.admin_role.members.add(self.super_django_user)
# Set parent group name to one that might be created by the sync.
group = self.group
group.name = 'DFW'
@ -1759,7 +1759,7 @@ class InventoryUpdatesTest(BaseTransactionTest):
username=source_username,
password=source_password,
host=source_host)
credential.owner_role.members.add(self.super_django_user)
credential.admin_role.members.add(self.super_django_user)
inventory_source = self.update_inventory_source(self.group,
source='vmware', credential=credential)
# Check first without instance_id set (to import by name only).

View File

@ -506,7 +506,7 @@ class ProjectUpdatesTest(BaseTransactionTest):
u = kw['user']
del kw['user']
credential = Credential.objects.create(**kw)
credential.owner_role.members.add(u)
credential.admin_role.members.add(u)
kwargs['credential'] = credential
project = Project.objects.create(**kwargs)
project_path = project.get_project_path(check_if_exists=False)
@ -1418,7 +1418,7 @@ class ProjectUpdatesTest(BaseTransactionTest):
inventory=self.inventory)
self.group.hosts.add(self.host)
self.credential = Credential.objects.create(name='test-creds')
self.credential.owner_role.members.add(self.super_django_user)
self.credential.admin_role.members.add(self.super_django_user)
self.project = self.create_project(
name='my public git project over https',
scm_type='git',
@ -1454,7 +1454,7 @@ class ProjectUpdatesTest(BaseTransactionTest):
inventory=self.inventory)
self.group.hosts.add(self.host)
self.credential = Credential.objects.create(name='test-creds')
self.credential.owner_role.members.add(self.super_django_user)
self.credential.admin_role.members.add(self.super_django_user)
self.project = self.create_project(
name='my private git project over https',
scm_type='git',

View File

@ -62,7 +62,7 @@ class ScheduleTest(BaseTest):
self.organizations[1].member_role.members.add(self.diff_org_user)
self.cloud_source = Credential.objects.create(kind='awx', username='Dummy', password='Dummy')
self.cloud_source.owner_role.members.add(self.super_django_user)
self.cloud_source.admin_role.members.add(self.super_django_user)
self.first_inventory = Inventory.objects.create(name='test_inventory', description='for org 0', organization=self.organizations[0])
self.first_inventory.hosts.create(name='host_1')

View File

@ -283,7 +283,7 @@ class RunJobTest(BaseJobExecutionTest):
user = opts['user']
del opts['user']
self.cloud_credential = Credential.objects.create(**opts)
self.cloud_credential.owner_role.members.add(user)
self.cloud_credential.admin_role.members.add(user)
return self.cloud_credential
def create_test_project(self, playbook_content, role_playbooks=None):

View File

@ -216,7 +216,7 @@ try:
sys.stdout.flush()
credential_id = ids['credential']
credential = Credential.objects.create(name='%s Credential %d User %d' % (prefix, credential_id, user_idx))
credential.owner_role.members.add(user)
credential.admin_role.members.add(user)
credentials.append(credential)
user_idx += 1
print('')
@ -232,7 +232,7 @@ try:
sys.stdout.flush()
credential_id = ids['credential']
credential = Credential.objects.create(name='%s Credential %d team %d' % (prefix, credential_id, team_idx))
credential.owner_role.parents.add(team.member_role)
credential.admin_role.parents.add(team.member_role)
credentials.append(credential)
team_idx += 1
print('')