Skip to content

Commit

Permalink
Prevent assigning credential to user of other org (#15296)
Browse files Browse the repository at this point in the history
Utilizes the `validate_role_assignment` callback
from dab (see dab PR #490) to prevent granting credential
access to a user of another organization.

This logic will work for role_user_assignments
and role_team_assignments endpoints.

Signed-off-by: Seth Foster <fosterbseth@gmail.com>
  • Loading branch information
fosterseth authored Jul 2, 2024
1 parent c4688d6 commit 94e5795
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 0 deletions.
14 changes: 14 additions & 0 deletions awx/main/models/credential/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
from django.utils.encoding import force_str
from django.utils.functional import cached_property
from django.utils.timezone import now
from django.contrib.auth.models import User

# DRF
from rest_framework.serializers import ValidationError as DRFValidationError

# AWX
from awx.api.versioning import reverse
Expand All @@ -41,6 +45,7 @@
ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,
ROLE_SINGLETON_SYSTEM_AUDITOR,
)
from awx.main.models import Team, Organization
from awx.main.utils import encrypt_field
from . import injectors as builtin_injectors

Expand Down Expand Up @@ -315,6 +320,15 @@ def _get_dynamic_input(self, field_name):
else:
raise ValueError('{} is not a dynamic input field'.format(field_name))

def validate_role_assignment(self, actor, role_definition):
if isinstance(actor, User):
if actor.is_superuser or Organization.access_qs(actor, 'change').filter(id=self.organization.id).exists():
return
if isinstance(actor, Team):
if actor.organization == self.organization:
return
raise DRFValidationError({'detail': _(f"You cannot grant credential access to a {actor._meta.object_name} not in the credentials' organization")})


class CredentialType(CommonModelNameNotUnique):
"""
Expand Down
22 changes: 22 additions & 0 deletions awx/main/tests/functional/dab_rbac/test_dab_rbac_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,28 @@ def test_workflow_creation_permissions(setup_managed_roles, organization, workfl
assert access.can_add({'name': 'foo-flow', 'organization': organization.pk})


@pytest.mark.django_db
def test_assign_credential_to_user_of_another_org(setup_managed_roles, credential, admin_user, rando, org_admin, organization, post):
'''Test that a credential can only be assigned to a user in the same organization'''
# cannot assign credential to rando, as rando is not in the same org as the credential
rd = RoleDefinition.objects.get(name="Credential Admin")
credential.organization = organization
credential.save(update_fields=['organization'])
assert credential.organization not in Organization.access_qs(rando, 'change')
url = django_reverse('roleuserassignment-list')
resp = post(url=url, data={"user": rando.id, "role_definition": rd.id, "object_id": credential.id}, user=admin_user, expect=400)
assert "You cannot grant credential access to a User not in the credentials' organization" in str(resp.data)

# can assign credential to superuser
rando.is_superuser = True
rando.save()
post(url=url, data={"user": rando.id, "role_definition": rd.id, "object_id": credential.id}, user=admin_user, expect=201)

# can assign credential to org_admin
assert credential.organization in Organization.access_qs(org_admin, 'change')
post(url=url, data={"user": org_admin.id, "role_definition": rd.id, "object_id": credential.id}, user=admin_user, expect=201)


@pytest.mark.django_db
@override_settings(ALLOW_LOCAL_RESOURCE_MANAGEMENT=False)
def test_team_member_role_not_assignable(team, rando, post, admin_user, setup_managed_roles):
Expand Down

0 comments on commit 94e5795

Please sign in to comment.