Exemplo n.º 1
0
    def setUp(self):
        """Set up the access view tests."""
        super().setUp()
        request = self.request_context['request']
        user = User()
        user.username = self.user_data['username']
        user.account = self.customer_data['account_id']
        request.user = user

        self.access_data = {
            'permission':
            'app:*:*',
            'resourceDefinitions': [{
                'attributeFilter': {
                    'key': 'key1',
                    'operation': 'equal',
                    'value': 'value1'
                }
            }]
        }
        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data['username'])
            self.principal.save()
            self.admin_principal = Principal(username="******")
            self.admin_principal.save()
            self.group = Group(name='groupA')
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.save()
Exemplo n.º 2
0
    def setUp(self):
        """Set up the group view nonadmin tests."""
        super().setUp()

        self.user_data = self._create_user_data()
        self.customer = self._create_customer_data()
        self.request_context = self._create_request_context(self.customer,
                                                            self.user_data,
                                                            is_org_admin=False)

        request = self.request_context["request"]
        self.headers = request.META
        self.access_data = {
            "permission":
            "app:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "key1",
                    "operation": "equal",
                    "value": "value1"
                }
            }],
        }
        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data["username"])
            self.principal.save()
            self.admin_principal = Principal(username="******")
            self.admin_principal.save()
            self.group = Group(name="groupA")
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.save()
Exemplo n.º 3
0
    def setUp(self):
        """Set up the access view tests."""
        super().setUp()
        request = self.request_context["request"]
        user = User()
        user.username = self.user_data["username"]
        user.account = self.customer_data["account_id"]
        request.user = user

        self.access_data = {
            "permission":
            "app:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "key1",
                    "operation": "equal",
                    "value": "value1"
                }
            }],
        }
        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data["username"])
            self.principal.save()
            self.admin_principal = Principal(username="******")
            self.admin_principal.save()
            self.group = Group(name="groupA")
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.save()
Exemplo n.º 4
0
    def setUp(self):
        """Set up the group view nonadmin tests."""
        super().setUp()

        self.user_data = self._create_user_data()
        self.customer = self._create_customer_data()
        self.request_context = self._create_request_context(self.customer,
                                                            self.user_data,
                                                            is_org_admin=False)

        request = self.request_context['request']
        self.headers = request.META
        self.access_data = {
            'permission':
            'app:*:*',
            'resourceDefinitions': [{
                'attributeFilter': {
                    'key': 'key1',
                    'operation': 'equal',
                    'value': 'value1'
                }
            }]
        }
        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data['username'])
            self.principal.save()
            self.admin_principal = Principal(username="******")
            self.admin_principal.save()
            self.group = Group(name='groupA')
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.save()
Exemplo n.º 5
0
    def setUp(self):
        """Set up the internal viewset tests."""
        super().setUp()

        self.client = APIClient()
        self.customer = self._create_customer_data()
        self.internal_request_context = self._create_request_context(
            self.customer, self.user_data, create_customer=False, is_internal=True, create_tenant=True
        )

        self.request = self.internal_request_context["request"]
        user = User()
        user.username = self.user_data["username"]
        user.account = self.customer_data["account_id"]
        self.request.user = user

        with tenant_context(self.tenant):
            self.group = Group(name="System Group", system=True)
            self.group.save()
            self.role = Role.objects.create(name="System Role", description="A role for a group.", system=True)
            self.policy = Policy.objects.create(name="System Policy", group=self.group)
            self.policy.roles.add(self.role)
            self.policy.save()
            self.group.policies.add(self.policy)
            self.group.save()
Exemplo n.º 6
0
    def setUp(self):
        """Set up the role viewset tests."""
        super().setUp()
        request = self.request_context['request']
        user = User(username=self.user_data['username'],
                    tenant=self.tenant)
        user.save()
        request.user = user

        sys_role_config = {
            'name': 'system_role',
            'system': True
        }

        def_role_config = {
            'name': 'default_role',
            'platform_default': True
        }

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data['username'])
            self.principal.save()
            self.group = Group(name='groupA')
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.save()

            self.sysRole = Role(**sys_role_config)
            self.sysRole.save()

            self.defRole = Role(**def_role_config)
            self.defRole.save()
Exemplo n.º 7
0
class GroupViewNonAdminTests(IdentityRequest):
    """Test the group view for nonadmin user."""
    def setUp(self):
        """Set up the group view nonadmin tests."""
        super().setUp()

        self.user_data = self._create_user_data()
        self.customer = self._create_customer_data()
        self.request_context = self._create_request_context(self.customer,
                                                            self.user_data,
                                                            is_org_admin=False)

        request = self.request_context["request"]
        self.headers = request.META
        self.access_data = {
            "permission":
            "app:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "key1",
                    "operation": "equal",
                    "value": "value1"
                }
            }],
        }
        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data["username"])
            self.principal.save()
            self.admin_principal = Principal(username="******")
            self.admin_principal.save()
            self.group = Group(name="groupA")
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.save()

    def tearDown(self):
        """Tear down group view tests."""
        with tenant_context(self.tenant):
            Group.objects.all().delete()
            Principal.objects.all().delete()
            Role.objects.all().delete()
            Policy.objects.all().delete()

    def test_nonadmin_RonR_list(self):
        """Test that a nonadmin user can list groups in tenant"""
        url = "{}?application={}".format(reverse("group-list"), "rbac")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_nonadmin_RonR_retrieve(self):
        """Test that a nonadmin user can't retrieve group RBAC resources"""
        url = reverse("group-detail", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
Exemplo n.º 8
0
class GroupViewNonAdminTests(IdentityRequest):
    """Test the group view for nonadmin user."""
    def setUp(self):
        """Set up the group view nonadmin tests."""
        super().setUp()

        self.user_data = self._create_user_data()
        self.customer = self._create_customer_data()
        self.request_context = self._create_request_context(self.customer,
                                                            self.user_data,
                                                            is_org_admin=False)

        request = self.request_context['request']
        self.headers = request.META
        self.access_data = {
            'permission':
            'app:*:*',
            'resourceDefinitions': [{
                'attributeFilter': {
                    'key': 'key1',
                    'operation': 'equal',
                    'value': 'value1'
                }
            }]
        }
        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data['username'])
            self.principal.save()
            self.admin_principal = Principal(username="******")
            self.admin_principal.save()
            self.group = Group(name='groupA')
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.save()

    def tearDown(self):
        """Tear down group view tests."""
        with tenant_context(self.tenant):
            Group.objects.all().delete()
            Principal.objects.all().delete()
            Role.objects.all().delete()
            Policy.objects.all().delete()

    def test_nonadmin_RonR_list(self):
        """Test that a nonadmin user can list groups in tenant"""
        url = '{}?application={}'.format(reverse('group-list'), 'rbac')
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_nonadmin_RonR_retrieve(self):
        """Test that a nonadmin user can't retrieve group RBAC resources"""
        url = reverse('group-detail', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
Exemplo n.º 9
0
    def setUp(self):
        """Set up the role viewset tests."""
        super().setUp()
        request = self.request_context['request']
        user = User(username=self.user_data['username'], tenant=self.tenant)
        user.save()
        request.user = user

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data['username'])
            self.principal.save()
            self.group = Group(name='groupA')
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.save()
Exemplo n.º 10
0
    def setUp(self):
        """Set up the policy viewset tests."""
        super().setUp()
        request = self.request_context["request"]
        user = User()
        user.username = self.user_data["username"]
        user.account = self.customer_data["account_id"]
        request.user = user

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data["username"])
            self.principal.save()
            self.group = Group(name="groupA")
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.save()
Exemplo n.º 11
0
    def setUp(self):
        """Set up the policy viewset tests."""
        super().setUp()
        request = self.request_context["request"]
        user = User()
        user.username = self.user_data["username"]
        user.account = self.customer_data["account_id"]
        request.user = user

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data["username"])
            self.principal.save()
            self.group = Group(name="groupA")
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.save()
            Permission.objects.create(permission="app:*:*")
        with tenant_context(Tenant.objects.get(schema_name="public")):
            Permission.objects.create(permission="app:*:*")
Exemplo n.º 12
0
    def setUp(self):
        """Set up the role viewset tests."""
        super().setUp()
        request = self.request_context['request']
        user = User()
        user.username = self.user_data['username']
        user.account = self.customer_data['account_id']
        request.user = user

        sys_role_config = {'name': 'system_role', 'system': True}

        def_role_config = {'name': 'default_role', 'platform_default': True}

        self.display_fields = {
            'applications', 'description', 'uuid', 'name', 'system', 'created',
            'policyCount', 'accessCount', 'modified', 'platform_default'
        }

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data['username'])
            self.principal.save()
            self.policy = Policy.objects.create(name='policyA')
            self.group = Group(name='groupA', description='groupA description')
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.policies.add(self.policy)
            self.group.save()

            self.sysRole = Role(**sys_role_config)
            self.sysRole.save()

            self.defRole = Role(**def_role_config)
            self.defRole.save()
            self.defRole.save()

            self.policy.roles.add(self.defRole, self.sysRole)
            self.policy.save()

            self.access = Access.objects.create(permission='app:*:*',
                                                role=self.defRole)
Exemplo n.º 13
0
def groups_for_principal(principal, **kwargs):
    """Gathers all groups for a principal, including the default."""
    assigned_group_set = principal.group.all()
    platform_default_group_set = Group.platform_default_set()
    prefetch_lookups = kwargs.get("prefetch_lookups_for_groups")

    if prefetch_lookups:
        assigned_group_set = assigned_group_set.prefetch_related(
            prefetch_lookups)
        platform_default_group_set = platform_default_group_set.prefetch_related(
            prefetch_lookups)

    return set(assigned_group_set | platform_default_group_set)
Exemplo n.º 14
0
    def setUp(self):
        """Set up the group viewset tests."""
        super().setUp()
        request = self.request_context['request']
        user = User()
        user.username = self.user_data['username']
        user.account = self.customer_data['account_id']
        request.user = user
        self.dummy_role_id = uuid4()

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data['username'])
            self.principal.save()
            self.principalB = Principal(username='******')
            self.principalB.save()
            self.principalC = Principal(
                username='******')
            self.principalC.save()
            self.group = Group(name='groupA')
            self.group.save()
            self.role = Role.objects.create(name='roleA',
                                            description='A role for a group.')
            self.policy = Policy.objects.create(name='policyA',
                                                group=self.group)
            self.policy.roles.add(self.role)
            self.policy.save()
            self.group.policies.add(self.policy)
            self.group.principals.add(self.principal, self.principalB)
            self.group.save()

            self.defGroup = Group(name='groupDef',
                                  platform_default=True,
                                  system=True)
            self.defGroup.save()
            self.defGroup.principals.add(self.principal)
            self.defGroup.save()

            self.emptyGroup = Group(name='groupE')
            self.emptyGroup.save()

            self.groupB = Group.objects.create(name='groupB')
            self.groupB.principals.add(self.principal)
            self.policyB = Policy.objects.create(name='policyB',
                                                 group=self.groupB)
            self.roleB = Role.objects.create(name='roleB')
            self.policyB.roles.add(self.roleB)
            self.policyB.save()

            # role that's not assigned to principal
            self.roleOrphan = Role.objects.create(name='roleOrphan')

            # group that associates with multipal roles
            self.groupMultiRole = Group.objects.create(name='groupMultiRole')
            self.policyMultiRole = Policy.objects.create(
                name='policyMultiRole')
            self.policyMultiRole.roles.add(self.role)
            self.policyMultiRole.roles.add(self.roleB)
            self.groupMultiRole.policies.add(self.policyMultiRole)
Exemplo n.º 15
0
    def setUp(self):
        """Set up the group viewset tests."""
        super().setUp()
        request = self.request_context["request"]
        user = User()
        user.username = self.user_data["username"]
        user.account = self.customer_data["account_id"]
        request.user = user
        self.dummy_role_id = uuid4()

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data["username"])
            self.principal.save()
            self.principalB = Principal(username="******")
            self.principalB.save()
            self.principalC = Principal(
                username="******")
            self.principalC.save()
            self.group = Group(name="groupA")
            self.group.save()
            self.role = Role.objects.create(name="roleA",
                                            description="A role for a group.")
            self.policy = Policy.objects.create(name="policyA",
                                                group=self.group)
            self.policy.roles.add(self.role)
            self.policy.save()
            self.group.policies.add(self.policy)
            self.group.principals.add(self.principal, self.principalB)
            self.group.save()

            self.defGroup = Group(name="groupDef",
                                  platform_default=True,
                                  system=True)
            self.defGroup.save()
            self.defGroup.principals.add(self.principal)
            self.defGroup.save()

            self.emptyGroup = Group(name="groupE")
            self.emptyGroup.save()

            self.groupB = Group.objects.create(name="groupB")
            self.groupB.principals.add(self.principal)
            self.policyB = Policy.objects.create(name="policyB",
                                                 group=self.groupB)
            self.roleB = Role.objects.create(name="roleB")
            self.policyB.roles.add(self.roleB)
            self.policyB.save()

            # role that's not assigned to principal
            self.roleOrphan = Role.objects.create(name="roleOrphan")

            # group that associates with multipal roles
            self.groupMultiRole = Group.objects.create(name="groupMultiRole")
            self.policyMultiRole = Policy.objects.create(
                name="policyMultiRole")
            self.policyMultiRole.roles.add(self.role)
            self.policyMultiRole.roles.add(self.roleB)
            self.groupMultiRole.policies.add(self.policyMultiRole)
Exemplo n.º 16
0
    def setUp(self):
        """Set up the group viewset tests."""
        super().setUp()
        request = self.request_context['request']
        user = User(username=self.user_data['username'], tenant=self.tenant)
        user.save()
        request.user = user
        self.dummy_role_id = uuid4()

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data['username'])
            self.principal.save()
            self.group = Group(name='groupA')
            self.group.save()
            self.role = Role.objects.create(name='roleA')
            self.policy = Policy.objects.create(name='policyA',
                                                group=self.group)
            self.policy.roles.add(self.role)
            self.policy.save()
            self.group.policies.add(self.policy)
            self.group.principals.add(self.principal)
            self.group.save()

            self.defGroup = Group(name='groupDef',
                                  platform_default=True,
                                  system=True)
            self.defGroup.save()
            self.defGroup.principals.add(self.principal)
            self.defGroup.save()

            self.groupB = Group.objects.create(name='groupB')
            self.groupB.principals.add(self.principal)
            self.policyB = Policy.objects.create(name='policyB',
                                                 group=self.groupB)
            self.roleB = Role.objects.create(name='roleB')
            self.policyB.roles.add(self.roleB)
            self.policyB.save()
Exemplo n.º 17
0
    def setUp(self):
        """Set up the role viewset tests."""
        super().setUp()
        request = self.request_context["request"]
        user = User()
        user.username = self.user_data["username"]
        user.account = self.customer_data["account_id"]
        request.user = user

        sys_role_config = {
            "name": "system_role",
            "display_name": "system_display",
            "system": True
        }

        def_role_config = {
            "name": "default_role",
            "display_name": "default_display",
            "platform_default": True
        }

        self.display_fields = {
            "applications",
            "description",
            "uuid",
            "name",
            "display_name",
            "system",
            "created",
            "policyCount",
            "accessCount",
            "modified",
            "platform_default",
        }

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data["username"])
            self.principal.save()
            self.policy = Policy.objects.create(name="policyA")
            self.group = Group(name="groupA", description="groupA description")
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.policies.add(self.policy)
            self.group.save()

            self.sysRole = Role(**sys_role_config)
            self.sysRole.save()

            self.defRole = Role(**def_role_config)
            self.defRole.save()
            self.defRole.save()

            self.policy.roles.add(self.defRole, self.sysRole)
            self.policy.save()

            self.permission = Permission.objects.create(permission="app:*:*")
            self.permission2 = Permission.objects.create(permission="app2:*:*")
            self.access = Access.objects.create(permission=self.permission,
                                                role=self.defRole)
            self.access2 = Access.objects.create(permission=self.permission2,
                                                 role=self.defRole)

            self.access3 = Access.objects.create(permission=self.permission2,
                                                 role=self.sysRole)
            Permission.objects.create(permission="cost-management:*:*")

        # Create permission in public schema
        with tenant_context(Tenant.objects.get(schema_name="public")):
            Permission.objects.create(permission="cost-management:*:*")
            Permission.objects.create(permission="app:*:*")
            Permission.objects.create(permission="app2:*:*")
Exemplo n.º 18
0
class RoleViewsetTests(IdentityRequest):
    """Test the role viewset."""
    def setUp(self):
        """Set up the role viewset tests."""
        super().setUp()
        request = self.request_context["request"]
        user = User()
        user.username = self.user_data["username"]
        user.account = self.customer_data["account_id"]
        request.user = user

        sys_role_config = {
            "name": "system_role",
            "display_name": "system_display",
            "system": True
        }

        def_role_config = {
            "name": "default_role",
            "display_name": "default_display",
            "platform_default": True
        }

        self.display_fields = {
            "applications",
            "description",
            "uuid",
            "name",
            "display_name",
            "system",
            "created",
            "policyCount",
            "accessCount",
            "modified",
            "platform_default",
        }

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data["username"])
            self.principal.save()
            self.policy = Policy.objects.create(name="policyA")
            self.group = Group(name="groupA", description="groupA description")
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.policies.add(self.policy)
            self.group.save()

            self.sysRole = Role(**sys_role_config)
            self.sysRole.save()

            self.defRole = Role(**def_role_config)
            self.defRole.save()
            self.defRole.save()

            self.policy.roles.add(self.defRole, self.sysRole)
            self.policy.save()

            self.permission = Permission.objects.create(permission="app:*:*")
            self.permission2 = Permission.objects.create(permission="app2:*:*")
            self.access = Access.objects.create(permission=self.permission,
                                                role=self.defRole)
            self.access2 = Access.objects.create(permission=self.permission2,
                                                 role=self.defRole)

            self.access3 = Access.objects.create(permission=self.permission2,
                                                 role=self.sysRole)
            Permission.objects.create(permission="cost-management:*:*")

        # Create permission in public schema
        with tenant_context(Tenant.objects.get(schema_name="public")):
            Permission.objects.create(permission="cost-management:*:*")
            Permission.objects.create(permission="app:*:*")
            Permission.objects.create(permission="app2:*:*")

    def create_role(self, role_name, role_display="", in_access_data=None):
        """Create a role."""
        access_data = [{
            "permission":
            "app:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "key1",
                    "operation": "equal",
                    "value": "value1"
                }
            }],
        }]
        if in_access_data:
            access_data = in_access_data
        test_data = {
            "name": role_name,
            "display_name": role_display,
            "access": access_data
        }

        # create a role
        client = APIClient()
        response = client.post(URL, test_data, format="json", **self.headers)
        return response

    def test_create_role_success(self):
        """Test that we can create a role."""
        role_name = "roleA"
        access_data = [{
            "permission":
            "app:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "equal",
                    "value": "valueA"
                }
            }],
        }]
        response = self.create_role(role_name, in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # test that we can retrieve the role
        url = reverse("role-detail",
                      kwargs={"uuid": response.data.get("uuid")})
        client = APIClient()
        response = client.get(url, **self.headers)
        uuid = response.data.get("uuid")
        role = Role.objects.get(uuid=uuid)

        self.assertIsNotNone(uuid)
        self.assertIsNotNone(response.data.get("name"))
        self.assertEqual(role_name, response.data.get("name"))
        self.assertIsNotNone(response.data.get("display_name"))
        self.assertEqual(role_name, response.data.get("display_name"))
        self.assertIsInstance(response.data.get("access"), list)
        self.assertEqual(access_data, response.data.get("access"))
        self.assertEqual(role.tenant, self.tenant)
        for access in role.access.all():
            self.assertEqual(access.tenant, self.tenant)
            for rd in ResourceDefinition.objects.filter(access=access):
                self.assertEqual(rd.tenant, self.tenant)

        # role also gets created in public schema
        with tenant_context(Tenant.objects.get(schema_name="public")):
            role_public = Role.objects.get(name="roleA")
            self.assertEqual(role_public.access.count(), 1)
            self.assertEqual(role_public.access.first().permission.permission,
                             access_data[0]["permission"])
            self.assertEqual(
                role_public.access.first().resourceDefinitions.first().
                attributeFilter,
                access_data[0]["resourceDefinitions"][0]["attributeFilter"],
            )

    def test_create_role_with_display_success(self):
        """Test that we can create a role."""
        role_name = "roleD"
        role_display = "display name for roleD"
        access_data = [{
            "permission":
            "app:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "equal",
                    "value": "valueA"
                }
            }],
        }]
        response = self.create_role(role_name,
                                    role_display=role_display,
                                    in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # test that we can retrieve the role
        url = reverse("role-detail",
                      kwargs={"uuid": response.data.get("uuid")})
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get("uuid"))
        self.assertIsNotNone(response.data.get("name"))
        self.assertEqual(role_name, response.data.get("name"))
        self.assertIsNotNone(response.data.get("display_name"))
        self.assertEqual(role_display, response.data.get("display_name"))
        self.assertIsInstance(response.data.get("access"), list)
        self.assertEqual(access_data, response.data.get("access"))

    def test_create_role_invalid(self):
        """Test that creating an invalid role returns an error."""
        test_data = {}
        client = APIClient()
        response = client.post(URL, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_create_role_invalid_permission(self):
        """Test that creating a role with invalid access permission returns an error."""
        test_data = {
            "name": "role1",
            "access": [{
                "permission": "foo:bar",
                "resourceDefinitions": []
            }]
        }
        client = APIClient()
        response = client.post(URL, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_create_role_empty_application_in_permission(self):
        """Test that creating a role with empty application in access permission returns an error."""
        test_data = {
            "name": "role1",
            "access": [{
                "permission": ":foo:bar",
                "resourceDefinitions": []
            }]
        }
        client = APIClient()
        response = client.post(URL, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_create_role_allow_list(self):
        """Test that we can create a role in an allow_listed application via API."""
        role_name = "C-MRole"
        access_data = [{
            "permission":
            "cost-management:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "equal",
                    "value": "valueA"
                }
            }],
        }]
        response = self.create_role(role_name, in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # test that we can retrieve the role
        url = reverse("role-detail",
                      kwargs={"uuid": response.data.get("uuid")})
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get("uuid"))
        self.assertIsNotNone(response.data.get("name"))
        self.assertEqual(role_name, response.data.get("name"))
        self.assertIsInstance(response.data.get("access"), list)
        self.assertEqual(access_data, response.data.get("access"))

    def test_create_role_allow_list_fail(self):
        """Test that we cannot create a role for a non-allow_listed app."""
        role_name = "roleFail"
        access_data = [{
            "permission":
            "someApp:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "equal",
                    "value": "valueA"
                }
            }],
        }]
        response = self.create_role(role_name, in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_create_role_appfilter_structure_fail(self):
        """Test that we cannot create a role with invalid structure of resource definition."""
        role_name = "operationFail"
        access_data = [{
            "permission": "cost-management:*:*",
            "resourceDefinitions": {
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "in",
                    "foo": "valueA"
                }
            },
        }]
        response = self.create_role(role_name, in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data["errors"][0]["detail"].code,
                         "not_a_list")

    def test_create_role_appfilter_fields_fail(self):
        """Test that we cannot create a role with an invalid key in the attributeFilter object."""
        role_name = "operationFail"
        access_data = [{
            "permission":
            "cost-management:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "in",
                    "foo": "valueA"
                }
            }],
        }]
        response = self.create_role(role_name, in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_create_role_appfilter_operation_fail(self):
        """Test that we cannot create a role with an invalid operation."""
        role_name = "operationFail"
        access_data = [{
            "permission":
            "cost-management:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "boop",
                    "value": "valueA"
                }
            }],
        }]
        response = self.create_role(role_name, in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_create_role_permission_does_not_exist_fail(self):
        """Test that we cannot create a role with a permission that doesn't exist."""
        role_name = "roleFailPermission"
        permission = "cost-management:foo:bar"
        access_data = [{
            "permission":
            permission,
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "equal",
                    "value": "valueA"
                }
            }],
        }]
        response = self.create_role(role_name, in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(
            response.data.get("errors")[0].get("detail"),
            f"Permission does not exist: {permission}")

    def test_create_role_fail_with_access_not_list(self):
        """Test that we cannot create a role for a non-allow_listed app."""
        role_name = "AccessNotList"
        access_data = "some data"
        response = self.create_role(role_name, in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_create_role_fail_with_invalid_access(self):
        """Test that we cannot create a role for invalid access data."""
        role_name = "AccessInvalid"
        access_data = [{"per": "some data"}]
        response = self.create_role(role_name, in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_read_role_invalid(self):
        """Test that reading an invalid role returns an error."""
        url = reverse("role-detail", kwargs={"uuid": uuid4()})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_read_role_valid(self):
        """Test that reading a valid role returns expected fields/values."""
        url = reverse("role-detail", kwargs={"uuid": self.defRole.uuid})
        client = APIClient()
        response = client.get(url, **self.headers)
        response_data = response.data
        expected_fields = self.display_fields
        expected_fields.add("access")
        self.assertEqual(expected_fields, set(response_data.keys()))
        self.assertEqual(response_data.get("uuid"), str(self.defRole.uuid))
        self.assertEqual(response_data.get("name"), self.defRole.name)
        self.assertEqual(response_data.get("display_name"),
                         self.defRole.display_name)
        self.assertEqual(response_data.get("description"),
                         self.defRole.description)
        self.assertCountEqual(response_data.get("applications"),
                              ["app", "app2"])
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_read_role_access_success(self):
        """Test that reading a valid role returns access."""
        url = reverse("role-access", kwargs={"uuid": self.defRole.uuid})
        client = APIClient()
        response = client.get(url, **self.headers)

        for keyname in ["meta", "links", "data"]:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get("data"), list)
        self.assertEqual(len(response.data.get("data")), 2)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_read_role_access_invalid_uuid(self):
        """Test that reading a non-existent role uuid returns an error."""
        url = reverse("role-access", kwargs={"uuid": "abc-123"})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_read_role_access_not_found_uuid(self):
        """Test that reading an invalid role uuid returns an error."""
        url = reverse("role-access", kwargs={"uuid": uuid4()})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_read_role_list_success(self):
        """Test that we can read a list of roles."""
        role_name = "roleA"
        role_display = "Display name for roleA"
        response = self.create_role(role_name, role_display=role_display)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        role_uuid = response.data.get("uuid")

        # list a role
        client = APIClient()
        response = client.get(URL, **self.headers)

        # three parts in response: meta, links and data
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ["meta", "links", "data"]:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get("data"), list)
        self.assertEqual(len(response.data.get("data")), 3)

        role = None

        for iterRole in response.data.get("data"):
            self.assertIsNotNone(iterRole.get("name"))
            # fields displayed are same as defined
            self.assertEqual(self.display_fields, set(iterRole.keys()))
            if iterRole.get("name") == role_name:
                self.assertEqual(iterRole.get("accessCount"), 1)
                role = iterRole
        self.assertEqual(role.get("name"), role_name)
        self.assertEqual(role.get("display_name"), role_display)

    def test_get_role_by_application_single(self):
        """Test that getting roles by application returns roles based on permissions."""
        url = "{}?application={}".format(URL, "app")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 1)
        self.assertEqual(
            response.data.get("data")[0].get("name"), self.defRole.name)

    def test_get_role_by_application_multiple(self):
        """Test that getting roles by multiple applications returns roles based on permissions."""
        url = "{}?application={}".format(URL, "app2")
        client = APIClient()
        response = client.get(url, **self.headers)
        role_names = [role.get("name") for role in response.data.get("data")]
        self.assertEqual(response.data.get("meta").get("count"), 2)
        self.assertCountEqual(role_names,
                              [self.defRole.name, self.sysRole.name])

    def test_get_role_by_application_duplicate_role(self):
        """Test that getting roles by application with permissions in the same role only returns the roles once."""
        url = "{}?application={}".format(URL, "app,app2")
        client = APIClient()
        response = client.get(url, **self.headers)
        role_names = [role.get("name") for role in response.data.get("data")]
        self.assertEqual(response.data.get("meta").get("count"), 2)
        self.assertCountEqual(role_names,
                              [self.defRole.name, self.sysRole.name])

    def test_get_role_by_application_does_not_exist(self):
        """Test that getting roles by application returns nothing when there is no match."""
        url = "{}?application={}".format(URL, "foo")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 0)

    def test_get_role_by_permission_single(self):
        """Test that getting roles by permission returns roles based on permissions."""
        url = "{}?permission={}".format(URL, "app:*:*")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 1)
        self.assertEqual(
            response.data.get("data")[0].get("name"), self.defRole.name)

    def test_get_role_by_duplicate_permission(self):
        """Test that getting roles by duplicate permissions in the same role only returns the roles once."""
        url = "{}?permission={}".format(URL, "app2:*:*")
        client = APIClient()
        response = client.get(url, **self.headers)
        role_names = [role.get("name") for role in response.data.get("data")]
        self.assertEqual(response.data.get("meta").get("count"), 2)
        self.assertCountEqual(role_names,
                              [self.defRole.name, self.sysRole.name])

    def test_get_role_by_permission_multiple(self):
        """Test that getting roles by permissions ."""
        url = "{}?permission={}".format(URL, "app:*:*,app2:*:*")
        client = APIClient()
        response = client.get(url, **self.headers)
        role_names = [role.get("name") for role in response.data.get("data")]
        self.assertEqual(response.data.get("meta").get("count"), 2)
        self.assertCountEqual(role_names,
                              [self.defRole.name, self.sysRole.name])

    def test_get_role_by_permission_does_not_exist(self):
        """Test that getting roles by permission returns nothing when there is no match."""
        url = "{}?permission={}".format(URL, "foo:foo:foo")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 0)

    def test_get_role_by_partial_name_by_default(self):
        """Test that getting roles by name returns partial match by default."""
        url = "{}?name={}".format(URL, "role")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 2)

    def test_get_role_by_partial_name_explicit(self):
        """Test that getting roles by name returns partial match when specified."""
        url = "{}?name={}&name_match={}".format(URL, "role", "partial")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 2)

    def test_get_role_by_name_invalid_criteria(self):
        """Test that getting roles by name fails with invalid name_match."""
        url = "{}?name={}&name_match={}".format(URL, "role", "bad_criteria")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_get_role_by_exact_name_match(self):
        """Test that getting roles by name returns exact match."""
        url = "{}?name={}&name_match={}".format(URL, self.sysRole.name,
                                                "exact")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 1)
        role = response.data.get("data")[0]
        self.assertEqual(role.get("name"), self.sysRole.name)

    def test_get_role_by_exact_name_no_match(self):
        """Test that getting roles by name returns no results with exact match."""
        url = "{}?name={}&name_match={}".format(URL, "role", "exact")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 0)

    def test_get_role_by_partial_display_name_by_default(self):
        """Test that getting roles by display_name returns partial match by default."""
        url = "{}?display_name={}".format(URL, "display")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 2)

    def test_get_role_by_partial_display_name_explicit(self):
        """Test that getting roles by display_name returns partial match when specified."""
        url = "{}?display_name={}&name_match={}".format(
            URL, "display", "partial")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 2)

    def test_get_role_by_display_name_invalid_criteria(self):
        """Test that getting roles by display_name fails with invalid name_match."""
        url = "{}?display_name={}&name_match={}".format(
            URL, "display", "bad_criteria")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_get_role_by_exact_display_name_match(self):
        """Test that getting roles by display_name returns exact match."""
        url = "{}?display_name={}&name_match={}".format(
            URL, self.sysRole.display_name, "exact")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 1)
        role = response.data.get("data")[0]
        self.assertEqual(role.get("display_name"), self.sysRole.display_name)

    def test_get_role_by_exact_display_name_no_match(self):
        """Test that getting roles by display_name returns no results with exact match."""
        url = "{}?display_name={}&name_match={}".format(
            URL, "display", "exact")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 0)

    def test_list_role_with_additional_fields_success(self):
        """Test that we can read a list of roles and add fields."""
        role_name = "roleA"
        field_1 = "groups_in_count"
        field_2 = "groups_in"
        new_diaplay_fields = self.display_fields
        new_diaplay_fields.add(field_1)
        new_diaplay_fields.add(field_2)

        # list a role
        url = "{}?add_fields={},{}".format(URL, field_1, field_2)
        client = APIClient()
        response = client.get(url, **self.headers)

        # three parts in response: meta, links and data
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ["meta", "links", "data"]:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get("data"), list)

        role = None

        for iterRole in response.data.get("data"):
            # fields displayed are same as defined, groupsInCount is added
            self.assertEqual(new_diaplay_fields, set(iterRole.keys()))
            if iterRole.get("name") == role_name:
                self.assertEqual(iterRole.get("accessCount"), 1)
                role = iterRole

            self.assertIsNotNone(iterRole.get("groups_in")[0]["name"])
            self.assertIsNotNone(iterRole.get("groups_in")[0]["uuid"])
            self.assertIsNotNone(iterRole.get("groups_in")[0]["description"])

    def test_list_role_with_username_forbidden_to_nonadmin(self):
        """Test that non admin can not read a list of roles for username."""
        # Setup non admin request
        non_admin_request_context = self._create_request_context(
            self.customer_data,
            self.user_data,
            create_customer=False,
            is_org_admin=False)
        non_admin_request = non_admin_request_context["request"]

        url = "{}?username={}".format(URL, self.user_data["username"])
        client = APIClient()
        response = client.get(url, **non_admin_request.META)

        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={
            "status_code": 200,
            "data": []
        },
    )
    def test_list_role_fail_with_invalid_username(self, mock_request):
        """Test that non admin can not read a list of roles for username."""
        url = "{}?username={}".format(URL, "foo")
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_list_role_with_additional_fields_username_success(self):
        """Test that we can read a list of roles and add fields for username."""
        field_1 = "groups_in_count"
        field_2 = "groups_in"
        new_diaplay_fields = self.display_fields
        new_diaplay_fields.add(field_1)
        new_diaplay_fields.add(field_2)

        url = "{}?add_fields={},{}&username={}".format(
            URL, field_1, field_2, self.user_data["username"])
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(len(response.data.get("data")), 2)

        role = response.data.get("data")[0]
        self.assertEqual(new_diaplay_fields, set(role.keys()))
        self.assertEqual(role["groups_in_count"], 1)

    def test_list_role_with_additional_fields_principal_success(self):
        """Test that we can read a list of roles and add fields for principal."""
        field_1 = "groups_in_count"
        field_2 = "groups_in"
        new_diaplay_fields = self.display_fields
        new_diaplay_fields.add(field_1)
        new_diaplay_fields.add(field_2)

        url = "{}?add_fields={},{}&scope=principal".format(
            URL, field_1, field_2)
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(len(response.data.get("data")), 2)

        role = response.data.get("data")[0]
        self.assertEqual(new_diaplay_fields, set(role.keys()))
        self.assertEqual(role["groups_in_count"], 1)

    def test_list_role_with_invalid_additional_fields(self):
        """Test that invalid additional fields will raise exception."""
        add_field = "invalid_field"

        # list a role
        url = "{}?add_fields={}".format(URL, add_field)
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_list_role_with_invalid_sort_order(self):
        """Test that an invalid sort order is ignored."""
        url = "{}?sort_field=zombie".format(URL)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_patch_role_success(self):
        """Test that we can patch an existing role."""
        role_name = "role"
        response = self.create_role(role_name)
        updated_name = role_name + "_update"
        updated_description = role_name + "This is a test"
        role_uuid = response.data.get("uuid")
        url = reverse("role-detail", kwargs={"uuid": role_uuid})
        client = APIClient()
        response = client.patch(
            url,
            {
                "name": updated_name,
                "display_name": updated_name,
                "description": updated_description
            },
            format="json",
            **self.headers,
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        self.assertIsNotNone(response.data.get("uuid"))
        self.assertEqual(updated_name, response.data.get("name"))
        self.assertEqual(updated_name, response.data.get("display_name"))
        self.assertEqual(updated_description, response.data.get("description"))

        with tenant_context(Tenant.objects.get(schema_name="public")):
            role_in_public = Role.objects.get(name=updated_name,
                                              tenant=self.tenant)
            self.assertIsNotNone(role_in_public)
            self.assertEqual(updated_name, role_in_public.display_name)
            self.assertEqual(updated_description, role_in_public.description)

    def test_patch_role_failure(self):
        """Test that we return a 400 with invalid fields in the patch."""
        role_name = "role"
        response = self.create_role(role_name)
        updated_name = role_name + "_update"
        updated_description = role_name + "This is a test"
        role_uuid = response.data.get("uuid")
        url = reverse("role-detail", kwargs={"uuid": role_uuid})
        client = APIClient()
        response = client.patch(
            url,
            {
                "name": updated_name,
                "display_name": updated_name,
                "description": updated_description,
                "foo": "bar"
            },
            format="json",
            **self.headers,
        )
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_update_role_success(self):
        """Test that we can update an existing role."""
        role_name = "roleA"
        response = self.create_role(role_name)
        updated_name = role_name + "_update"
        role_uuid = response.data.get("uuid")
        test_data = response.data
        test_data["name"] = updated_name
        test_data["access"][0]["permission"] = "cost-management:*:*"
        del test_data["uuid"]
        url = reverse("role-detail", kwargs={"uuid": role_uuid})
        client = APIClient()
        response = client.put(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        self.assertIsNotNone(response.data.get("uuid"))
        self.assertEqual(updated_name, response.data.get("name"))
        self.assertEqual("cost-management:*:*",
                         response.data.get("access")[0]["permission"])

        with tenant_context(Tenant.objects.get(schema_name="public")):
            role_in_public = Role.objects.get(name=updated_name,
                                              tenant=self.tenant)
            self.assertIsNotNone(role_in_public)
            self.assertEqual(
                "cost-management:*:*",
                role_in_public.access.first().permission.permission)

    def test_update_role_invalid(self):
        """Test that updating an invalid role returns an error."""
        url = reverse("role-detail", kwargs={"uuid": uuid4()})
        client = APIClient()
        response = client.put(
            url,
            {
                "name": "updated_name",
                "display_name": "updated_name",
                "description": "updated_description"
            },
            format="json",
            **self.headers,
        )
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_update_role_invalid_permission(self):
        """Test that updating a role with an invalid permission returns an error."""
        # Set up
        role_name = "permRole"
        access_data = [{
            "permission":
            "cost-management:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "equal",
                    "value": "valueA"
                }
            }],
        }]
        response = self.create_role(role_name, in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        role_uuid = response.data.get("uuid")
        test_data = response.data
        test_data.get("access")[0]["permission"] = "foo:*:read"
        test_data["applications"] = ["foo"]

        # Test update failure
        url = reverse("role-detail", kwargs={"uuid": role_uuid})
        client = APIClient()
        response = client.put(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_update_role_invalid_resource_defs_structure(self):
        """Test that updating a role with an invalid resource definitions returns an error."""
        # Set up
        role_name = "permRole"
        access_data = [{
            "permission":
            "cost-management:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "equal",
                    "value": "valueA"
                }
            }],
        }]
        response = self.create_role(role_name, in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        role_uuid = response.data.get("uuid")
        test_data = response.data
        test_data.get("access")[0]["resourceDefinitions"] = {
            "attributeFilter": {
                "key": "keyA",
                "operation": "equal",
                "value": "valueA"
            }
        }

        # Test update failure
        url = reverse("role-detail", kwargs={"uuid": role_uuid})
        client = APIClient()
        response = client.put(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data["errors"][0]["detail"].code,
                         "not_a_list")

    def test_update_role_appfilter_operation_fail(self):
        # Set up
        role_name = "permRole"
        access_data = [{
            "permission":
            "cost-management:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "equal",
                    "value": "valueA"
                }
            }],
        }]
        response = self.create_role(role_name, in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        role_uuid = response.data.get("uuid")
        test_data = response.data
        test_data.get("access")[0]["resourceDefinitions"][0].get(
            "attributeFilter")["operation"] = "foo"

        # Test update failure
        url = reverse("role-detail", kwargs={"uuid": role_uuid})
        client = APIClient()
        response = client.put(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(
            str(response.data["errors"][0]["detail"]),
            "attributeFilter operation must be one of ['in', 'equal']")

    def test_update_role_permission_does_not_exist_fail(self):
        """Test that we cannot update a role with a permission that doesn't exist."""
        # Set up
        role_name = "permRole"
        permission = "cost-management:foo:bar"
        access_data = [{
            "permission":
            "cost-management:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "equal",
                    "value": "valueA"
                }
            }],
        }]
        response = self.create_role(role_name, in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        role_uuid = response.data.get("uuid")
        test_data = response.data
        test_data.get("access")[0]["permission"] = permission
        test_data["applications"] = ["foo"]

        # Test update failure
        url = reverse("role-detail", kwargs={"uuid": role_uuid})
        client = APIClient()
        response = client.put(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(
            response.data.get("errors")[0].get("detail"),
            f"Permission does not exist: {permission}")

    def test_delete_role_success(self):
        """Test that we can delete an existing role."""
        role_name = "roleA"
        response = self.create_role(role_name)

        with tenant_context(Tenant.objects.get(schema_name="public")):
            self.assertIsNotNone(
                Role.objects.get(name=role_name, tenant=self.tenant))
        role_uuid = response.data.get("uuid")
        url = reverse("role-detail", kwargs={"uuid": role_uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

        # verify the role no longer exists
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
        with tenant_context(Tenant.objects.get(schema_name="public")):
            self.assertIsNone(
                Role.objects.filter(name=role_name,
                                    tenant=self.tenant).first())

    def test_delete_system_role(self):
        """Test that system roles are protected from deletion"""
        url = reverse("role-detail", kwargs={"uuid": self.sysRole.uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        # verify the role still exists
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_delete_default_role(self):
        """Test that default roles are protected from deletion"""
        url = reverse("role-detail", kwargs={"uuid": self.defRole.uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        # verify the role still exists
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_delete_role_invalid(self):
        """Test that deleting an invalid role returns an error."""
        url = reverse("role-detail", kwargs={"uuid": uuid4()})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_system_flag_filter(self):
        """Test that we can filter roles based on system flag."""
        client = APIClient()
        response = client.get(URL, **self.headers)

        self.assertEqual(len(response.data.get("data")), 2)

        url = f"{URL}?system=true"
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(len(response.data.get("data")), 1)
        role = response.data.get("data")[0]
        self.assertEqual(role.get("system"), True)

        url = f"{URL}?system=false"
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(len(response.data.get("data")), 1)
        role = response.data.get("data")[0]
        self.assertEqual(role.get("system"), False)
Exemplo n.º 19
0
class InternalViewsetTests(IdentityRequest):
    """Test the internal viewset."""

    def valid_destructive_time():
        return datetime.utcnow().replace(tzinfo=pytz.UTC) + timedelta(hours=1)

    def invalid_destructive_time():
        return datetime.utcnow().replace(tzinfo=pytz.UTC) - timedelta(hours=1)

    def setUp(self):
        """Set up the internal viewset tests."""
        super().setUp()

        self.client = APIClient()
        self.customer = self._create_customer_data()
        self.internal_request_context = self._create_request_context(
            self.customer, self.user_data, create_customer=False, is_internal=True, create_tenant=True
        )

        self.request = self.internal_request_context["request"]
        user = User()
        user.username = self.user_data["username"]
        user.account = self.customer_data["account_id"]
        self.request.user = user

        with tenant_context(self.tenant):
            self.group = Group(name="System Group", system=True)
            self.group.save()
            self.role = Role.objects.create(name="System Role", description="A role for a group.", system=True)
            self.policy = Policy.objects.create(name="System Policy", group=self.group)
            self.policy.roles.add(self.role)
            self.policy.save()
            self.group.policies.add(self.policy)
            self.group.save()

    def tearDown(self):
        """Tear down internal viewset tests."""
        with tenant_context(self.tenant):
            Group.objects.all().delete()
            Role.objects.all().delete()
            Policy.objects.all().delete()

    def test_delete_tenant_disallowed(self):
        """Test that we cannot delete a tenant when disallowed."""
        response = self.client.delete(f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.content.decode(), "Destructive operations disallowed.")

    @override_settings(INTERNAL_DESTRUCTIVE_API_OK_UNTIL=invalid_destructive_time())
    def test_delete_tenant_disallowed_with_past_timestamp(self):
        """Test that we cannot delete a tenant when disallowed."""
        response = self.client.delete(f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.content.decode(), "Destructive operations disallowed.")

    @override_settings(INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time())
    @patch.object(Tenant, "delete")
    def test_delete_tenant_allowed_and_unmodified(self, mock):
        """Test that we can delete a tenant when allowed and unmodified."""
        response = self.client.delete(f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    @override_settings(INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time())
    def test_delete_tenant_allowed_but_multiple_groups(self):
        """Test that we cannot delete a tenant when allowed but modified."""
        with tenant_context(self.tenant):
            Group.objects.create(name="Custom Group")

        response = self.client.delete(f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.content.decode(), "Tenant cannot be deleted.")

    @override_settings(INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time())
    def test_delete_tenant_allowed_but_group_is_not_system(self):
        """Test that we cannot delete a tenant when allowed but modified."""
        with tenant_context(self.tenant):
            self.group.system = False
            self.group.save()

        response = self.client.delete(f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.content.decode(), "Tenant cannot be deleted.")

    @override_settings(INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time())
    def test_delete_tenant_allowed_but_role_is_not_system(self):
        """Test that we cannot delete a tenant when allowed but modified."""
        with tenant_context(self.tenant):
            self.role.system = False
            self.role.save()

        response = self.client.delete(f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.content.decode(), "Tenant cannot be deleted.")

    @override_settings(INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time())
    def test_delete_tenant_allowed_but_custom_one_role_is_not_system(self):
        """Test that we cannot delete a tenant when allowed but modified."""
        with tenant_context(self.tenant):
            Role.objects.create(name="Custom Role")

        response = self.client.delete(f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.content.decode(), "Tenant cannot be deleted.")

    def test_list_unmodified_tenants(self):
        """Test that only unmodified tenants are returned"""
        modified_tenant_groups = Tenant.objects.create(schema_name="acctmodifiedgroups")
        modified_tenant_roles = Tenant.objects.create(schema_name="acctmodifiedroles")
        unmodified_tenant_2 = Tenant.objects.create(schema_name="acctunmodified2")

        with tenant_context(modified_tenant_groups):
            Group.objects.create(name="Custom Group")

        with tenant_context(modified_tenant_roles):
            Role.objects.create(name="Custom Role")

        with tenant_context(unmodified_tenant_2):
            Group.objects.create(name="System Group", system=True)
            Role.objects.create(name="System Role", system=True)

        response = self.client.get(f"/_private/api/tenant/unmodified/", **self.request.META)
        response_data = json.loads(response.content)
        self.assertCountEqual(
            response_data["unmodified_tenants"], [self.tenant.schema_name, unmodified_tenant_2.schema_name]
        )
        self.assertEqual(response_data["unmodified_tenants_count"], 2)
        self.assertEqual(response_data["total_tenants_count"], 4)
        self.assertEqual(Tenant.objects.count(), 4)

        response = self.client.get(f"/_private/api/tenant/unmodified/?limit=2", **self.request.META)
        response_data = json.loads(response.content)
        self.assertEqual(response_data["total_tenants_count"], 2)

        response = self.client.get(f"/_private/api/tenant/unmodified/?limit=2&offset=3", **self.request.META)
        response_data = json.loads(response.content)
        self.assertEqual(response_data["total_tenants_count"], 1)

    @patch("management.tasks.run_migrations_in_worker.delay")
    def test_run_migrations(self, migration_mock):
        """Test that we can trigger migrations."""
        response = self.client.post(f"/_private/api/migrations/run/", **self.request.META)
        migration_mock.assert_called_once()
        self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
        self.assertEqual(response.content.decode(), "Migrations are running in a background worker.")

    def test_list_migration_progress(self):
        """Test that we can get the status of migrations."""
        migration_name = "foo_migration"
        app_name = "foo_app"
        tenant_migrations_complete = Tenant.objects.create(schema_name="acctcomplete")
        tenant_migrations_incomplete = Tenant.objects.create(schema_name="acctincomplete")

        with tenant_context(tenant_migrations_complete):
            migrations_have_run = MigrationRecorder.Migration.objects.create(name=migration_name, app=app_name)

        url = f"/_private/api/migrations/progress/?migration_name={migration_name}&app={app_name}"
        response = self.client.get(url, **self.request.META)
        response_data = json.loads(response.content)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response_data["migration_name"], migration_name)
        self.assertEqual(response_data["app_name"], app_name)
        self.assertEqual(response_data["tenants_completed_count"], 1)
        self.assertEqual(response_data["percent_completed"], 33)
        self.assertIn("acctincomplete", response_data["incomplete_tenants"])
        self.assertNotIn("acctcomplete", response_data["incomplete_tenants"])
        self.assertEqual(len(response_data["incomplete_tenants"]), 2)

    def test_list_migration_progress_without_migration_name(self):
        """Test that we get a 400 when no migration name supplied."""
        url = f"/_private/api/migrations/progress/"
        response = self.client.get(url, **self.request.META)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.content.decode(), "Please specify a migration name in the `?migration_name=` param.")

    @patch("management.tasks.run_seeds_in_worker.delay")
    def test_run_seeds_with_defaults(self, seed_mock):
        """Test that we can trigger seeds with defaults."""
        response = self.client.post(f"/_private/api/seeds/run/", **self.request.META)
        seed_mock.assert_called_once_with({})
        self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
        self.assertEqual(response.content.decode(), "Seeds are running in a background worker.")

    @patch("management.tasks.run_seeds_in_worker.delay")
    def test_run_seeds_with_options(self, seed_mock):
        """Test that we can trigger seeds with options."""
        response = self.client.post(f"/_private/api/seeds/run/?seed_types=roles,groups", **self.request.META)
        seed_mock.assert_called_once_with({"roles": True, "groups": True})
        self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
        self.assertEqual(response.content.decode(), "Seeds are running in a background worker.")

    @patch("management.tasks.run_seeds_in_worker.delay")
    def test_run_seeds_with_invalid_options(self, seed_mock):
        """Test that we get a 400 when invalid option supplied."""
        response = self.client.post(f"/_private/api/seeds/run/?seed_types=foo,bar", **self.request.META)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        seed_mock.assert_not_called()
        self.assertEqual(
            response.content.decode(), "Valid options for \"seed_types\": ['permissions', 'roles', 'groups']."
        )
Exemplo n.º 20
0
class RoleViewsetTests(IdentityRequest):
    """Test the role viewset."""
    def setUp(self):
        """Set up the role viewset tests."""
        super().setUp()
        request = self.request_context["request"]
        user = User()
        user.username = self.user_data["username"]
        user.account = self.customer_data["account_id"]
        request.user = user

        sys_role_config = {
            "name": "system_role",
            "display_name": "system",
            "system": True
        }

        def_role_config = {
            "name": "default_role",
            "display_name": "default",
            "platform_default": True
        }

        self.display_fields = {
            "applications",
            "description",
            "uuid",
            "name",
            "display_name",
            "system",
            "created",
            "policyCount",
            "accessCount",
            "modified",
            "platform_default",
        }

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data["username"])
            self.principal.save()
            self.policy = Policy.objects.create(name="policyA")
            self.group = Group(name="groupA", description="groupA description")
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.policies.add(self.policy)
            self.group.save()

            self.sysRole = Role(**sys_role_config)
            self.sysRole.save()

            self.defRole = Role(**def_role_config)
            self.defRole.save()
            self.defRole.save()

            self.policy.roles.add(self.defRole, self.sysRole)
            self.policy.save()

            self.access = Access.objects.create(permission="app:*:*",
                                                role=self.defRole)
            self.access2 = Access.objects.create(permission="app2:*:*",
                                                 role=self.defRole)

            self.access3 = Access.objects.create(permission="app2:*:*",
                                                 role=self.sysRole)

    def tearDown(self):
        """Tear down role viewset tests."""
        with tenant_context(self.tenant):
            Group.objects.all().delete()
            Principal.objects.all().delete()
            Role.objects.all().delete()

    def create_role(self, role_name, role_display="", in_access_data=None):
        """Create a role."""
        access_data = [{
            "permission":
            "app:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "key1",
                    "operation": "equal",
                    "value": "value1"
                }
            }],
        }]
        if in_access_data:
            access_data = in_access_data
        test_data = {
            "name": role_name,
            "display_name": role_display,
            "access": access_data
        }

        # create a role
        client = APIClient()
        response = client.post(URL, test_data, format="json", **self.headers)
        return response

    def test_create_role_success(self):
        """Test that we can create a role."""
        role_name = "roleA"
        access_data = [{
            "permission":
            "app:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "equal",
                    "value": "valueA"
                }
            }],
        }]
        response = self.create_role(role_name, in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # test that we can retrieve the role
        url = reverse("role-detail",
                      kwargs={"uuid": response.data.get("uuid")})
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get("uuid"))
        self.assertIsNotNone(response.data.get("name"))
        self.assertEqual(role_name, response.data.get("name"))
        self.assertIsNotNone(response.data.get("display_name"))
        self.assertEqual(role_name, response.data.get("display_name"))
        self.assertIsInstance(response.data.get("access"), list)
        self.assertEqual(access_data, response.data.get("access"))

    def test_create_role_with_display_success(self):
        """Test that we can create a role."""
        role_name = "roleD"
        role_display = "display name for roleD"
        access_data = [{
            "permission":
            "app:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "equal",
                    "value": "valueA"
                }
            }],
        }]
        response = self.create_role(role_name,
                                    role_display=role_display,
                                    in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # test that we can retrieve the role
        url = reverse("role-detail",
                      kwargs={"uuid": response.data.get("uuid")})
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get("uuid"))
        self.assertIsNotNone(response.data.get("name"))
        self.assertEqual(role_name, response.data.get("name"))
        self.assertIsNotNone(response.data.get("display_name"))
        self.assertEqual(role_display, response.data.get("display_name"))
        self.assertIsInstance(response.data.get("access"), list)
        self.assertEqual(access_data, response.data.get("access"))

    def test_create_role_invalid(self):
        """Test that creating an invalid role returns an error."""
        test_data = {}
        client = APIClient()
        response = client.post(URL, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_create_role_invalid_permission(self):
        """Test that creating an invalid role returns an error."""
        test_data = {
            "name": "role1",
            "access": [{
                "permission": "foo:bar",
                "resourceDefinitions": []
            }]
        }
        client = APIClient()
        response = client.post(URL, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_create_role_allow_list(self):
        """Test that we can create a role in an allow_listed application via API."""
        role_name = "C-MRole"
        access_data = [{
            "permission":
            "cost-management:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "equal",
                    "value": "valueA"
                }
            }],
        }]
        response = self.create_role(role_name, in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # test that we can retrieve the role
        url = reverse("role-detail",
                      kwargs={"uuid": response.data.get("uuid")})
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get("uuid"))
        self.assertIsNotNone(response.data.get("name"))
        self.assertEqual(role_name, response.data.get("name"))
        self.assertIsInstance(response.data.get("access"), list)
        self.assertEqual(access_data, response.data.get("access"))

    def test_create_role_allow_list_fail(self):
        """Test that we cannot create a role for a non-allow_listed app."""
        role_name = "roleFail"
        access_data = [{
            "permission":
            "someApp:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "equal",
                    "value": "valueA"
                }
            }],
        }]
        response = self.create_role(role_name, in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_create_role_fail_with_access_not_list(self):
        """Test that we cannot create a role for a non-allow_listed app."""
        role_name = "AccessNotList"
        access_data = "some data"
        response = self.create_role(role_name, in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_create_role_fail_with_invalid_access(self):
        """Test that we cannot create a role for invalid access data."""
        role_name = "AccessInvalid"
        access_data = [{"per": "some data"}]
        response = self.create_role(role_name, in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_read_role_invalid(self):
        """Test that reading an invalid role returns an error."""
        url = reverse("role-detail", kwargs={"uuid": uuid4()})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_read_role_valid(self):
        """Test that reading a valid role returns expected fields/values."""
        url = reverse("role-detail", kwargs={"uuid": self.defRole.uuid})
        client = APIClient()
        response = client.get(url, **self.headers)
        response_data = response.data
        expected_fields = self.display_fields
        expected_fields.add("access")
        self.assertEqual(expected_fields, set(response_data.keys()))
        self.assertEqual(response_data.get("uuid"), str(self.defRole.uuid))
        self.assertEqual(response_data.get("name"), self.defRole.name)
        self.assertEqual(response_data.get("display_name"),
                         self.defRole.display_name)
        self.assertEqual(response_data.get("description"),
                         self.defRole.description)
        self.assertCountEqual(response_data.get("applications"),
                              ["app", "app2"])
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_read_role_access_success(self):
        """Test that reading a valid role returns access."""
        url = reverse("role-access", kwargs={"uuid": self.defRole.uuid})
        client = APIClient()
        response = client.get(url, **self.headers)

        for keyname in ["meta", "links", "data"]:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get("data"), list)
        self.assertEqual(len(response.data.get("data")), 2)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_read_role_access_invalid_uuid(self):
        """Test that reading a non-existent role uuid returns an error."""
        url = reverse("role-access", kwargs={"uuid": "abc-123"})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_read_role_access_not_found_uuid(self):
        """Test that reading an invalid role uuid returns an error."""
        url = reverse("role-access", kwargs={"uuid": uuid4()})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_read_role_list_success(self):
        """Test that we can read a list of roles."""
        role_name = "roleA"
        role_display = "Display name for roleA"
        response = self.create_role(role_name, role_display=role_display)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        role_uuid = response.data.get("uuid")

        # list a role
        client = APIClient()
        response = client.get(URL, **self.headers)

        # three parts in response: meta, links and data
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ["meta", "links", "data"]:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get("data"), list)
        self.assertEqual(len(response.data.get("data")), 3)

        role = None

        for iterRole in response.data.get("data"):
            self.assertIsNotNone(iterRole.get("name"))
            # fields displayed are same as defined
            self.assertEqual(self.display_fields, set(iterRole.keys()))
            if iterRole.get("name") == role_name:
                self.assertEqual(iterRole.get("accessCount"), 1)
                role = iterRole
        self.assertEqual(role.get("name"), role_name)
        self.assertEqual(role.get("display_name"), role_display)

    def test_get_role_by_application_single(self):
        """Test that getting roles by application returns roles based on permissions."""
        url = "{}?application={}".format(URL, "app")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 1)
        self.assertEqual(
            response.data.get("data")[0].get("name"), self.defRole.name)

    def test_get_role_by_application_multiple(self):
        """Test that getting roles by multiple applications returns roles based on permissions."""
        url = "{}?application={}".format(URL, "app2")
        client = APIClient()
        response = client.get(url, **self.headers)
        role_names = [role.get("name") for role in response.data.get("data")]
        self.assertEqual(response.data.get("meta").get("count"), 2)
        self.assertCountEqual(role_names,
                              [self.defRole.name, self.sysRole.name])

    def test_get_role_by_application_duplicate_role(self):
        """Test that getting roles by application with permissions in the same role only returns the roles once."""
        url = "{}?application={}".format(URL, "app,app2")
        client = APIClient()
        response = client.get(url, **self.headers)
        role_names = [role.get("name") for role in response.data.get("data")]
        self.assertEqual(response.data.get("meta").get("count"), 2)
        self.assertCountEqual(role_names,
                              [self.defRole.name, self.sysRole.name])

    def test_get_role_by_application_does_not_exist(self):
        """Test that getting roles by application returns nothing when there is no match."""
        url = "{}?application={}".format(URL, "foo")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 0)

    def test_get_role_by_permission_single(self):
        """Test that getting roles by permission returns roles based on permissions."""
        url = "{}?permission={}".format(URL, "app:*:*")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 1)
        self.assertEqual(
            response.data.get("data")[0].get("name"), self.defRole.name)

    def test_get_role_by_duplicate_permission(self):
        """Test that getting roles by duplicate permissions in the same role only returns the roles once."""
        url = "{}?permission={}".format(URL, "app2:*:*")
        client = APIClient()
        response = client.get(url, **self.headers)
        role_names = [role.get("name") for role in response.data.get("data")]
        self.assertEqual(response.data.get("meta").get("count"), 2)
        self.assertCountEqual(role_names,
                              [self.defRole.name, self.sysRole.name])

    def test_get_role_by_permission_multiple(self):
        """Test that getting roles by permissions ."""
        url = "{}?permission={}".format(URL, "app:*:*,app2:*:*")
        client = APIClient()
        response = client.get(url, **self.headers)
        role_names = [role.get("name") for role in response.data.get("data")]
        self.assertEqual(response.data.get("meta").get("count"), 2)
        self.assertCountEqual(role_names,
                              [self.defRole.name, self.sysRole.name])

    def test_get_role_by_permission_does_not_exist(self):
        """Test that getting roles by permission returns nothing when there is no match."""
        url = "{}?permission={}".format(URL, "foo:foo:foo")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 0)

    def test_get_role_by_partial_name_by_default(self):
        """Test that getting roles by name returns partial match by default."""
        url = "{}?name={}".format(URL, "role")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 2)

    def test_get_role_by_partial_name_explicit(self):
        """Test that getting roles by name returns partial match when specified."""
        url = "{}?name={}&name_match={}".format(URL, "role", "partial")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 2)

    def test_get_role_by_name_invalid_criteria(self):
        """Test that getting roles by name fails with invalid name_match."""
        url = "{}?name={}&name_match={}".format(URL, "role", "bad_criteria")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_get_role_by_exact_name_match(self):
        """Test that getting roles by name returns exact match."""
        url = "{}?name={}&name_match={}".format(URL, self.sysRole.name,
                                                "exact")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 1)
        role = response.data.get("data")[0]
        self.assertEqual(role.get("name"), self.sysRole.name)

    def test_get_role_by_exact_name_no_match(self):
        """Test that getting roles by name returns no results with exact match."""
        url = "{}?name={}&name_match={}".format(URL, "role", "exact")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 0)

    def test_list_role_with_additional_fields_success(self):
        """Test that we can read a list of roles and add fields."""
        role_name = "roleA"
        field_1 = "groups_in_count"
        field_2 = "groups_in"
        new_diaplay_fields = self.display_fields
        new_diaplay_fields.add(field_1)
        new_diaplay_fields.add(field_2)

        # list a role
        url = "{}?add_fields={},{}".format(URL, field_1, field_2)
        client = APIClient()
        response = client.get(url, **self.headers)

        # three parts in response: meta, links and data
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ["meta", "links", "data"]:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get("data"), list)

        role = None

        for iterRole in response.data.get("data"):
            # fields displayed are same as defined, groupsInCount is added
            self.assertEqual(new_diaplay_fields, set(iterRole.keys()))
            if iterRole.get("name") == role_name:
                self.assertEqual(iterRole.get("accessCount"), 1)
                role = iterRole

            self.assertIsNotNone(iterRole.get("groups_in")[0]["name"])
            self.assertIsNotNone(iterRole.get("groups_in")[0]["uuid"])
            self.assertIsNotNone(iterRole.get("groups_in")[0]["description"])

    def test_list_role_with_additional_fields_username_success(self):
        """Test that we can read a list of roles and add fields for username."""
        field_1 = "groups_in_count"
        field_2 = "groups_in"
        new_diaplay_fields = self.display_fields
        new_diaplay_fields.add(field_1)
        new_diaplay_fields.add(field_2)

        url = "{}?add_fields={},{}&username={}".format(
            URL, field_1, field_2, self.user_data["username"])
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(len(response.data.get("data")), 2)

        role = response.data.get("data")[0]
        self.assertEqual(new_diaplay_fields, set(role.keys()))
        self.assertEqual(role["groups_in_count"], 1)

    def test_list_role_with_additional_fields_principal_success(self):
        """Test that we can read a list of roles and add fields for principal."""
        field_1 = "groups_in_count"
        field_2 = "groups_in"
        new_diaplay_fields = self.display_fields
        new_diaplay_fields.add(field_1)
        new_diaplay_fields.add(field_2)

        url = "{}?add_fields={},{}&scope=principal".format(
            URL, field_1, field_2)
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(len(response.data.get("data")), 2)

        role = response.data.get("data")[0]
        self.assertEqual(new_diaplay_fields, set(role.keys()))
        self.assertEqual(role["groups_in_count"], 1)

    def test_list_role_with_invalid_additional_fields(self):
        """Test that invalid additional fields will raise exception."""
        add_field = "invalid_field"

        # list a role
        url = "{}?add_fields={}".format(URL, add_field)
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_update_role_success(self):
        """Test that we can update an existing role."""
        role_name = "roleA"
        response = self.create_role(role_name)
        updated_name = role_name + "_update"
        role_uuid = response.data.get("uuid")
        test_data = response.data
        test_data["name"] = updated_name
        del test_data["uuid"]
        url = reverse("role-detail", kwargs={"uuid": role_uuid})
        client = APIClient()
        response = client.put(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        self.assertIsNotNone(response.data.get("uuid"))
        self.assertEqual(updated_name, response.data.get("name"))

    def test_update_role_invalid(self):
        """Test that updating an invalid role returns an error."""
        url = reverse("role-detail", kwargs={"uuid": uuid4()})
        client = APIClient()
        response = client.put(url, {}, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_update_role_invalid_permission(self):
        """Test that updating a role with an invalid permission returns an error."""
        # Set up
        role_name = "permRole"
        access_data = [{
            "permission":
            "cost-management:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "equal",
                    "value": "valueA"
                }
            }],
        }]
        response = self.create_role(role_name, in_access_data=access_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        role_uuid = response.data.get("uuid")
        test_data = response.data
        test_data.get("access")[0]["permission"] = "foo:*:read"
        test_data["applications"] = ["foo"]

        # Test update failure
        url = reverse("role-detail", kwargs={"uuid": role_uuid})
        client = APIClient()
        response = client.put(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_delete_role_success(self):
        """Test that we can delete an existing role."""
        role_name = "roleA"
        response = self.create_role(role_name)
        role_uuid = response.data.get("uuid")
        url = reverse("role-detail", kwargs={"uuid": role_uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

        # verify the role no longer exists
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_system_role(self):
        """Test that system roles are protected from deletion"""
        url = reverse("role-detail", kwargs={"uuid": self.sysRole.uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        # verify the role still exists
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_delete_default_role(self):
        """Test that default roles are protected from deletion"""
        url = reverse("role-detail", kwargs={"uuid": self.defRole.uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        # verify the role still exists
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_delete_role_invalid(self):
        """Test that deleting an invalid role returns an error."""
        url = reverse("role-detail", kwargs={"uuid": uuid4()})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
Exemplo n.º 21
0
class AccessViewTests(IdentityRequest):
    """Test the access view."""
    def setUp(self):
        """Set up the access view tests."""
        super().setUp()
        request = self.request_context["request"]
        user = User()
        user.username = self.user_data["username"]
        user.account = self.customer_data["account_id"]
        request.user = user

        self.access_data = {
            "permission":
            "app:*:*",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "key1",
                    "operation": "equal",
                    "value": "value1"
                }
            }],
        }
        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data["username"])
            self.principal.save()
            self.admin_principal = Principal(username="******")
            self.admin_principal.save()
            self.group = Group(name="groupA")
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.save()

    def tearDown(self):
        """Tear down access view tests."""
        with tenant_context(self.tenant):
            Group.objects.all().delete()
            Principal.objects.all().delete()
            Role.objects.all().delete()
            Policy.objects.all().delete()

    def create_role(self, role_name, in_access_data=None):
        """Create a role."""
        access_data = self.access_data
        if in_access_data:
            access_data = in_access_data
        test_data = {"name": role_name, "access": [access_data]}

        # create a role
        url = reverse("role-list")
        client = APIClient()
        response = client.post(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        return response

    def create_policy(self,
                      policy_name,
                      group,
                      roles,
                      status=status.HTTP_201_CREATED):
        """Create a policy."""
        # create a policy
        test_data = {"name": policy_name, "group": group, "roles": roles}
        url = reverse("policy-list")
        client = APIClient()
        response = client.post(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status)
        return response

    def test_get_access_success(self):
        """Test that we can obtain the expected access without pagination."""
        role_name = "roleA"
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        role_uuid = response.data.get("uuid")
        role = Role.objects.get(uuid=role_uuid)
        access = Access.objects.create(role=role, permission="app2:foo:bar")
        policy_name = "policyA"
        response = self.create_policy(policy_name, self.group.uuid,
                                      [role_uuid])

        # test that we can retrieve the principal access
        url = "{}?application={}&username={}".format(reverse("access"), "app",
                                                     self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(response.data.get("data"))
        self.assertIsInstance(response.data.get("data"), list)
        self.assertEqual(len(response.data.get("data")), 1)
        self.assertEqual(response.data.get("meta").get("limit"), 1000)
        self.assertEqual(self.access_data, response.data.get("data")[0])

    def test_get_access_no_app_supplied(self):
        """Test that we return all permissions when no app supplied."""
        role_name = "roleA"
        policy_name = "policyA"
        access_data = {
            "permission":
            "app:foo:bar",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "equal",
                    "value": "valueA"
                }
            }],
        }
        response = self.create_role(role_name, access_data)
        role_uuid = response.data.get("uuid")
        role = Role.objects.get(uuid=role_uuid)
        access = Access.objects.create(role=role, permission="app2:foo:bar")
        self.create_policy(policy_name, self.group.uuid, [role_uuid])

        url = "{}?application=&username={}".format(reverse("access"),
                                                   self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(response.data.get("data"))
        self.assertIsInstance(response.data.get("data"), list)
        self.assertEqual(len(response.data.get("data")), 2)
        self.assertEqual(response.data.get("meta").get("limit"), 1000)

    def test_get_access_multiple_apps_supplied(self):
        """Test that we return all permissions for multiple apps when supplied."""
        role_name = "roleA"
        policy_name = "policyA"
        access_data = {
            "permission":
            "app:foo:bar",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "equal",
                    "value": "valueA"
                }
            }],
        }
        response = self.create_role(role_name, access_data)
        role_uuid = response.data.get("uuid")
        role = Role.objects.get(uuid=role_uuid)
        access = Access.objects.create(role=role, permission="app2:foo:bar")
        self.create_policy(policy_name, self.group.uuid, [role_uuid])

        url = "{}?application={}&username={}".format(reverse("access"),
                                                     "app,app2",
                                                     self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIsInstance(response.data.get("data"), list)
        self.assertEqual(len(response.data.get("data")), 2)

    def test_get_access_no_partial_match(self):
        """Test that we can have a partial match on app/permission."""
        role_name = "roleA"
        policy_name = "policyA"
        access_data = {
            "permission":
            "app:foo:bar",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "equal",
                    "value": "valueA"
                }
            }],
        }
        response = self.create_role(role_name, access_data)
        role_uuid = response.data.get("uuid")
        self.create_policy(policy_name, self.group.uuid, [role_uuid])

        url = "{}?application={}&username={}".format(reverse("access"), "ap",
                                                     self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(response.data.get("data"))
        self.assertIsInstance(response.data.get("data"), list)
        self.assertEqual(len(response.data.get("data")), 0)
        self.assertEqual(response.data.get("meta").get("limit"), 1000)

    def test_get_access_no_match(self):
        """Test that we only match on the application name of the permission data."""
        role_name = "roleA"
        policy_name = "policyA"
        access_data = {
            "permission":
            "app:foo:bar",
            "resourceDefinitions": [{
                "attributeFilter": {
                    "key": "keyA",
                    "operation": "equal",
                    "value": "valueA"
                }
            }],
        }
        response = self.create_role(role_name, access_data)
        role_uuid = response.data.get("uuid")
        self.create_policy(policy_name, self.group.uuid, [role_uuid])

        url = "{}?application={}&username={}".format(reverse("access"), "foo",
                                                     self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(response.data.get("data"))
        self.assertIsInstance(response.data.get("data"), list)
        self.assertEqual(len(response.data.get("data")), 0)
        self.assertEqual(response.data.get("meta").get("limit"), 1000)

    def test_get_access_with_limit(self):
        """Test that we can obtain the expected access with pagination."""
        role_name = "roleA"
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        role_uuid = response.data.get("uuid")
        policy_name = "policyA"
        response = self.create_policy(policy_name, self.group.uuid,
                                      [role_uuid])

        # test that we can retrieve the principal access
        url = "{}?application={}&username={}&limit=1".format(
            reverse("access"), "app", self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(response.data.get("data"))
        self.assertIsInstance(response.data.get("data"), list)
        self.assertEqual(len(response.data.get("data")), 1)
        self.assertEqual(response.data.get("meta").get("count"), 1)
        self.assertEqual(response.data.get("meta").get("limit"), 1)
        self.assertEqual(self.access_data, response.data.get("data")[0])

    def test_missing_query_params(self):
        """Test that we get expected failure when missing required query params."""
        url = "{}?page={}".format(reverse("access"), "3")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={
            "status_code": 200,
            "data": []
        },
    )
    def test_missing_invalid_username(self, mock_request):
        """Test that we get expected failure when missing required query params."""
        url = "{}?application={}&username={}".format(reverse("access"), "app",
                                                     uuid4())
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
Exemplo n.º 22
0
class PolicyViewsetTests(IdentityRequest):
    """Test the policy viewset."""

    def setUp(self):
        """Set up the policy viewset tests."""
        super().setUp()
        request = self.request_context["request"]
        user = User()
        user.username = self.user_data["username"]
        user.account = self.customer_data["account_id"]
        request.user = user

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data["username"])
            self.principal.save()
            self.group = Group(name="groupA")
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.save()
            Permission.objects.create(permission="app:*:*")

    def tearDown(self):
        """Tear down policy viewset tests."""
        with tenant_context(self.tenant):
            Group.objects.all().delete()
            Principal.objects.all().delete()
            Role.objects.all().delete()
            Policy.objects.all().delete()

    def create_role(self, role_name, in_access_data=None):
        """Create a role."""
        access_data = {
            "permission": "app:*:*",
            "resourceDefinitions": [{"attributeFilter": {"key": "key1", "operation": "equal", "value": "value1"}}],
        }
        if in_access_data:
            access_data = in_access_data
        test_data = {"name": role_name, "access": [access_data]}

        # create a role
        url = reverse("role-list")
        client = APIClient()
        response = client.post(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        return response

    def create_policy(self, policy_name, group, roles, status=status.HTTP_201_CREATED):
        """Create a policy."""
        # create a policy
        test_data = {"name": policy_name, "group": group, "roles": roles}
        url = reverse("policy-list")
        client = APIClient()
        response = client.post(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status)
        return response

    def test_create_policy_success(self):
        """Test that we can create a policy."""
        role_name = "roleA"
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        role_uuid = response.data.get("uuid")
        policy_name = "policyA"
        response = self.create_policy(policy_name, self.group.uuid, [role_uuid])

        # test that we can retrieve the policy
        url = reverse("policy-detail", kwargs={"uuid": response.data.get("uuid")})
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get("uuid"))
        self.assertIsNotNone(response.data.get("name"))
        self.assertEqual(policy_name, response.data.get("name"))
        self.assertEqual(str(self.group.uuid), response.data.get("group").get("uuid"))

    def test_create_policy_invalid_group(self):
        """Test that we cannot create a policy with invalid group."""
        role_name = "roleA"
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        role_uuid = response.data.get("uuid")
        policy_name = "policyA"
        response = self.create_policy(policy_name, uuid4(), [role_uuid], status.HTTP_400_BAD_REQUEST)

    def test_create_policy_invalid_role(self):
        """Test that we cannot create a policy with an invalid role."""
        policy_name = "policyA"
        response = self.create_policy(policy_name, self.group.uuid, [uuid4()], status.HTTP_400_BAD_REQUEST)

    def test_create_policy_no_role(self):
        """Test that we cannot create a policy without roles."""
        policy_name = "policyA"
        response = self.create_policy(policy_name, self.group.uuid, [], status.HTTP_400_BAD_REQUEST)

    def test_create_policy_invalid(self):
        """Test that creating an invalid policy returns an error."""
        test_data = {}
        url = reverse("policy-list")
        client = APIClient()
        response = client.post(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_read_policy_invalid(self):
        """Test that reading an invalid policy returns an error."""
        url = reverse("policy-detail", kwargs={"uuid": uuid4()})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_read_policy_list_success(self):
        """Test that we can read a list of policies."""
        role_name = "roleA"
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        role_uuid = response.data.get("uuid")
        policy_name = "policyA"
        response = self.create_policy(policy_name, self.group.uuid, [role_uuid])

        # list a policies
        url = reverse("policy-list")
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ["meta", "links", "data"]:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get("data"), list)
        self.assertEqual(len(response.data.get("data")), 1)

        policy = response.data.get("data")[0]
        self.assertIsNotNone(policy.get("name"))
        self.assertEqual(policy.get("name"), policy_name)

    def test_update_policy_success(self):
        """Test that we can update an existing policy."""
        role_name = "roleA"
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        role_uuid = response.data.get("uuid")
        policy_name = "policyA"
        response = self.create_policy(policy_name, self.group.uuid, [role_uuid])
        updated_name = policy_name + "_update"
        policy_uuid = response.data.get("uuid")
        test_data = response.data
        test_data["name"] = updated_name
        test_data["group"] = self.group.uuid
        test_data["roles"] = [role_uuid]
        del test_data["uuid"]
        url = reverse("policy-detail", kwargs={"uuid": policy_uuid})
        client = APIClient()
        response = client.put(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        self.assertIsNotNone(response.data.get("uuid"))
        self.assertEqual(updated_name, response.data.get("name"))

    def test_update_policy_bad_group(self):
        """Test that we cannot update an existing policy with a bad group."""
        role_name = "roleA"
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        role_uuid = response.data.get("uuid")
        policy_name = "policyA"
        response = self.create_policy(policy_name, self.group.uuid, [role_uuid])
        updated_name = policy_name + "_update"
        policy_uuid = response.data.get("uuid")
        test_data = response.data
        test_data["name"] = updated_name
        test_data["group"] = uuid4()
        test_data["roles"] = [role_uuid]
        del test_data["uuid"]
        url = reverse("policy-detail", kwargs={"uuid": policy_uuid})
        client = APIClient()
        response = client.put(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_update_policy_bad_role(self):
        """Test that we cannot update an existing policy with a bad role."""
        role_name = "roleA"
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        role_uuid = response.data.get("uuid")
        policy_name = "policyA"
        response = self.create_policy(policy_name, self.group.uuid, [role_uuid])
        updated_name = policy_name + "_update"
        policy_uuid = response.data.get("uuid")
        test_data = response.data
        test_data["name"] = updated_name
        test_data["group"] = self.group.uuid
        test_data["roles"] = [uuid4()]
        del test_data["uuid"]
        url = reverse("policy-detail", kwargs={"uuid": policy_uuid})
        client = APIClient()
        response = client.put(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_update_policy_no_role(self):
        """Test that we can update an existing policy to have no roles."""
        role_name = "roleA"
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        role_uuid = response.data.get("uuid")
        policy_name = "policyA"
        response = self.create_policy(policy_name, self.group.uuid, [role_uuid])
        updated_name = policy_name + "_update"
        policy_uuid = response.data.get("uuid")
        test_data = response.data
        test_data["name"] = updated_name
        test_data["group"] = self.group.uuid
        test_data["roles"] = []
        del test_data["uuid"]
        url = reverse("policy-detail", kwargs={"uuid": policy_uuid})
        client = APIClient()
        response = client.put(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_update_policy_invalid(self):
        """Test that updating an invalid policy returns an error."""
        url = reverse("policy-detail", kwargs={"uuid": uuid4()})
        client = APIClient()
        response = client.put(url, {}, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_role_success(self):
        """Test that we can delete an existing role."""
        role_name = "roleA"
        response = self.create_role(role_name)
        role_uuid = response.data.get("uuid")
        policy_name = "policyA"
        response = self.create_policy(policy_name, self.group.uuid, [role_uuid])
        policy_uuid = response.data.get("uuid")
        url = reverse("policy-detail", kwargs={"uuid": policy_uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

        # verify the policy no longer exists
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_policy_invalid(self):
        """Test that deleting an invalid policy returns an error."""
        url = reverse("policy-detail", kwargs={"uuid": uuid4()})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_policy_removed_on_group_deletion(self):
        """Test that we can an existing policy is cleaned up when the group is deleted."""
        role_name = "roleA"
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        role_uuid = response.data.get("uuid")
        policy_name = "policyA"
        response = self.create_policy(policy_name, self.group.uuid, [role_uuid])
        policy_uuid = response.data.get("uuid")

        url = reverse("group-detail", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)

        url = reverse("policy-detail", kwargs={"uuid": policy_uuid})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_policy_removed_on_all_role_deletion(self):
        """Test that we can an existing policy is cleaned up when the all roles are deleted."""
        role_name = "roleA"
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        role_uuid = response.data.get("uuid")
        policy_name = "policyA"
        response = self.create_policy(policy_name, self.group.uuid, [role_uuid])
        policy_uuid = response.data.get("uuid")

        url = reverse("role-detail", kwargs={"uuid": role_uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)

        url = reverse("policy-detail", kwargs={"uuid": policy_uuid})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_policy_removed_on_one_role_deletion(self):
        """Test that we can an existing policy remains when not all roles are deleted."""
        roles = []
        role_name = "roleA"
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        roles.append(response.data.get("uuid"))

        role_name = "roleB"
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        roles.append(response.data.get("uuid"))

        policy_name = "policyA"
        response = self.create_policy(policy_name, self.group.uuid, roles)
        policy_uuid = response.data.get("uuid")

        url = reverse("role-detail", kwargs={"uuid": roles[0]})
        client = APIClient()
        response = client.delete(url, **self.headers)

        url = reverse("policy-detail", kwargs={"uuid": policy_uuid})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
Exemplo n.º 23
0
class AccessViewTests(IdentityRequest):
    """Test the access view."""
    def setUp(self):
        """Set up the access view tests."""
        super().setUp()
        request = self.request_context['request']
        user = User()
        user.username = self.user_data['username']
        user.account = self.customer_data['account_id']
        request.user = user

        self.access_data = {
            'permission':
            'app:*:*',
            'resourceDefinitions': [{
                'attributeFilter': {
                    'key': 'key1',
                    'operation': 'equal',
                    'value': 'value1'
                }
            }]
        }
        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data['username'])
            self.principal.save()
            self.admin_principal = Principal(username="******")
            self.admin_principal.save()
            self.group = Group(name='groupA')
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.save()

    def tearDown(self):
        """Tear down access view tests."""
        with tenant_context(self.tenant):
            Group.objects.all().delete()
            Principal.objects.all().delete()
            Role.objects.all().delete()
            Policy.objects.all().delete()

    def create_role(self, role_name, in_access_data=None):
        """Create a role."""
        access_data = self.access_data
        if in_access_data:
            access_data = in_access_data
        test_data = {'name': role_name, 'access': [access_data]}

        # create a role
        url = reverse('role-list')
        client = APIClient()
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        return response

    def create_policy(self,
                      policy_name,
                      group,
                      roles,
                      status=status.HTTP_201_CREATED):
        """Create a policy."""
        # create a policy
        test_data = {'name': policy_name, 'group': group, 'roles': roles}
        url = reverse('policy-list')
        client = APIClient()
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status)
        return response

    def test_get_access_success(self):
        """Test that we can obtain the expected access without pagination."""
        role_name = 'roleA'
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        role_uuid = response.data.get('uuid')
        role = Role.objects.get(uuid=role_uuid)
        access = Access.objects.create(role=role, permission='app2:foo:bar')
        policy_name = 'policyA'
        response = self.create_policy(policy_name, self.group.uuid,
                                      [role_uuid])

        # test that we can retrieve the principal access
        url = '{}?application={}&username={}'.format(reverse('access'), 'app',
                                                     self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(response.data.get('data'))
        self.assertIsInstance(response.data.get('data'), list)
        self.assertEqual(len(response.data.get('data')), 1)
        self.assertEqual(response.data.get('meta').get('limit'), 1000)
        self.assertEqual(self.access_data, response.data.get('data')[0])

    def test_get_access_no_app_supplied(self):
        """Test that we return all permissions when no app supplied."""
        role_name = 'roleA'
        policy_name = 'policyA'
        access_data = {
            'permission':
            'app:foo:bar',
            'resourceDefinitions': [{
                'attributeFilter': {
                    'key': 'keyA',
                    'operation': 'equal',
                    'value': 'valueA'
                }
            }]
        }
        response = self.create_role(role_name, access_data)
        role_uuid = response.data.get('uuid')
        role = Role.objects.get(uuid=role_uuid)
        access = Access.objects.create(role=role, permission='app2:foo:bar')
        self.create_policy(policy_name, self.group.uuid, [role_uuid])

        url = '{}?application=&username={}'.format(reverse('access'),
                                                   self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(response.data.get('data'))
        self.assertIsInstance(response.data.get('data'), list)
        self.assertEqual(len(response.data.get('data')), 2)
        self.assertEqual(response.data.get('meta').get('limit'), 1000)

    def test_get_access_multiple_apps_supplied(self):
        """Test that we return all permissions for multiple apps when supplied."""
        role_name = 'roleA'
        policy_name = 'policyA'
        access_data = {
            'permission':
            'app:foo:bar',
            'resourceDefinitions': [{
                'attributeFilter': {
                    'key': 'keyA',
                    'operation': 'equal',
                    'value': 'valueA'
                }
            }]
        }
        response = self.create_role(role_name, access_data)
        role_uuid = response.data.get('uuid')
        role = Role.objects.get(uuid=role_uuid)
        access = Access.objects.create(role=role, permission='app2:foo:bar')
        self.create_policy(policy_name, self.group.uuid, [role_uuid])

        url = '{}?application={}&username={}'.format(reverse('access'),
                                                     'app,app2',
                                                     self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIsInstance(response.data.get('data'), list)
        self.assertEqual(len(response.data.get('data')), 2)

    def test_get_access_no_partial_match(self):
        """Test that we can have a partial match on app/permission."""
        role_name = 'roleA'
        policy_name = 'policyA'
        access_data = {
            'permission':
            'app:foo:bar',
            'resourceDefinitions': [{
                'attributeFilter': {
                    'key': 'keyA',
                    'operation': 'equal',
                    'value': 'valueA'
                }
            }]
        }
        response = self.create_role(role_name, access_data)
        role_uuid = response.data.get('uuid')
        self.create_policy(policy_name, self.group.uuid, [role_uuid])

        url = '{}?application={}&username={}'.format(reverse('access'), 'ap',
                                                     self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(response.data.get('data'))
        self.assertIsInstance(response.data.get('data'), list)
        self.assertEqual(len(response.data.get('data')), 0)
        self.assertEqual(response.data.get('meta').get('limit'), 1000)

    def test_get_access_no_match(self):
        """Test that we only match on the application name of the permission data."""
        role_name = 'roleA'
        policy_name = 'policyA'
        access_data = {
            'permission':
            'app:foo:bar',
            'resourceDefinitions': [{
                'attributeFilter': {
                    'key': 'keyA',
                    'operation': 'equal',
                    'value': 'valueA'
                }
            }]
        }
        response = self.create_role(role_name, access_data)
        role_uuid = response.data.get('uuid')
        self.create_policy(policy_name, self.group.uuid, [role_uuid])

        url = '{}?application={}&username={}'.format(reverse('access'), 'foo',
                                                     self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(response.data.get('data'))
        self.assertIsInstance(response.data.get('data'), list)
        self.assertEqual(len(response.data.get('data')), 0)
        self.assertEqual(response.data.get('meta').get('limit'), 1000)

    def test_get_access_with_limit(self):
        """Test that we can obtain the expected access with pagination."""
        role_name = 'roleA'
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        role_uuid = response.data.get('uuid')
        policy_name = 'policyA'
        response = self.create_policy(policy_name, self.group.uuid,
                                      [role_uuid])

        # test that we can retrieve the principal access
        url = '{}?application={}&username={}&limit=1'.format(
            reverse('access'), 'app', self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(response.data.get('data'))
        self.assertIsInstance(response.data.get('data'), list)
        self.assertEqual(len(response.data.get('data')), 1)
        self.assertEqual(response.data.get('meta').get('count'), 1)
        self.assertEqual(response.data.get('meta').get('limit'), 1)
        self.assertEqual(self.access_data, response.data.get('data')[0])

    def test_missing_query_params(self):
        """Test that we get expected failure when missing required query params."""
        url = '{}?page={}'.format(reverse('access'), '3')
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': []
        })
    def test_missing_invalid_username(self, mock_request):
        """Test that we get expected failure when missing required query params."""
        url = '{}?application={}&username={}'.format(reverse('access'), 'app',
                                                     uuid4())
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
Exemplo n.º 24
0
class GroupViewsetTests(IdentityRequest):
    """Test the group viewset."""
    def setUp(self):
        """Set up the group viewset tests."""
        super().setUp()
        request = self.request_context['request']
        user = User(username=self.user_data['username'],
                    email=self.user_data['email'],
                    tenant=self.tenant)
        user.save()
        request.user = user

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data['username'],
                                       email=self.user_data['email'])
            self.principal.save()
            self.group = Group(name='groupA')
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.save()

    def tearDown(self):
        """Tear down group viewset tests."""
        User.objects.all().delete()
        with tenant_context(self.tenant):
            Group.objects.all().delete()
            Principal.objects.all().delete()

    def test_create_group_success(self):
        """Test that we can create a group."""
        group_name = 'groupB'
        test_data = {'name': group_name}

        # create a group
        url = reverse('group-list')
        client = APIClient()
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # test that we can retrieve the group
        url = reverse('group-detail',
                      kwargs={'uuid': response.data.get('uuid')})
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get('uuid'))
        self.assertIsNotNone(response.data.get('name'))
        self.assertEqual(group_name, response.data.get('name'))

    def test_create_group_invalid(self):
        """Test that creating an invalid group returns an error."""
        test_data = {}
        url = reverse('group-list')
        client = APIClient()
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_read_group_success(self):
        """Test that we can read a group."""
        url = reverse('group-detail', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(response.data.get('name'))
        self.assertEqual(self.group.name, response.data.get('name'))

    def test_read_group_invalid(self):
        """Test that reading an invalid group returns an error."""
        url = reverse('group-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_read_group_list_success(self):
        """Test that we can read a list of groups."""
        url = reverse('group-list')
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ['meta', 'links', 'data']:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get('data'), list)
        self.assertEqual(len(response.data.get('data')), 1)

        group = response.data.get('data')[0]
        self.assertIsNotNone(group.get('name'))
        self.assertEqual(group.get('name'), self.group.name)

    def test_update_group_success(self):
        """Test that we can update an existing group."""
        group = Group.objects.first()
        updated_name = group.name + '_update'
        test_data = {'name': updated_name}
        url = reverse('group-detail', kwargs={'uuid': group.uuid})
        client = APIClient()
        response = client.put(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        self.assertIsNotNone(response.data.get('uuid'))
        self.assertEqual(updated_name, response.data.get('name'))

    def test_update_group_invalid(self):
        """Test that updating an invalid group returns an error."""
        url = reverse('group-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.put(url, {}, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_group_success(self):
        """Test that we can delete an existing group."""
        group = Group.objects.first()
        url = reverse('group-detail', kwargs={'uuid': group.uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

        # verify the group no longer exists
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_group_invalid(self):
        """Test that deleting an invalid group returns an error."""
        url = reverse('group-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_group_principals_invalid_method(self):
        """Test that using an unsupported REST method returns an error."""
        url = reverse('group-principals', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.put(url, {}, format='json', **self.headers)
        self.assertEqual(response.status_code,
                         status.HTTP_405_METHOD_NOT_ALLOWED)

    def test_add_group_principals_success(self):
        """Test that adding a principal to a group returns successfully."""
        url = reverse('group-principals', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        new_username = uuid4()
        test_data = {
            'principals': [{
                'username': self.principal.username
            }, {
                'username': new_username
            }]
        }
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_remove_group_principals_success(self):
        """Test that removing a principal to a group returns successfully."""
        url = reverse('group-principals', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        url = '{}?usernames={}'.format(url, self.principal.username)
        response = client.delete(url, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_principals_invalid(self):
        """Test that removing a principal returns an error with invalid data format."""
        url = reverse('group-principals', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        response = client.delete(url, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
Exemplo n.º 25
0
class RoleViewsetTests(IdentityRequest):
    """Test the role viewset."""
    def setUp(self):
        """Set up the role viewset tests."""
        super().setUp()
        request = self.request_context['request']
        user = User(username=self.user_data['username'], tenant=self.tenant)
        user.save()
        request.user = user

        sys_role_config = {'name': 'system_role', 'system': True}

        def_role_config = {'name': 'default_role', 'platform_default': True}

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data['username'])
            self.principal.save()
            self.group = Group(name='groupA')
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.save()

            self.sysRole = Role(**sys_role_config)
            self.sysRole.save()

            self.defRole = Role(**def_role_config)
            self.defRole.save()

    def tearDown(self):
        """Tear down role viewset tests."""
        User.objects.all().delete()
        with tenant_context(self.tenant):
            Group.objects.all().delete()
            Principal.objects.all().delete()
            Role.objects.all().delete()

    def create_role(self, role_name, in_access_data=None):
        """Create a role."""
        access_data = [{
            'permission':
            'app:*:*',
            'resourceDefinitions': [{
                'attributeFilter': {
                    'key': 'key1',
                    'operation': 'equal',
                    'value': 'value1'
                }
            }]
        }]
        if in_access_data:
            access_data = in_access_data
        test_data = {'name': role_name, 'access': access_data}

        # create a role
        url = reverse('role-list')
        client = APIClient()
        response = client.post(url, test_data, format='json', **self.headers)
        return response

    def test_create_role_success(self):
        """Test that we can create a role."""
        role_name = 'roleA'
        access_data = [{
            'permission':
            'app:*:*',
            'resourceDefinitions': [{
                'attributeFilter': {
                    'key': 'keyA',
                    'operation': 'equal',
                    'value': 'valueA'
                }
            }]
        }]
        response = self.create_role(role_name, access_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # test that we can retrieve the role
        url = reverse('role-detail',
                      kwargs={'uuid': response.data.get('uuid')})
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get('uuid'))
        self.assertIsNotNone(response.data.get('name'))
        self.assertEqual(role_name, response.data.get('name'))
        self.assertIsInstance(response.data.get('access'), list)
        self.assertEqual(access_data, response.data.get('access'))

    def test_create_role_invalid(self):
        """Test that creating an invalid role returns an error."""
        test_data = {}
        url = reverse('role-list')
        client = APIClient()
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_create_role_invalid_permission(self):
        """Test that creating an invalid role returns an error."""
        test_data = {
            'name': 'role1',
            'access': [{
                'permission': 'foo:bar',
                'resourceDefinitions': []
            }]
        }
        url = reverse('role-list')
        client = APIClient()
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_create_role_whitelist(self):
        """Test that we can create a role in a whitelisted application via API."""
        role_name = 'C-MRole'
        access_data = [{
            'permission':
            'cost-management:*:*',
            'resourceDefinitions': [{
                'attributeFilter': {
                    'key': 'keyA',
                    'operation': 'equal',
                    'value': 'valueA'
                }
            }]
        }]
        response = self.create_role(role_name, access_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # test that we can retrieve the role
        url = reverse('role-detail',
                      kwargs={'uuid': response.data.get('uuid')})
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get('uuid'))
        self.assertIsNotNone(response.data.get('name'))
        self.assertEqual(role_name, response.data.get('name'))
        self.assertIsInstance(response.data.get('access'), list)
        self.assertEqual(access_data, response.data.get('access'))

    def test_create_role_whitelist_fail(self):
        """Test that we cannot create a role for a non-whitelisted app."""
        role_name = 'roleFail'
        access_data = [{
            'permission':
            'someApp:*:*',
            'resourceDefinitions': [{
                'attributeFilter': {
                    'key': 'keyA',
                    'operation': 'equal',
                    'value': 'valueA'
                }
            }]
        }]
        response = self.create_role(role_name, access_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_create_role_fail_with_access_not_list(self):
        """Test that we cannot create a role for a non-whitelisted app."""
        role_name = 'AccessNotList'
        access_data = 'some data'
        response = self.create_role(role_name, access_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_create_role_fail_with_invalid_access(self):
        """Test that we cannot create a role for invalid access data."""
        role_name = 'AccessInvalid'
        access_data = [{'per': 'some data'}]
        response = self.create_role(role_name, access_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_read_role_invalid(self):
        """Test that reading an invalid role returns an error."""
        url = reverse('role-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_read_role_list_success(self):
        """Test that we can read a list of roles."""
        role_name = 'roleA'
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        role_uuid = response.data.get('uuid')

        # list a role
        url = reverse('role-list')
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ['meta', 'links', 'data']:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get('data'), list)
        self.assertEqual(len(response.data.get('data')), 3)

        role = None

        for iterRole in response.data.get('data'):
            self.assertIsNotNone(iterRole.get('name'))
            if iterRole.get('name') == role_name:
                role = iterRole
                break
        self.assertEqual(role.get('name'), role_name)

    def test_update_role_success(self):
        """Test that we can update an existing role."""
        role_name = 'roleA'
        response = self.create_role(role_name)
        updated_name = role_name + '_update'
        role_uuid = response.data.get('uuid')
        test_data = response.data
        test_data['name'] = updated_name
        del test_data['uuid']
        url = reverse('role-detail', kwargs={'uuid': role_uuid})
        client = APIClient()
        response = client.put(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        self.assertIsNotNone(response.data.get('uuid'))
        self.assertEqual(updated_name, response.data.get('name'))

    def test_update_role_invalid(self):
        """Test that updating an invalid role returns an error."""
        url = reverse('role-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.put(url, {}, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_role_success(self):
        """Test that we can delete an existing role."""
        role_name = 'roleA'
        response = self.create_role(role_name)
        role_uuid = response.data.get('uuid')
        url = reverse('role-detail', kwargs={'uuid': role_uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

        # verify the role no longer exists
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_system_role(self):
        """Test that system roles are protected from deletion"""
        url = reverse('role-detail', kwargs={'uuid': self.sysRole.uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        # verify the role still exists
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_delete_default_role(self):
        """Test that default roles are protected from deletion"""
        url = reverse('role-detail', kwargs={'uuid': self.defRole.uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        # verify the role still exists
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_delete_role_invalid(self):
        """Test that deleting an invalid role returns an error."""
        url = reverse('role-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
Exemplo n.º 26
0
class GroupViewsetTests(IdentityRequest):
    """Test the group viewset."""

    def setUp(self):
        """Set up the group viewset tests."""
        super().setUp()
        request = self.request_context["request"]
        user = User()
        user.username = self.user_data["username"]
        user.account = self.customer_data["account_id"]
        request.user = user
        self.dummy_role_id = uuid4()

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data["username"])
            self.principal.save()
            self.principalB = Principal(username="******")
            self.principalB.save()
            self.principalC = Principal(username="******")
            self.principalC.save()
            self.group = Group(name="groupA")
            self.group.save()
            self.role = Role.objects.create(name="roleA", description="A role for a group.", system=True)
            self.policy = Policy.objects.create(name="policyA", group=self.group)
            self.policy.roles.add(self.role)
            self.policy.save()
            self.group.policies.add(self.policy)
            self.group.principals.add(self.principal, self.principalB)
            self.group.save()

            self.defGroup = Group(name="groupDef", platform_default=True, system=True)
            self.defGroup.save()
            self.defGroup.principals.add(self.principal)
            self.defGroup.save()

            self.emptyGroup = Group(name="groupE")
            self.emptyGroup.save()

            self.groupB = Group.objects.create(name="groupB")
            self.groupB.principals.add(self.principal)
            self.policyB = Policy.objects.create(name="policyB", group=self.groupB)
            self.roleB = Role.objects.create(name="roleB", system=False)
            self.policyB.roles.add(self.roleB)
            self.policyB.save()

            # role that's not assigned to principal
            self.roleOrphan = Role.objects.create(name="roleOrphan")

            # group that associates with multipal roles
            self.groupMultiRole = Group.objects.create(name="groupMultiRole")
            self.policyMultiRole = Policy.objects.create(name="policyMultiRole")
            self.policyMultiRole.roles.add(self.role)
            self.policyMultiRole.roles.add(self.roleB)
            self.groupMultiRole.policies.add(self.policyMultiRole)

    def tearDown(self):
        """Tear down group viewset tests."""
        with tenant_context(self.tenant):
            Group.objects.all().delete()
            Principal.objects.all().delete()
            Role.objects.all().delete()
            Policy.objects.all().delete()

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": []},
    )
    def test_create_group_success(self, mock_request):
        """Test that we can create a group."""
        group_name = "groupC"
        test_data = {"name": group_name}

        # create a group
        url = reverse("group-list")
        client = APIClient()
        response = client.post(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # test that we can retrieve the group
        url = reverse("group-detail", kwargs={"uuid": response.data.get("uuid")})
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get("uuid"))
        self.assertIsNotNone(response.data.get("name"))
        self.assertEqual(group_name, response.data.get("name"))

    def test_create_default_group(self):
        """Test that system groups can be created."""
        group_name = "groupDef"

        # test group retrieval
        client = APIClient()
        url = reverse("group-detail", kwargs={"uuid": self.defGroup.uuid})
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get("uuid"))
        self.assertIsNotNone(response.data.get("name"))
        self.assertTrue(response.data.get("platform_default"))
        self.assertEqual(group_name, response.data.get("name"))

    def test_create_group_invalid(self):
        """Test that creating an invalid group returns an error."""
        test_data = {}
        url = reverse("group-list")
        client = APIClient()
        response = client.post(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_group_filter_by_any_role_name_in_a_list_success(self):
        """Test default behaviour that filter groups by any role name in a list success."""
        url = "{}?role_names={},{}".format(reverse("group-list"), "Rolea", "RoleB")
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertTrue(response.data.get("meta").get("count") == 3)

        expected_groups = [self.group.name, self.groupB.name, self.groupMultiRole.name]
        self.assertEqual(expected_groups, [group.get("name") for group in response.data.get("data")])

    def test_group_filter_by_all_role_name_in_a_list_success(self):
        """Test that filter groups by all role names in a list success."""
        url = "{}?role_names={},{}&role_discriminator=all".format(reverse("group-list"), "Rolea", "roleB")
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertTrue(response.data.get("meta").get("count") == 1)

        expected_groups = [self.groupMultiRole.name]
        self.assertEqual(expected_groups, [group.get("name") for group in response.data.get("data")])

    def test_group_filter_with_invalid_discriminator_failure(self):
        """Test that filter groups with invalid discriminator returns failed validation."""
        url = "{}?role_names={},{}&role_discriminator=invalid".format(reverse("group-list"), "roleA", "ROLEb")
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": []},
    )
    def test_read_group_success(self, mock_request):
        """Test that we can read a group."""
        url = reverse("group-detail", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(response.data.get("name"))
        self.assertEqual(self.group.name, response.data.get("name"))
        self.assertEqual(len(response.data.get("roles")), 1)
        self.assertEqual(response.data.get("roles")[0]["uuid"], str(self.role.uuid))

    def test_read_group_invalid(self):
        """Test that reading an invalid group returns an error."""
        url = reverse("group-detail", kwargs={"uuid": uuid4()})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_read_group_nonguid(self):
        """Test that reading a group with an invalid UUID returns an error."""
        url = reverse("group-detail", kwargs={"uuid": "potato"})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_read_group_list_success(self):
        """Test that we can read a list of groups."""
        url = reverse("group-list")
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ["meta", "links", "data"]:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get("data"), list)
        self.assertEqual(len(response.data.get("data")), 5)

        group = response.data.get("data")[0]
        self.assertIsNotNone(group.get("name"))
        self.assertEqual(group.get("name"), self.group.name)

    def test_get_group_by_partial_name_by_default(self):
        """Test that getting groups by name returns partial match by default."""
        url = reverse("group-list")
        url = "{}?name={}".format(url, "group")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 5)

    def test_get_group_by_partial_name_explicit(self):
        """Test that getting groups by name returns partial match when specified."""
        url = reverse("group-list")
        url = "{}?name={}&name_match={}".format(url, "group", "partial")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 5)

    def test_get_group_by_name_invalid_criteria(self):
        """Test that getting groups by name fails with invalid name_match."""
        url = reverse("group-list")
        url = "{}?name={}&name_match={}".format(url, "group", "bad_criteria")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_get_group_by_exact_name_match(self):
        """Test that getting groups by name returns exact match."""
        url = reverse("group-list")
        url = "{}?name={}&name_match={}".format(url, self.group.name, "exact")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 1)
        group = response.data.get("data")[0]
        self.assertEqual(group.get("name"), self.group.name)

    def test_get_group_by_exact_name_no_match(self):
        """Test that getting groups by name returns no results with exact match."""
        url = reverse("group-list")
        url = "{}?name={}&name_match={}".format(url, "group", "exact")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 0)

    def test_filter_group_list_by_uuid_success(self):
        """Test that we can filter a list of groups by uuid."""
        url = f"{reverse('group-list')}?uuid={self.group.uuid}"
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ["meta", "links", "data"]:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get("data"), list)
        self.assertEqual(len(response.data.get("data")), 1)

        group = response.data.get("data")[0]
        self.assertIsNotNone(group.get("name"))
        self.assertEqual(group.get("name"), self.group.name)

    def test_filter_group_list_by_uuid_multiple(self):
        """Test that we can filter a list of groups by uuid."""
        url = f"{reverse('group-list')}?uuid={self.group.uuid},{self.groupB.uuid}"
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ["meta", "links", "data"]:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get("data"), list)
        self.assertEqual(len(response.data.get("data")), 2)

        group = response.data.get("data")[0]
        self.assertIsNotNone(group.get("name"))
        self.assertEqual(group.get("name"), self.group.name)
        group = response.data.get("data")[1]
        self.assertIsNotNone(group.get("name"))
        self.assertEqual(group.get("name"), self.groupB.name)

    def test_filter_group_list_by_uuid_fail(self):
        """Test that filtering by a nonexistant uuid returns nothing."""
        url = f"{reverse('group-list')}?uuid={uuid4()}"
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ["meta", "links", "data"]:
            self.assertIn(keyname, response.data)
        self.assertEqual(response.data.get("data"), [])
        self.assertEqual(len(response.data.get("data")), 0)

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": []},
    )
    def test_update_group_success(self, mock_request):
        """Test that we can update an existing group."""
        group = Group.objects.first()
        updated_name = group.name + "_update"
        test_data = {"name": updated_name}
        url = reverse("group-detail", kwargs={"uuid": group.uuid})
        client = APIClient()
        response = client.put(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        self.assertIsNotNone(response.data.get("uuid"))
        self.assertEqual(updated_name, response.data.get("name"))

    def test_update_default_group(self):
        """Test that platform_default groups are protected from updates"""
        url = reverse("group-detail", kwargs={"uuid": self.defGroup.uuid})
        test_data = {"name": self.defGroup.name + "_updated"}
        client = APIClient()
        response = client.put(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_update_group_invalid(self):
        """Test that updating an invalid group returns an error."""
        url = reverse("group-detail", kwargs={"uuid": uuid4()})
        client = APIClient()
        response = client.put(url, {}, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_group_success(self):
        """Test that we can delete an existing group."""
        group = Group.objects.first()
        url = reverse("group-detail", kwargs={"uuid": group.uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

        # verify the group no longer exists
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_default_group(self):
        """Test that platform_default groups are protected from deletion"""
        url = reverse("group-detail", kwargs={"uuid": self.defGroup.uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_delete_group_invalid(self):
        """Test that deleting an invalid group returns an error."""
        url = reverse("group-detail", kwargs={"uuid": uuid4()})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_group_principals_invalid_method(self):
        """Test that using an unsupported REST method returns an error."""
        url = reverse("group-principals", kwargs={"uuid": uuid4()})
        client = APIClient()
        response = client.put(url, {}, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED)

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={
            "status_code": status.HTTP_500_INTERNAL_SERVER_ERROR,
            "errors": [
                {
                    "detail": "Unexpected error.",
                    "status": status.HTTP_500_INTERNAL_SERVER_ERROR,
                    "source": "principals",
                }
            ],
        },
    )
    def test_add_group_principals_failure(self, mock_request):
        """Test that adding a principal to a group returns has proper response when it is failed."""
        url = reverse("group-principals", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        new_username = uuid4()
        test_data = {"principals": [{"username": self.principal.username}, {"username": new_username}]}
        response = client.post(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
        self.assertEqual(response.data[0]["detail"], "Unexpected error.")
        self.assertEqual(response.data[0]["status"], 500)
        self.assertEqual(response.data[0]["source"], "principals")

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": [{"username": "******"}]},
    )
    def test_add_group_principals_success(self, mock_request):
        """Test that adding a principal to a group returns successfully."""
        # Create a group and a cross account user.
        with tenant_context(self.tenant):
            test_group = Group.objects.create(name="test")
            cross_account_user = Principal.objects.create(username="******", cross_account=True)
        url = reverse("group-principals", kwargs={"uuid": test_group.uuid})
        client = APIClient()
        test_data = {"principals": [{"username": "******"}, {"username": "******"}]}
        response = client.post(url, test_data, format="json", **self.headers)

        # Only the user exists in IT will be added to the group.
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data.get("principals")), 1)
        self.assertEqual(response.data.get("principals")[0], {"username": "******"})

        test_group.delete()
        cross_account_user.delete()

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": []},
    )
    def test_get_group_principals_empty(self, mock_request):
        """Test that getting principals from an empty group returns successfully."""
        client = APIClient()
        url = reverse("group-principals", kwargs={"uuid": self.emptyGroup.uuid})
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data.get("meta").get("count"), 0)
        self.assertEqual(response.data.get("data"), [])

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": []},
    )
    def test_get_group_principals_nonempty(self, mock_request):
        """Test that getting principals from a nonempty group returns successfully."""
        mock_request.return_value["data"] = [
            {"username": self.principal.username},
            {"username": self.principalB.username},
        ]

        client = APIClient()
        url = reverse("group-principals", kwargs={"uuid": self.group.uuid})
        response = client.get(url, **self.headers)

        call_args, kwargs = mock_request.call_args_list[0]
        username_arg = call_args[0]

        for username in [self.principal.username, self.principalB.username]:
            self.assertTrue(username in username_arg)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data.get("meta").get("count"), 2)
        self.assertEqual(response.data.get("data")[0].get("username"), self.principal.username)
        self.assertEqual(response.data.get("data")[1].get("username"), self.principalB.username)

    def test_remove_group_principals_success(self):
        """Test that removing a principal to a group returns successfully."""
        url = reverse("group-principals", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        url = "{}?usernames={}".format(url, self.principal.username)
        response = client.delete(url, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_principals_invalid(self):
        """Test that removing a principal returns an error with invalid data format."""
        url = reverse("group-principals", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        response = client.delete(url, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": []},
    )
    def test_get_group_by_username(self, mock_request):
        """Test that getting groups for a principal returns successfully."""
        url = reverse("group-list")
        url = "{}?username={}".format(url, self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 3)

        # User who is not added to a group explicitly will return platform default group
        url = reverse("group-list")
        url = "{}?username={}".format(url, self.principalC.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 1)

        # Return bad request when user does not exist
        url = reverse("group-list")
        url = "{}?username={}".format(url, uuid4())
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_get_group_by_username_for_cross_account_principal(self):
        """Test that getting groups for a cross account principal won't have platform default group."""
        with tenant_context(self.tenant):
            self.principalC.cross_account = True
            self.principalC.save()
        url = reverse("group-list")
        url = "{}?username={}".format(url, self.principalC.username)
        client = APIClient()

        # User who is not added to a group explicitly will not return platform default group if he is cross account principal.
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 0)

    def test_get_group_by_username_with_capitalization(self):
        """Test that getting groups for a user name with capitalization returns successfully."""
        url = reverse("group-list")
        username = "".join(random.choice([k.upper(), k]) for k in self.principal.username)
        url = "{}?username={}".format(url, username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 3)

    def test_get_group_roles_success(self):
        """Test that getting roles for a group returns successfully."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get("uuid"), str(self.role.uuid))
        self.assertEqual(roles[0].get("name"), self.role.name)
        self.assertEqual(roles[0].get("description"), self.role.description)

    def test_get_group_roles_with_exclude_false_success(self):
        """Test that getting roles with 'exclude=false' for a group works as default."""
        url = "%s?exclude=FALSE" % (reverse("group-roles", kwargs={"uuid": self.group.uuid}))
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get("uuid"), str(self.role.uuid))
        self.assertEqual(roles[0].get("name"), self.role.name)
        self.assertEqual(roles[0].get("description"), self.role.description)

    def test_get_group_roles_with_exclude_success(self):
        """Test that getting roles with 'exclude=True' for a group returns successfully."""
        url = "%s?exclude=True" % (reverse("group-roles", kwargs={"uuid": self.group.uuid}))
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 2)
        self.assertTrue(role.uuid in [self.roleB.uuid, self.roleOrphan.uuid] for role in roles)

    def test_get_group_roles_with_exclude_in_principal_scope_success(self):
        """Test that getting roles with 'exclude=True' for a group in principal scope."""
        url = "%s?exclude=True&scope=principal" % (reverse("group-roles", kwargs={"uuid": self.group.uuid}))
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get("uuid"), str(self.roleB.uuid))
        self.assertEqual(roles[0].get("name"), self.roleB.name)
        self.assertEqual(roles[0].get("description"), self.roleB.description)

    def test_get_group_roles_ordered(self):
        """Test getting roles with 'order_by=' returns properly."""
        url = f"{reverse('group-roles', kwargs={'uuid': self.group.uuid})}?order_by=-name"
        client = APIClient()

        test_data = {"roles": [self.roleB.uuid]}
        response = client.post(url, test_data, format="json", **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)

        response = client.get(url, **self.headers)
        roles = response.data.get("data")
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 2)
        self.assertEqual(roles[0].get("name"), self.roleB.name)
        self.assertEqual(roles[1].get("name"), self.role.name)

    def test_exclude_input_invalid(self):
        """Test that getting roles with 'exclude=' for a group returns failed validation."""
        url = "%s?exclude=sth" % (reverse("group-roles", kwargs={"uuid": self.group.uuid}))
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_role_name_filter_for_group_roles_no_match(self):
        """Test role_name filter for getting roles for a group."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        url = "{}?role_name=test".format(url)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 0)

    def test_role_name_filter_for_group_roles_match(self):
        """Test role_name filter for getting roles for a group."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        url = "{}?role_name={}".format(url, self.role.name)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get("uuid"), str(self.role.uuid))

    def test_role_display_name_filter_for_group_roles_no_match(self):
        """Test role_display_name filter for getting roles for a group."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        url = "{}?role_display_name=test".format(url)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 0)

    def test_role_display_name_filter_for_group_roles_match(self):
        """Test role_display_name filter for getting roles for a group."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        url = "{}?role_display_name={}".format(url, self.role.name)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get("uuid"), str(self.role.uuid))

    def test_role_description_filter_for_group_roles_no_match(self):
        """Test role_description filter for getting roles for a group."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        url = "{}?role_description=test".format(url)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 0)

    def test_role_description_filter_for_group_roles_match(self):
        """Test role_description filter for getting roles for a group."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        url = "{}?role_description={}".format(url, self.role.description)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get("uuid"), str(self.role.uuid))

    def test_all_role_filters_for_group_roles_no_match(self):
        """Test role filters for getting roles for a group."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        url = "{}?role_description=test&role_name=test".format(url)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 0)

    def test_all_role_filters_for_group_roles_match(self):
        """Test role filters for getting roles for a group."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        url = "{}?role_description={}&role_name={}".format(url, self.role.description, self.role.name)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get("uuid"), str(self.role.uuid))

    def test_role_system_filter_for_group_roles(self):
        """Test role_system filter for getting roles for a group."""
        base_url = reverse("group-roles", kwargs={"uuid": self.groupMultiRole.uuid})
        client = APIClient()
        response = client.get(base_url, **self.headers)
        self.assertEqual(len(response.data.get("data")), 2)

        url = f"{base_url}?role_system=true"
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(len(response.data.get("data")), 1)
        role = response.data.get("data")[0]
        self.assertEqual(role.get("system"), True)

        url = f"{base_url}?role_system=false"
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(len(response.data.get("data")), 1)
        role = response.data.get("data")[0]
        self.assertEqual(role.get("system"), False)

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": []},
    )
    def test_principal_username_filter_for_group_roles_no_match(self, mock_request):
        """Test principal_username filter for getting principals for a group."""
        url = reverse("group-principals", kwargs={"uuid": self.group.uuid})
        url = "{}?principal_username=test".format(url)
        client = APIClient()
        response = client.get(url, **self.headers)
        principals = response.data.get("data")

        mock_request.assert_called_with([], ANY, options={"sort_order": None})
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(principals), 0)

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": [{"username": "******"}]},
    )
    def test_principal_username_filter_for_group_roles_match(self, mock_request):
        """Test principal_username filter for getting principals for a group."""
        url = reverse("group-principals", kwargs={"uuid": self.group.uuid})
        url = "{}?principal_username={}".format(url, self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        principals = response.data.get("data")

        mock_request.assert_called_with([self.principal.username], ANY, options={"sort_order": None})
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(principals), 1)

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": [{"username": "******"}]},
    )
    def test_principal_get_ordering_username_success(self, mock_request):
        """Test that passing a username order_by parameter calls the proxy correctly."""
        url = f"{reverse('group-principals', kwargs={'uuid': self.group.uuid})}?order_by=username"
        client = APIClient()
        response = client.get(url, **self.headers)
        principals = response.data.get("data")
        expected_principals = sorted([self.principal.username, self.principalB.username])
        mock_request.assert_called_with(expected_principals, ANY, options={"sort_order": "asc"})
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(principals), 1)

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": [{"username": "******"}]},
    )
    def test_principal_get_ordering_nonusername_fail(self, mock_request):
        """Test that passing a username order_by parameter calls the proxy correctly."""
        url = f"{reverse('group-principals', kwargs={'uuid': self.group.uuid})}?order_by=best_joke"
        client = APIClient()
        response = client.get(url, **self.headers)
        principals = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(principals, None)

    def test_add_group_roles_system_policy_create_success(self):
        """Test that adding a role to a group without a system policy returns successfully."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        test_data = {"roles": [self.roleB.uuid, self.dummy_role_id]}

        self.assertCountEqual([self.role], list(self.group.roles()))
        self.assertCountEqual([self.policy], list(self.group.policies.all()))

        response = client.post(url, test_data, format="json", **self.headers)

        roles = response.data.get("data")
        system_policies = Policy.objects.filter(system=True)
        system_policy = system_policies.get(group=self.group)

        self.assertEqual(len(system_policies), 1)
        self.assertCountEqual([system_policy, self.policy], list(self.group.policies.all()))
        self.assertCountEqual([self.roleB], list(system_policy.roles.all()))
        self.assertCountEqual([self.role], list(self.policy.roles.all()))
        self.assertCountEqual([self.role, self.roleB], list(self.group.roles()))
        self.assertEqual(len(roles), 2)
        self.assertEqual(roles[0].get("uuid"), str(self.role.uuid))
        self.assertEqual(roles[0].get("name"), self.role.name)
        self.assertEqual(roles[0].get("description"), self.role.description)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_system_flag_update_on_add(self):
        """Test that adding a role to a platform_default group flips the system flag."""
        url = reverse("group-roles", kwargs={"uuid": self.defGroup.uuid})
        client = APIClient()
        test_data = {"roles": [self.roleB.uuid, self.dummy_role_id]}

        self.assertTrue(self.defGroup.system)
        response = client.post(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.defGroup.refresh_from_db()
        self.assertEqual(self.defGroup.name, "Custom default access")
        self.assertFalse(self.defGroup.system)

    def test_system_flag_update_on_remove(self):
        """Test that removing a role from a platform_default group flips the system flag."""
        url = reverse("group-roles", kwargs={"uuid": self.defGroup.uuid})
        client = APIClient()
        url = "{}?roles={}".format(url, self.roleB.uuid)

        self.policy.roles.add(self.roleB)
        self.policy.save()

        self.assertTrue(self.defGroup.system)
        response = client.delete(url, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.defGroup.refresh_from_db()
        self.assertEqual(self.defGroup.name, "Custom default access")
        self.assertFalse(self.defGroup.system)

    def test_add_group_roles_system_policy_create_new_group_success(self):
        """Test that adding a role to a group without a system policy returns successfully."""
        group_url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        groupB_url = reverse("group-roles", kwargs={"uuid": self.groupB.uuid})
        client = APIClient()
        test_data = {"roles": [self.roleB.uuid]}

        response = client.post(group_url, test_data, format="json", **self.headers)
        responseB = client.post(groupB_url, test_data, format="json", **self.headers)

        system_policies = Policy.objects.filter(system=True)
        system_policy = system_policies.get(group=self.group)
        system_policyB = system_policies.get(group=self.groupB)

        self.assertEqual(len(system_policies), 2)
        self.assertCountEqual([self.roleB], list(system_policy.roles.all()))
        self.assertCountEqual([self.roleB], list(system_policyB.roles.all()))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(responseB.status_code, status.HTTP_200_OK)

    def test_add_group_roles_system_policy_get_success(self):
        """Test that adding a role to a group with existing system policy returns successfully."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        test_data = {"roles": [self.roleB.uuid, self.dummy_role_id]}
        system_policy_name = "System Policy for Group {}".format(self.group.uuid)
        system_policy = Policy.objects.create(system=True, group=self.group, name=system_policy_name)

        self.assertCountEqual([self.role], list(self.group.roles()))
        self.assertCountEqual([system_policy, self.policy], list(self.group.policies.all()))

        response = client.post(url, test_data, format="json", **self.headers)

        roles = response.data.get("data")
        system_policies = Policy.objects.filter(system=True, group=self.group)
        system_policy = system_policies.first()

        self.assertEqual(len(system_policies), 1)
        self.assertCountEqual([system_policy, self.policy], list(self.group.policies.all()))
        self.assertCountEqual([self.roleB], list(system_policy.roles.all()))
        self.assertCountEqual([self.role], list(self.policy.roles.all()))
        self.assertCountEqual([self.role, self.roleB], list(self.group.roles()))
        self.assertEqual(len(roles), 2)
        self.assertEqual(roles[0].get("uuid"), str(self.role.uuid))
        self.assertEqual(roles[0].get("name"), self.role.name)
        self.assertEqual(roles[0].get("description"), self.role.description)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_add_group_multiple_roles_success(self):
        """Test that adding multiple roles to a group returns successfully."""
        with tenant_context(self.tenant):
            groupC = Group.objects.create(name="groupC")
            url = reverse("group-roles", kwargs={"uuid": groupC.uuid})
            client = APIClient()
            test_data = {"roles": [self.role.uuid, self.roleB.uuid]}

            self.assertCountEqual([], list(groupC.roles()))

            response = client.post(url, test_data, format="json", **self.headers)

            self.assertCountEqual([self.role, self.roleB], list(groupC.roles()))
            self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_add_group_multiple_roles_invalid(self):
        """Test that adding invalid roles to a group fails the request and does not add any."""
        with tenant_context(self.tenant):
            groupC = Group.objects.create(name="groupC")
            url = reverse("group-roles", kwargs={"uuid": groupC.uuid})
            client = APIClient()
            test_data = {"roles": ["abc123", self.roleB.uuid]}

            self.assertCountEqual([], list(groupC.roles()))

            response = client.post(url, test_data, format="json", **self.headers)

            self.assertCountEqual([], list(groupC.roles()))
            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_add_group_multiple_roles_not_found_success(self):
        """Test that adding roles to a group skips ids not found, and returns success."""
        with tenant_context(self.tenant):
            groupC = Group.objects.create(name="groupC")
            url = reverse("group-roles", kwargs={"uuid": groupC.uuid})
            client = APIClient()
            test_data = {"roles": [self.dummy_role_id, self.roleB.uuid]}

            self.assertCountEqual([], list(groupC.roles()))

            response = client.post(url, test_data, format="json", **self.headers)

            self.assertCountEqual([self.roleB], list(groupC.roles()))
            self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_remove_group_roles_success(self):
        """Test that removing a role from a group returns successfully."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        url = "{}?roles={}".format(url, self.role.uuid)

        self.policyB.roles.add(self.role)
        self.policyB.save()
        self.assertCountEqual([self.role], list(self.group.roles()))

        response = client.delete(url, format="json", **self.headers)

        self.assertCountEqual([], list(self.group.roles()))
        self.assertCountEqual([self.role, self.roleB], list(self.groupB.roles()))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_multiple_roles_success(self):
        """Test that removing multiple roles from a group returns successfully."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        url = "{}?roles={},{}".format(url, self.role.uuid, self.roleB.uuid)

        self.policy.roles.add(self.roleB)
        self.policy.save()
        self.assertCountEqual([self.role, self.roleB], list(self.group.roles()))

        response = client.delete(url, format="json", **self.headers)

        self.assertCountEqual([], list(self.group.roles()))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_multiple_roles_invalid(self):
        """Test that removing invalid roles from a group fails the request and does not remove any."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        url = "{}?roles={},{}".format(url, "abc123", self.roleB.uuid)

        self.policy.roles.add(self.roleB)
        self.policy.save()
        self.assertCountEqual([self.role, self.roleB], list(self.group.roles()))

        response = client.delete(url, format="json", **self.headers)

        self.assertCountEqual([self.role, self.roleB], list(self.group.roles()))
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_remove_group_multiple_roles_not_found_success(self):
        """Test that removing roles from a group skips ids not found, and returns success."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        url = "{}?roles={},{},{}".format(url, self.role.uuid, self.roleB.uuid, self.dummy_role_id)

        self.policy.roles.add(self.roleB)
        self.policy.save()
        self.assertCountEqual([self.role, self.roleB], list(self.group.roles()))

        response = client.delete(url, format="json", **self.headers)

        self.assertCountEqual([], list(self.group.roles()))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_roles_invalid(self):
        """Test that removing a role returns an error with invalid data format."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        client = APIClient()

        response = client.delete(url, format="json", **self.headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_admin_RonR(self):
        """Test that a admin user can group RBAC resources"""
        url = "{}?application={}".format(reverse("group-list"), "rbac")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
Exemplo n.º 27
0
class RoleViewsetTests(IdentityRequest):
    """Test the role viewset."""
    def setUp(self):
        """Set up the role viewset tests."""
        super().setUp()
        request = self.request_context['request']
        user = User(username=self.user_data['username'], tenant=self.tenant)
        user.save()
        request.user = user

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data['username'])
            self.principal.save()
            self.group = Group(name='groupA')
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.save()

    def tearDown(self):
        """Tear down role viewset tests."""
        User.objects.all().delete()
        with tenant_context(self.tenant):
            Group.objects.all().delete()
            Principal.objects.all().delete()
            Role.objects.all().delete()

    def create_role(self, role_name, in_access_data=None):
        """Create a role."""
        access_data = {
            'permission':
            'app:*:*',
            'resourceDefinitions': [{
                'attributeFilter': {
                    'key': 'key1',
                    'operation': 'equal',
                    'value': 'value1'
                }
            }]
        }
        if in_access_data:
            access_data = in_access_data
        test_data = {'name': role_name, 'access': [access_data]}

        # create a role
        url = reverse('role-list')
        client = APIClient()
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        return response

    def test_create_role_success(self):
        """Test that we can create a role."""
        role_name = 'roleA'
        access_data = {
            'permission':
            'app:*:*',
            'resourceDefinitions': [{
                'attributeFilter': {
                    'key': 'keyA',
                    'operation': 'equal',
                    'value': 'valueA'
                }
            }]
        }
        response = self.create_role(role_name, access_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # test that we can retrieve the role
        url = reverse('role-detail',
                      kwargs={'uuid': response.data.get('uuid')})
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get('uuid'))
        self.assertIsNotNone(response.data.get('name'))
        self.assertEqual(role_name, response.data.get('name'))
        self.assertIsInstance(response.data.get('access'), list)
        self.assertEqual(access_data, response.data.get('access')[0])

    def test_create_role_invalid(self):
        """Test that creating an invalid role returns an error."""
        test_data = {}
        url = reverse('role-list')
        client = APIClient()
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_create_role_invalid_permission(self):
        """Test that creating an invalid role returns an error."""
        test_data = {
            'name': 'role1',
            'access': [{
                'permission': 'foo:bar',
                'resourceDefinitions': []
            }]
        }
        url = reverse('role-list')
        client = APIClient()
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_read_role_invalid(self):
        """Test that reading an invalid role returns an error."""
        url = reverse('role-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_read_role_list_success(self):
        """Test that we can read a list of roles."""
        role_name = 'roleA'
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # list a roles
        url = reverse('role-list')
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ['meta', 'links', 'data']:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get('data'), list)
        self.assertEqual(len(response.data.get('data')), 1)

        role = response.data.get('data')[0]
        self.assertIsNotNone(role.get('name'))
        self.assertEqual(role.get('name'), role_name)

    def test_update_role_success(self):
        """Test that we can update an existing role."""
        role_name = 'roleA'
        response = self.create_role(role_name)
        updated_name = role_name + '_update'
        role_uuid = response.data.get('uuid')
        test_data = response.data
        test_data['name'] = updated_name
        del test_data['uuid']
        url = reverse('role-detail', kwargs={'uuid': role_uuid})
        client = APIClient()
        response = client.put(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        self.assertIsNotNone(response.data.get('uuid'))
        self.assertEqual(updated_name, response.data.get('name'))

    def test_update_role_invalid(self):
        """Test that updating an invalid role returns an error."""
        url = reverse('role-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.put(url, {}, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_role_success(self):
        """Test that we can delete an existing role."""
        role_name = 'roleA'
        response = self.create_role(role_name)
        role_uuid = response.data.get('uuid')
        url = reverse('role-detail', kwargs={'uuid': role_uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

        # verify the role no longer exists
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_role_invalid(self):
        """Test that deleting an invalid role returns an error."""
        url = reverse('role-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
Exemplo n.º 28
0
class InternalViewsetTests(IdentityRequest):
    """Test the internal viewset."""
    def valid_destructive_time():
        return datetime.utcnow().replace(tzinfo=pytz.UTC) + timedelta(hours=1)

    def invalid_destructive_time():
        return datetime.utcnow().replace(tzinfo=pytz.UTC) - timedelta(hours=1)

    def setUp(self):
        """Set up the internal viewset tests."""
        super().setUp()

        self.client = APIClient()
        self.customer = self._create_customer_data()
        self.internal_request_context = self._create_request_context(
            self.customer,
            self.user_data,
            create_customer=False,
            is_internal=True,
            create_tenant=True)

        self.request = self.internal_request_context["request"]
        user = User()
        user.username = self.user_data["username"]
        user.account = self.customer_data["account_id"]
        self.request.user = user

        with tenant_context(self.tenant):
            self.group = Group(name="System Group", system=True)
            self.group.save()
            self.role = Role.objects.create(name="System Role",
                                            description="A role for a group.",
                                            system=True)
            self.policy = Policy.objects.create(name="System Policy",
                                                group=self.group)
            self.policy.roles.add(self.role)
            self.policy.save()
            self.group.policies.add(self.policy)
            self.group.save()

    def tearDown(self):
        """Tear down internal viewset tests."""
        with tenant_context(self.tenant):
            Group.objects.all().delete()
            Role.objects.all().delete()
            Policy.objects.all().delete()

    def test_delete_tenant_disallowed(self):
        """Test that we cannot delete a tenant when disallowed."""
        response = self.client.delete(
            f"/_private/api/tenant/{self.tenant.schema_name}/",
            **self.request.META)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.content.decode(),
                         "Destructive operations disallowed.")

    @override_settings(
        INTERNAL_DESTRUCTIVE_API_OK_UNTIL=invalid_destructive_time())
    def test_delete_tenant_disallowed_with_past_timestamp(self):
        """Test that we cannot delete a tenant when disallowed."""
        response = self.client.delete(
            f"/_private/api/tenant/{self.tenant.schema_name}/",
            **self.request.META)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.content.decode(),
                         "Destructive operations disallowed.")

    @override_settings(
        INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time())
    @patch.object(Tenant, "delete")
    def test_delete_tenant_allowed_and_unmodified(self, mock):
        """Test that we can delete a tenant when allowed and unmodified."""
        response = self.client.delete(
            f"/_private/api/tenant/{self.tenant.schema_name}/",
            **self.request.META)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    @override_settings(
        INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time())
    def test_delete_tenant_allowed_but_multiple_groups(self):
        """Test that we cannot delete a tenant when allowed but modified."""
        with tenant_context(self.tenant):
            Group.objects.create(name="Custom Group")

        response = self.client.delete(
            f"/_private/api/tenant/{self.tenant.schema_name}/",
            **self.request.META)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.content.decode(),
                         "Tenant cannot be deleted.")

    @override_settings(
        INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time())
    def test_delete_tenant_allowed_but_group_is_not_system(self):
        """Test that we cannot delete a tenant when allowed but modified."""
        with tenant_context(self.tenant):
            self.group.system = False
            self.group.save()

        response = self.client.delete(
            f"/_private/api/tenant/{self.tenant.schema_name}/",
            **self.request.META)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.content.decode(),
                         "Tenant cannot be deleted.")

    @override_settings(
        INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time())
    def test_delete_tenant_allowed_but_role_is_not_system(self):
        """Test that we cannot delete a tenant when allowed but modified."""
        with tenant_context(self.tenant):
            self.role.system = False
            self.role.save()

        response = self.client.delete(
            f"/_private/api/tenant/{self.tenant.schema_name}/",
            **self.request.META)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.content.decode(),
                         "Tenant cannot be deleted.")

    @override_settings(
        INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time())
    def test_delete_tenant_allowed_but_custom_one_role_is_not_system(self):
        """Test that we cannot delete a tenant when allowed but modified."""
        with tenant_context(self.tenant):
            Role.objects.create(name="Custom Role")

        response = self.client.delete(
            f"/_private/api/tenant/{self.tenant.schema_name}/",
            **self.request.META)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.content.decode(),
                         "Tenant cannot be deleted.")

    def test_list_unmodified_tenants(self):
        """Test that only unmodified tenants are returned"""
        modified_tenant_groups = Tenant.objects.create(
            schema_name="acctmodifiedgroups")
        modified_tenant_roles = Tenant.objects.create(
            schema_name="acctmodifiedroles")
        unmodified_tenant_2 = Tenant.objects.create(
            schema_name="acctunmodified2")

        with tenant_context(modified_tenant_groups):
            Group.objects.create(name="Custom Group")

        with tenant_context(modified_tenant_roles):
            Role.objects.create(name="Custom Role")

        with tenant_context(unmodified_tenant_2):
            Group.objects.create(name="System Group", system=True)
            Role.objects.create(name="System Role", system=True)

        response = self.client.get(f"/_private/api/tenant/unmodified/",
                                   **self.request.META)
        response_data = json.loads(response.content)
        self.assertCountEqual(
            response_data["unmodified_tenants"],
            [self.tenant.schema_name, unmodified_tenant_2.schema_name])
        self.assertEqual(response_data["unmodified_tenants_count"], 2)
        self.assertEqual(response_data["total_tenants_count"], 4)
        self.assertEqual(Tenant.objects.count(), 4)
Exemplo n.º 29
0
class PolicyViewsetTests(IdentityRequest):
    """Test the policy viewset."""
    def setUp(self):
        """Set up the policy viewset tests."""
        super().setUp()
        request = self.request_context['request']
        user = User(username=self.user_data['username'],
                    email=self.user_data['email'],
                    tenant=self.tenant)
        user.save()
        request.user = user

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data['username'],
                                       email=self.user_data['email'])
            self.principal.save()
            self.group = Group(name='groupA')
            self.group.save()
            self.group.principals.add(self.principal)
            self.group.save()

    def tearDown(self):
        """Tear down policy viewset tests."""
        User.objects.all().delete()
        with tenant_context(self.tenant):
            Group.objects.all().delete()
            Principal.objects.all().delete()
            Role.objects.all().delete()
            Policy.objects.all().delete()

    def create_role(self, role_name, in_access_data=None):
        """Create a role."""
        access_data = {
            'permission':
            'app:*:*',
            'resourceDefinition': [{
                'attributeFilter': {
                    'key': 'key1',
                    'operation': 'equal',
                    'value': 'value1'
                }
            }]
        }
        if in_access_data:
            access_data = in_access_data
        test_data = {'name': role_name, 'access': [access_data]}

        # create a role
        url = reverse('role-list')
        client = APIClient()
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        return response

    def create_policy(self,
                      policy_name,
                      group,
                      roles,
                      status=status.HTTP_201_CREATED):
        """Create a policy."""
        # create a policy
        test_data = {'name': policy_name, 'group': group, 'roles': roles}
        url = reverse('policy-list')
        client = APIClient()
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status)
        return response

    def test_create_policy_success(self):
        """Test that we can create a policy."""
        role_name = 'roleA'
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        role_uuid = response.data.get('uuid')
        policy_name = 'policyA'
        response = self.create_policy(policy_name, self.group.uuid,
                                      [role_uuid])

        # test that we can retrieve the policy
        url = reverse('policy-detail',
                      kwargs={'uuid': response.data.get('uuid')})
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get('uuid'))
        self.assertIsNotNone(response.data.get('name'))
        self.assertEqual(policy_name, response.data.get('name'))
        self.assertEqual(str(self.group.uuid),
                         response.data.get('group').get('uuid'))

    def test_create_policy_invalid_group(self):
        """Test that we cannot create a policy with invalid group."""
        role_name = 'roleA'
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        role_uuid = response.data.get('uuid')
        policy_name = 'policyA'
        response = self.create_policy(policy_name, uuid4(), [role_uuid],
                                      status.HTTP_400_BAD_REQUEST)

    def test_create_policy_invalid_role(self):
        """Test that we cannot create a policy with an invalid role."""
        policy_name = 'policyA'
        response = self.create_policy(policy_name, self.group.uuid, [uuid4()],
                                      status.HTTP_400_BAD_REQUEST)

    def test_create_policy_no_role(self):
        """Test that we cannot create a policy without roles."""
        policy_name = 'policyA'
        response = self.create_policy(policy_name, self.group.uuid, [],
                                      status.HTTP_400_BAD_REQUEST)

    def test_create_policy_invalid(self):
        """Test that creating an invalid policy returns an error."""
        test_data = {}
        url = reverse('policy-list')
        client = APIClient()
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_read_policy_invalid(self):
        """Test that reading an invalid policy returns an error."""
        url = reverse('policy-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_read_policy_list_success(self):
        """Test that we can read a list of policies."""
        role_name = 'roleA'
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        role_uuid = response.data.get('uuid')
        policy_name = 'policyA'
        response = self.create_policy(policy_name, self.group.uuid,
                                      [role_uuid])

        # list a policies
        url = reverse('policy-list')
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ['meta', 'links', 'data']:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get('data'), list)
        self.assertEqual(len(response.data.get('data')), 1)

        policy = response.data.get('data')[0]
        self.assertIsNotNone(policy.get('name'))
        self.assertEqual(policy.get('name'), policy_name)

    def test_update_policy_success(self):
        """Test that we can update an existing policy."""
        role_name = 'roleA'
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        role_uuid = response.data.get('uuid')
        policy_name = 'policyA'
        response = self.create_policy(policy_name, self.group.uuid,
                                      [role_uuid])
        updated_name = policy_name + '_update'
        policy_uuid = response.data.get('uuid')
        test_data = response.data
        test_data['name'] = updated_name
        test_data['group'] = self.group.uuid
        test_data['roles'] = [role_uuid]
        del test_data['uuid']
        url = reverse('policy-detail', kwargs={'uuid': policy_uuid})
        client = APIClient()
        response = client.put(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        self.assertIsNotNone(response.data.get('uuid'))
        self.assertEqual(updated_name, response.data.get('name'))

    def test_update_policy_bad_group(self):
        """Test that we cannot update an existing policy with a bad group."""
        role_name = 'roleA'
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        role_uuid = response.data.get('uuid')
        policy_name = 'policyA'
        response = self.create_policy(policy_name, self.group.uuid,
                                      [role_uuid])
        updated_name = policy_name + '_update'
        policy_uuid = response.data.get('uuid')
        test_data = response.data
        test_data['name'] = updated_name
        test_data['group'] = uuid4()
        test_data['roles'] = [role_uuid]
        del test_data['uuid']
        url = reverse('policy-detail', kwargs={'uuid': policy_uuid})
        client = APIClient()
        response = client.put(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_update_policy_bad_role(self):
        """Test that we cannot update an existing policy with a bad role."""
        role_name = 'roleA'
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        role_uuid = response.data.get('uuid')
        policy_name = 'policyA'
        response = self.create_policy(policy_name, self.group.uuid,
                                      [role_uuid])
        updated_name = policy_name + '_update'
        policy_uuid = response.data.get('uuid')
        test_data = response.data
        test_data['name'] = updated_name
        test_data['group'] = self.group.uuid
        test_data['roles'] = [uuid4()]
        del test_data['uuid']
        url = reverse('policy-detail', kwargs={'uuid': policy_uuid})
        client = APIClient()
        response = client.put(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_update_policy_no_role(self):
        """Test that we can update an existing policy to have no roles."""
        role_name = 'roleA'
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        role_uuid = response.data.get('uuid')
        policy_name = 'policyA'
        response = self.create_policy(policy_name, self.group.uuid,
                                      [role_uuid])
        updated_name = policy_name + '_update'
        policy_uuid = response.data.get('uuid')
        test_data = response.data
        test_data['name'] = updated_name
        test_data['group'] = self.group.uuid
        test_data['roles'] = []
        del test_data['uuid']
        url = reverse('policy-detail', kwargs={'uuid': policy_uuid})
        client = APIClient()
        response = client.put(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_update_policy_invalid(self):
        """Test that updating an invalid policy returns an error."""
        url = reverse('policy-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.put(url, {}, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_role_success(self):
        """Test that we can delete an existing role."""
        role_name = 'roleA'
        response = self.create_role(role_name)
        role_uuid = response.data.get('uuid')
        policy_name = 'policyA'
        response = self.create_policy(policy_name, self.group.uuid,
                                      [role_uuid])
        policy_uuid = response.data.get('uuid')
        url = reverse('policy-detail', kwargs={'uuid': policy_uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

        # verify the policy no longer exists
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_policy_invalid(self):
        """Test that deleting an invalid policy returns an error."""
        url = reverse('policy-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_policy_removed_on_group_deletion(self):
        """Test that we can an existing policy is cleaned up when the group is deleted."""
        role_name = 'roleA'
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        role_uuid = response.data.get('uuid')
        policy_name = 'policyA'
        response = self.create_policy(policy_name, self.group.uuid,
                                      [role_uuid])
        policy_uuid = response.data.get('uuid')

        url = reverse('group-detail', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)

        url = reverse('policy-detail', kwargs={'uuid': policy_uuid})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_policy_removed_on_all_role_deletion(self):
        """Test that we can an existing policy is cleaned up when the all roles are deleted."""
        role_name = 'roleA'
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        role_uuid = response.data.get('uuid')
        policy_name = 'policyA'
        response = self.create_policy(policy_name, self.group.uuid,
                                      [role_uuid])
        policy_uuid = response.data.get('uuid')

        url = reverse('role-detail', kwargs={'uuid': role_uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)

        url = reverse('policy-detail', kwargs={'uuid': policy_uuid})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_policy_removed_on_one_role_deletion(self):
        """Test that we can an existing policy remains when not all roles are deleted."""
        roles = []
        role_name = 'roleA'
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        roles.append(response.data.get('uuid'))

        role_name = 'roleB'
        response = self.create_role(role_name)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        roles.append(response.data.get('uuid'))

        policy_name = 'policyA'
        response = self.create_policy(policy_name, self.group.uuid, roles)
        policy_uuid = response.data.get('uuid')

        url = reverse('role-detail', kwargs={'uuid': roles[0]})
        client = APIClient()
        response = client.delete(url, **self.headers)

        url = reverse('policy-detail', kwargs={'uuid': policy_uuid})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
Exemplo n.º 30
0
class GroupViewsetTests(IdentityRequest):
    """Test the group viewset."""
    def setUp(self):
        """Set up the group viewset tests."""
        super().setUp()
        request = self.request_context['request']
        user = User(username=self.user_data['username'], tenant=self.tenant)
        user.save()
        request.user = user
        self.dummy_role_id = uuid4()

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data['username'])
            self.principal.save()
            self.group = Group(name='groupA')
            self.group.save()
            self.role = Role.objects.create(name='roleA')
            self.policy = Policy.objects.create(name='policyA',
                                                group=self.group)
            self.policy.roles.add(self.role)
            self.policy.save()
            self.group.policies.add(self.policy)
            self.group.principals.add(self.principal)
            self.group.save()

            self.defGroup = Group(name='groupDef',
                                  platform_default=True,
                                  system=True)
            self.defGroup.save()
            self.defGroup.principals.add(self.principal)
            self.defGroup.save()

            self.groupB = Group.objects.create(name='groupB')
            self.groupB.principals.add(self.principal)
            self.policyB = Policy.objects.create(name='policyB',
                                                 group=self.groupB)
            self.roleB = Role.objects.create(name='roleB')
            self.policyB.roles.add(self.roleB)
            self.policyB.save()

    def tearDown(self):
        """Tear down group viewset tests."""
        User.objects.all().delete()
        with tenant_context(self.tenant):
            Group.objects.all().delete()
            Principal.objects.all().delete()
            Role.objects.all().delete()
            Policy.objects.all().delete()

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': []
        })
    def test_create_group_success(self, mock_request):
        """Test that we can create a group."""
        group_name = 'groupC'
        test_data = {'name': group_name}

        # create a group
        url = reverse('group-list')
        client = APIClient()
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # test that we can retrieve the group
        url = reverse('group-detail',
                      kwargs={'uuid': response.data.get('uuid')})
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get('uuid'))
        self.assertIsNotNone(response.data.get('name'))
        self.assertEqual(group_name, response.data.get('name'))

    def test_create_default_group(self):
        """Test that system groups can be created."""
        group_name = 'groupDef'

        # test group retrieval
        client = APIClient()
        url = reverse('group-detail', kwargs={'uuid': self.defGroup.uuid})
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get('uuid'))
        self.assertIsNotNone(response.data.get('name'))
        self.assertTrue(response.data.get('platform_default'))
        self.assertEqual(group_name, response.data.get('name'))

    def test_create_group_invalid(self):
        """Test that creating an invalid group returns an error."""
        test_data = {}
        url = reverse('group-list')
        client = APIClient()
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': []
        })
    def test_read_group_success(self, mock_request):
        """Test that we can read a group."""
        url = reverse('group-detail', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(response.data.get('name'))
        self.assertEqual(self.group.name, response.data.get('name'))
        self.assertEqual(len(response.data.get('roles')), 1)
        self.assertEqual(
            response.data.get('roles')[0]['uuid'], str(self.role.uuid))

    def test_read_group_invalid(self):
        """Test that reading an invalid group returns an error."""
        url = reverse('group-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_read_group_list_success(self):
        """Test that we can read a list of groups."""
        url = reverse('group-list')
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ['meta', 'links', 'data']:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get('data'), list)
        self.assertEqual(len(response.data.get('data')), 3)

        group = response.data.get('data')[0]
        self.assertIsNotNone(group.get('name'))
        self.assertEqual(group.get('name'), self.group.name)

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': []
        })
    def test_update_group_success(self, mock_request):
        """Test that we can update an existing group."""
        group = Group.objects.first()
        updated_name = group.name + '_update'
        test_data = {'name': updated_name}
        url = reverse('group-detail', kwargs={'uuid': group.uuid})
        client = APIClient()
        response = client.put(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        self.assertIsNotNone(response.data.get('uuid'))
        self.assertEqual(updated_name, response.data.get('name'))

    def test_update_group_invalid(self):
        """Test that updating an invalid group returns an error."""
        url = reverse('group-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.put(url, {}, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_group_success(self):
        """Test that we can delete an existing group."""
        group = Group.objects.first()
        url = reverse('group-detail', kwargs={'uuid': group.uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

        # verify the group no longer exists
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_default_group(self):
        """Test that platform_default groups are protected from deletion"""
        url = reverse('group-detail', kwargs={'uuid': self.defGroup.uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_delete_group_invalid(self):
        """Test that deleting an invalid group returns an error."""
        url = reverse('group-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_group_principals_invalid_method(self):
        """Test that using an unsupported REST method returns an error."""
        url = reverse('group-principals', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.put(url, {}, format='json', **self.headers)
        self.assertEqual(response.status_code,
                         status.HTTP_405_METHOD_NOT_ALLOWED)

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': []
        })
    def test_add_group_principals_success(self, mock_request):
        """Test that adding a principal to a group returns successfully."""
        url = reverse('group-principals', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        new_username = uuid4()
        test_data = {
            'principals': [{
                'username': self.principal.username
            }, {
                'username': new_username
            }]
        }
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        url = reverse('group-list')
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data.get('meta').get('count'), 3)
        self.assertEqual(response.data.get('data')[0].get('principalCount'), 1)
        self.assertEqual(response.data.get('data')[0].get('policyCount'), None)
        self.assertEqual(response.data.get('data')[0].get('roleCount'), 1)

    def test_remove_group_principals_success(self):
        """Test that removing a principal to a group returns successfully."""
        url = reverse('group-principals', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        url = '{}?usernames={}'.format(url, self.principal.username)
        response = client.delete(url, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_principals_invalid(self):
        """Test that removing a principal returns an error with invalid data format."""
        url = reverse('group-principals', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        response = client.delete(url, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': []
        })
    def test_get_group_by_username(self, mock_request):
        """Test that getting groups for a principalreturns successfully."""
        url = reverse('group-principals', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        new_username = uuid4()
        test_data = {
            'principals': [{
                'username': self.principal.username
            }, {
                'username': new_username
            }]
        }
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        url = reverse('group-list')
        url = '{}?username={}'.format(url, self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get('meta').get('count'), 3)

        url = reverse('group-list')
        url = '{}?username={}'.format(url, uuid4())
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get('meta').get('count'), 0)

    def test_get_group_roles_success(self):
        """Test that getting roles for a group returns successfully."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get('data')

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get('uuid'), str(self.role.uuid))
        self.assertEqual(roles[0].get('name'), self.role.name)
        self.assertEqual(roles[0].get('description'), self.role.description)

    def test_add_group_roles_system_policy_create_success(self):
        """Test that adding a role to a group without a system policy returns successfully."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        test_data = {'roles': [self.roleB.uuid, self.dummy_role_id]}

        self.assertCountEqual([self.role], list(self.group.roles()))
        self.assertCountEqual([self.policy], list(self.group.policies.all()))

        response = client.post(url, test_data, format='json', **self.headers)

        roles = response.data.get('data')
        system_policies = Policy.objects.filter(system=True)
        system_policy = system_policies.get(group=self.group)

        self.assertEqual(len(system_policies), 1)
        self.assertCountEqual([system_policy, self.policy],
                              list(self.group.policies.all()))
        self.assertCountEqual([self.roleB], list(system_policy.roles.all()))
        self.assertCountEqual([self.role], list(self.policy.roles.all()))
        self.assertCountEqual([self.role, self.roleB],
                              list(self.group.roles()))
        self.assertEqual(len(roles), 2)
        self.assertEqual(roles[0].get('uuid'), str(self.role.uuid))
        self.assertEqual(roles[0].get('name'), self.role.name)
        self.assertEqual(roles[0].get('description'), self.role.description)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_system_flag_update_on_add(self):
        """Test that adding a role to a platform_default group flips the system flag."""
        url = reverse('group-roles', kwargs={'uuid': self.defGroup.uuid})
        client = APIClient()
        test_data = {'roles': [self.roleB.uuid, self.dummy_role_id]}

        self.assertTrue(self.defGroup.system)
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.defGroup.refresh_from_db()
        self.assertFalse(self.defGroup.system)

    def test_system_flag_update_on_remove(self):
        """Test that removing a role from a platform_default group flips the system flag."""
        url = reverse('group-roles', kwargs={'uuid': self.defGroup.uuid})
        client = APIClient()
        url = '{}?roles={}'.format(url, self.roleB.uuid)

        self.policy.roles.add(self.roleB)
        self.policy.save()

        self.assertTrue(self.defGroup.system)
        response = client.delete(url, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.defGroup.refresh_from_db()
        self.assertFalse(self.defGroup.system)

    def test_add_group_roles_system_policy_create_new_group_success(self):
        """Test that adding a role to a group without a system policy returns successfully."""
        group_url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        groupB_url = reverse('group-roles', kwargs={'uuid': self.groupB.uuid})
        client = APIClient()
        test_data = {'roles': [self.roleB.uuid]}

        response = client.post(group_url,
                               test_data,
                               format='json',
                               **self.headers)
        responseB = client.post(groupB_url,
                                test_data,
                                format='json',
                                **self.headers)

        system_policies = Policy.objects.filter(system=True)
        system_policy = system_policies.get(group=self.group)
        system_policyB = system_policies.get(group=self.groupB)

        self.assertEqual(len(system_policies), 2)
        self.assertCountEqual([self.roleB], list(system_policy.roles.all()))
        self.assertCountEqual([self.roleB], list(system_policyB.roles.all()))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(responseB.status_code, status.HTTP_200_OK)

    def test_add_group_roles_system_policy_get_success(self):
        """Test that adding a role to a group with existing system policy returns successfully."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        test_data = {'roles': [self.roleB.uuid, self.dummy_role_id]}
        system_policy_name = 'System Policy for Group {}'.format(
            self.group.uuid)
        system_policy = Policy.objects.create(system=True,
                                              group=self.group,
                                              name=system_policy_name)

        self.assertCountEqual([self.role], list(self.group.roles()))
        self.assertCountEqual([system_policy, self.policy],
                              list(self.group.policies.all()))

        response = client.post(url, test_data, format='json', **self.headers)

        roles = response.data.get('data')
        system_policies = Policy.objects.filter(system=True, group=self.group)
        system_policy = system_policies.first()

        self.assertEqual(len(system_policies), 1)
        self.assertCountEqual([system_policy, self.policy],
                              list(self.group.policies.all()))
        self.assertCountEqual([self.roleB], list(system_policy.roles.all()))
        self.assertCountEqual([self.role], list(self.policy.roles.all()))
        self.assertCountEqual([self.role, self.roleB],
                              list(self.group.roles()))
        self.assertEqual(len(roles), 2)
        self.assertEqual(roles[0].get('uuid'), str(self.role.uuid))
        self.assertEqual(roles[0].get('name'), self.role.name)
        self.assertEqual(roles[0].get('description'), self.role.description)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_add_group_multiple_roles_success(self):
        """Test that adding multiple roles to a group returns successfully."""
        with tenant_context(self.tenant):
            groupC = Group.objects.create(name='groupC')
            url = reverse('group-roles', kwargs={'uuid': groupC.uuid})
            client = APIClient()
            test_data = {'roles': [self.role.uuid, self.roleB.uuid]}

            self.assertCountEqual([], list(groupC.roles()))

            response = client.post(url,
                                   test_data,
                                   format='json',
                                   **self.headers)

            self.assertCountEqual([self.role, self.roleB],
                                  list(groupC.roles()))
            self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_add_group_multiple_roles_invalid(self):
        """Test that adding invalid roles to a group fails the request and does not add any."""
        with tenant_context(self.tenant):
            groupC = Group.objects.create(name='groupC')
            url = reverse('group-roles', kwargs={'uuid': groupC.uuid})
            client = APIClient()
            test_data = {'roles': ['abc123', self.roleB.uuid]}

            self.assertCountEqual([], list(groupC.roles()))

            response = client.post(url,
                                   test_data,
                                   format='json',
                                   **self.headers)

            self.assertCountEqual([], list(groupC.roles()))
            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_add_group_multiple_roles_not_found_success(self):
        """Test that adding roles to a group skips ids not found, and returns success."""
        with tenant_context(self.tenant):
            groupC = Group.objects.create(name='groupC')
            url = reverse('group-roles', kwargs={'uuid': groupC.uuid})
            client = APIClient()
            test_data = {'roles': [self.dummy_role_id, self.roleB.uuid]}

            self.assertCountEqual([], list(groupC.roles()))

            response = client.post(url,
                                   test_data,
                                   format='json',
                                   **self.headers)

            self.assertCountEqual([self.roleB], list(groupC.roles()))
            self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_remove_group_roles_success(self):
        """Test that removing a role from a group returns successfully."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        url = '{}?roles={}'.format(url, self.role.uuid)

        self.policyB.roles.add(self.role)
        self.policyB.save()
        self.assertCountEqual([self.role], list(self.group.roles()))

        response = client.delete(url, format='json', **self.headers)

        self.assertCountEqual([], list(self.group.roles()))
        self.assertCountEqual([self.role, self.roleB],
                              list(self.groupB.roles()))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_multiple_roles_success(self):
        """Test that removing multiple roles from a group returns successfully."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        url = '{}?roles={},{}'.format(url, self.role.uuid, self.roleB.uuid)

        self.policy.roles.add(self.roleB)
        self.policy.save()
        self.assertCountEqual([self.role, self.roleB],
                              list(self.group.roles()))

        response = client.delete(url, format='json', **self.headers)

        self.assertCountEqual([], list(self.group.roles()))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_multiple_roles_invalid(self):
        """Test that removing invalid roles from a group fails the request and does not remove any."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        url = '{}?roles={},{}'.format(url, 'abc123', self.roleB.uuid)

        self.policy.roles.add(self.roleB)
        self.policy.save()
        self.assertCountEqual([self.role, self.roleB],
                              list(self.group.roles()))

        response = client.delete(url, format='json', **self.headers)

        self.assertCountEqual([self.role, self.roleB],
                              list(self.group.roles()))
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_remove_group_multiple_roles_not_found_success(self):
        """Test that removing roles from a group skips ids not found, and returns success."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        url = '{}?roles={},{},{}'.format(url, self.role.uuid, self.roleB.uuid,
                                         self.dummy_role_id)

        self.policy.roles.add(self.roleB)
        self.policy.save()
        self.assertCountEqual([self.role, self.roleB],
                              list(self.group.roles()))

        response = client.delete(url, format='json', **self.headers)

        self.assertCountEqual([], list(self.group.roles()))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_roles_invalid(self):
        """Test that removing a role returns an error with invalid data format."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()

        response = client.delete(url, format='json', **self.headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)