Beispiel #1
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()
Beispiel #2
0
def add_role(request):
    username = request.session.get('username', False)
    if username is False:
        return HttpResponseRedirect('login')
    if request.is_ajax() and request.method == 'POST':
        role_name = request.POST.get('role_name')
        if role_name is None:
            result = {'status': '0', 'info': '角色名不能为空!'}
        else:
            try:
                Role.objects.get(role_name=role_name)
            except ObjectDoesNotExist:
                r = Role(role_name=role_name)
                r.create_date = datetime.datetime.now()
                r.save()
            result = {'status': '1', 'info': '新角色创建成功!'}
        return HttpResponse(json.dumps(result),
                            content_type='application/json')
    return render(request, 'role/add.html')
Beispiel #3
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)
Beispiel #4
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:*:*")
Beispiel #5
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)
Beispiel #6
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)
Beispiel #7
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')[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_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')[0])

    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_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)
Beispiel #8
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', '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)

    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, 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_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')), 1)
        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_404_NOT_FOUND)

    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'
        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)

        # 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)

    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(reverse('role-list'), 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(
            reverse('role-list'), 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(
            reverse('role-list'), 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(reverse('role-list'), 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_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)