class GroupViewNonAdminTests(IdentityRequest): """Test the group view for nonadmin user.""" def setUp(self): """Set up the group view nonadmin tests.""" super().setUp() self.user_data = self._create_user_data() self.customer = self._create_customer_data() self.request_context = self._create_request_context(self.customer, self.user_data, is_org_admin=False) request = self.request_context["request"] self.headers = request.META self.access_data = { "permission": "app:*:*", "resourceDefinitions": [{ "attributeFilter": { "key": "key1", "operation": "equal", "value": "value1" } }], } with tenant_context(self.tenant): self.principal = Principal(username=self.user_data["username"]) self.principal.save() self.admin_principal = Principal(username="******") self.admin_principal.save() self.group = Group(name="groupA") self.group.save() self.group.principals.add(self.principal) self.group.save() def tearDown(self): """Tear down group view tests.""" with tenant_context(self.tenant): Group.objects.all().delete() Principal.objects.all().delete() Role.objects.all().delete() Policy.objects.all().delete() def test_nonadmin_RonR_list(self): """Test that a nonadmin user can list groups in tenant""" url = "{}?application={}".format(reverse("group-list"), "rbac") client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_nonadmin_RonR_retrieve(self): """Test that a nonadmin user can't retrieve group RBAC resources""" url = reverse("group-detail", kwargs={"uuid": self.group.uuid}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
class GroupViewNonAdminTests(IdentityRequest): """Test the group view for nonadmin user.""" def setUp(self): """Set up the group view nonadmin tests.""" super().setUp() self.user_data = self._create_user_data() self.customer = self._create_customer_data() self.request_context = self._create_request_context(self.customer, self.user_data, is_org_admin=False) request = self.request_context['request'] self.headers = request.META self.access_data = { 'permission': 'app:*:*', 'resourceDefinitions': [{ 'attributeFilter': { 'key': 'key1', 'operation': 'equal', 'value': 'value1' } }] } with tenant_context(self.tenant): self.principal = Principal(username=self.user_data['username']) self.principal.save() self.admin_principal = Principal(username="******") self.admin_principal.save() self.group = Group(name='groupA') self.group.save() self.group.principals.add(self.principal) self.group.save() def tearDown(self): """Tear down group view tests.""" with tenant_context(self.tenant): Group.objects.all().delete() Principal.objects.all().delete() Role.objects.all().delete() Policy.objects.all().delete() def test_nonadmin_RonR_list(self): """Test that a nonadmin user can list groups in tenant""" url = '{}?application={}'.format(reverse('group-list'), 'rbac') client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_nonadmin_RonR_retrieve(self): """Test that a nonadmin user can't retrieve group RBAC resources""" url = reverse('group-detail', kwargs={'uuid': self.group.uuid}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
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)
class AccessViewTests(IdentityRequest): """Test the access view.""" def setUp(self): """Set up the access view tests.""" super().setUp() request = self.request_context["request"] user = User() user.username = self.user_data["username"] user.account = self.customer_data["account_id"] request.user = user self.access_data = { "permission": "app:*:*", "resourceDefinitions": [{ "attributeFilter": { "key": "key1", "operation": "equal", "value": "value1" } }], } with tenant_context(self.tenant): self.principal = Principal(username=self.user_data["username"]) self.principal.save() self.admin_principal = Principal(username="******") self.admin_principal.save() self.group = Group(name="groupA") self.group.save() self.group.principals.add(self.principal) self.group.save() def tearDown(self): """Tear down access view tests.""" with tenant_context(self.tenant): Group.objects.all().delete() Principal.objects.all().delete() Role.objects.all().delete() Policy.objects.all().delete() def create_role(self, role_name, in_access_data=None): """Create a role.""" access_data = self.access_data if in_access_data: access_data = in_access_data test_data = {"name": role_name, "access": [access_data]} # create a role url = reverse("role-list") client = APIClient() response = client.post(url, test_data, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_201_CREATED) return response def create_policy(self, policy_name, group, roles, status=status.HTTP_201_CREATED): """Create a policy.""" # create a policy test_data = {"name": policy_name, "group": group, "roles": roles} url = reverse("policy-list") client = APIClient() response = client.post(url, test_data, format="json", **self.headers) self.assertEqual(response.status_code, status) return response def test_get_access_success(self): """Test that we can obtain the expected access without pagination.""" role_name = "roleA" response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get("uuid") role = Role.objects.get(uuid=role_uuid) access = Access.objects.create(role=role, permission="app2:foo:bar") policy_name = "policyA" response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) # test that we can retrieve the principal access url = "{}?application={}&username={}".format(reverse("access"), "app", self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get("data")) self.assertIsInstance(response.data.get("data"), list) self.assertEqual(len(response.data.get("data")), 1) self.assertEqual(response.data.get("meta").get("limit"), 1000) self.assertEqual(self.access_data, response.data.get("data")[0]) def test_get_access_no_app_supplied(self): """Test that we return all permissions when no app supplied.""" role_name = "roleA" policy_name = "policyA" access_data = { "permission": "app:foo:bar", "resourceDefinitions": [{ "attributeFilter": { "key": "keyA", "operation": "equal", "value": "valueA" } }], } response = self.create_role(role_name, access_data) role_uuid = response.data.get("uuid") role = Role.objects.get(uuid=role_uuid) access = Access.objects.create(role=role, permission="app2:foo:bar") self.create_policy(policy_name, self.group.uuid, [role_uuid]) url = "{}?application=&username={}".format(reverse("access"), self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get("data")) self.assertIsInstance(response.data.get("data"), list) self.assertEqual(len(response.data.get("data")), 2) self.assertEqual(response.data.get("meta").get("limit"), 1000) def test_get_access_multiple_apps_supplied(self): """Test that we return all permissions for multiple apps when supplied.""" role_name = "roleA" policy_name = "policyA" access_data = { "permission": "app:foo:bar", "resourceDefinitions": [{ "attributeFilter": { "key": "keyA", "operation": "equal", "value": "valueA" } }], } response = self.create_role(role_name, access_data) role_uuid = response.data.get("uuid") role = Role.objects.get(uuid=role_uuid) access = Access.objects.create(role=role, permission="app2:foo:bar") self.create_policy(policy_name, self.group.uuid, [role_uuid]) url = "{}?application={}&username={}".format(reverse("access"), "app,app2", self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsInstance(response.data.get("data"), list) self.assertEqual(len(response.data.get("data")), 2) def test_get_access_no_partial_match(self): """Test that we can have a partial match on app/permission.""" role_name = "roleA" policy_name = "policyA" access_data = { "permission": "app:foo:bar", "resourceDefinitions": [{ "attributeFilter": { "key": "keyA", "operation": "equal", "value": "valueA" } }], } response = self.create_role(role_name, access_data) role_uuid = response.data.get("uuid") self.create_policy(policy_name, self.group.uuid, [role_uuid]) url = "{}?application={}&username={}".format(reverse("access"), "ap", self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get("data")) self.assertIsInstance(response.data.get("data"), list) self.assertEqual(len(response.data.get("data")), 0) self.assertEqual(response.data.get("meta").get("limit"), 1000) def test_get_access_no_match(self): """Test that we only match on the application name of the permission data.""" role_name = "roleA" policy_name = "policyA" access_data = { "permission": "app:foo:bar", "resourceDefinitions": [{ "attributeFilter": { "key": "keyA", "operation": "equal", "value": "valueA" } }], } response = self.create_role(role_name, access_data) role_uuid = response.data.get("uuid") self.create_policy(policy_name, self.group.uuid, [role_uuid]) url = "{}?application={}&username={}".format(reverse("access"), "foo", self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get("data")) self.assertIsInstance(response.data.get("data"), list) self.assertEqual(len(response.data.get("data")), 0) self.assertEqual(response.data.get("meta").get("limit"), 1000) def test_get_access_with_limit(self): """Test that we can obtain the expected access with pagination.""" role_name = "roleA" response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get("uuid") policy_name = "policyA" response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) # test that we can retrieve the principal access url = "{}?application={}&username={}&limit=1".format( reverse("access"), "app", self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get("data")) self.assertIsInstance(response.data.get("data"), list) self.assertEqual(len(response.data.get("data")), 1) self.assertEqual(response.data.get("meta").get("count"), 1) self.assertEqual(response.data.get("meta").get("limit"), 1) self.assertEqual(self.access_data, response.data.get("data")[0]) def test_missing_query_params(self): """Test that we get expected failure when missing required query params.""" url = "{}?page={}".format(reverse("access"), "3") client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @patch( "management.principal.proxy.PrincipalProxy.request_filtered_principals", return_value={ "status_code": 200, "data": [] }, ) def test_missing_invalid_username(self, mock_request): """Test that we get expected failure when missing required query params.""" url = "{}?application={}&username={}".format(reverse("access"), "app", uuid4()) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
class AccessViewTests(IdentityRequest): """Test the access view.""" def setUp(self): """Set up the access view tests.""" super().setUp() request = self.request_context['request'] user = User() user.username = self.user_data['username'] user.account = self.customer_data['account_id'] request.user = user self.access_data = { 'permission': 'app:*:*', 'resourceDefinitions': [{ 'attributeFilter': { 'key': 'key1', 'operation': 'equal', 'value': 'value1' } }] } with tenant_context(self.tenant): self.principal = Principal(username=self.user_data['username']) self.principal.save() self.admin_principal = Principal(username="******") self.admin_principal.save() self.group = Group(name='groupA') self.group.save() self.group.principals.add(self.principal) self.group.save() def tearDown(self): """Tear down access view tests.""" with tenant_context(self.tenant): Group.objects.all().delete() Principal.objects.all().delete() Role.objects.all().delete() Policy.objects.all().delete() def create_role(self, role_name, in_access_data=None): """Create a role.""" access_data = self.access_data if in_access_data: access_data = in_access_data test_data = {'name': role_name, 'access': [access_data]} # create a role url = reverse('role-list') client = APIClient() response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_201_CREATED) return response def create_policy(self, policy_name, group, roles, status=status.HTTP_201_CREATED): """Create a policy.""" # create a policy test_data = {'name': policy_name, 'group': group, 'roles': roles} url = reverse('policy-list') client = APIClient() response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status) return response def test_get_access_success(self): """Test that we can obtain the expected access without pagination.""" role_name = 'roleA' response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get('uuid') role = Role.objects.get(uuid=role_uuid) access = Access.objects.create(role=role, permission='app2:foo:bar') policy_name = 'policyA' response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) # test that we can retrieve the principal access url = '{}?application={}&username={}'.format(reverse('access'), 'app', self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get('data')) self.assertIsInstance(response.data.get('data'), list) self.assertEqual(len(response.data.get('data')), 1) self.assertEqual(response.data.get('meta').get('limit'), 1000) self.assertEqual(self.access_data, response.data.get('data')[0]) def test_get_access_no_app_supplied(self): """Test that we return all permissions when no app supplied.""" role_name = 'roleA' policy_name = 'policyA' access_data = { 'permission': 'app:foo:bar', 'resourceDefinitions': [{ 'attributeFilter': { 'key': 'keyA', 'operation': 'equal', 'value': 'valueA' } }] } response = self.create_role(role_name, access_data) role_uuid = response.data.get('uuid') role = Role.objects.get(uuid=role_uuid) access = Access.objects.create(role=role, permission='app2:foo:bar') self.create_policy(policy_name, self.group.uuid, [role_uuid]) url = '{}?application=&username={}'.format(reverse('access'), self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get('data')) self.assertIsInstance(response.data.get('data'), list) self.assertEqual(len(response.data.get('data')), 2) self.assertEqual(response.data.get('meta').get('limit'), 1000) def test_get_access_multiple_apps_supplied(self): """Test that we return all permissions for multiple apps when supplied.""" role_name = 'roleA' policy_name = 'policyA' access_data = { 'permission': 'app:foo:bar', 'resourceDefinitions': [{ 'attributeFilter': { 'key': 'keyA', 'operation': 'equal', 'value': 'valueA' } }] } response = self.create_role(role_name, access_data) role_uuid = response.data.get('uuid') role = Role.objects.get(uuid=role_uuid) access = Access.objects.create(role=role, permission='app2:foo:bar') self.create_policy(policy_name, self.group.uuid, [role_uuid]) url = '{}?application={}&username={}'.format(reverse('access'), 'app,app2', self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsInstance(response.data.get('data'), list) self.assertEqual(len(response.data.get('data')), 2) def test_get_access_no_partial_match(self): """Test that we can have a partial match on app/permission.""" role_name = 'roleA' policy_name = 'policyA' access_data = { 'permission': 'app:foo:bar', 'resourceDefinitions': [{ 'attributeFilter': { 'key': 'keyA', 'operation': 'equal', 'value': 'valueA' } }] } response = self.create_role(role_name, access_data) role_uuid = response.data.get('uuid') self.create_policy(policy_name, self.group.uuid, [role_uuid]) url = '{}?application={}&username={}'.format(reverse('access'), 'ap', self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get('data')) self.assertIsInstance(response.data.get('data'), list) self.assertEqual(len(response.data.get('data')), 0) self.assertEqual(response.data.get('meta').get('limit'), 1000) def test_get_access_no_match(self): """Test that we only match on the application name of the permission data.""" role_name = 'roleA' policy_name = 'policyA' access_data = { 'permission': 'app:foo:bar', 'resourceDefinitions': [{ 'attributeFilter': { 'key': 'keyA', 'operation': 'equal', 'value': 'valueA' } }] } response = self.create_role(role_name, access_data) role_uuid = response.data.get('uuid') self.create_policy(policy_name, self.group.uuid, [role_uuid]) url = '{}?application={}&username={}'.format(reverse('access'), 'foo', self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get('data')) self.assertIsInstance(response.data.get('data'), list) self.assertEqual(len(response.data.get('data')), 0) self.assertEqual(response.data.get('meta').get('limit'), 1000) def test_get_access_with_limit(self): """Test that we can obtain the expected access with pagination.""" role_name = 'roleA' response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get('uuid') policy_name = 'policyA' response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) # test that we can retrieve the principal access url = '{}?application={}&username={}&limit=1'.format( reverse('access'), 'app', self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get('data')) self.assertIsInstance(response.data.get('data'), list) self.assertEqual(len(response.data.get('data')), 1) self.assertEqual(response.data.get('meta').get('count'), 1) self.assertEqual(response.data.get('meta').get('limit'), 1) self.assertEqual(self.access_data, response.data.get('data')[0]) def test_missing_query_params(self): """Test that we get expected failure when missing required query params.""" url = '{}?page={}'.format(reverse('access'), '3') client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @patch( 'management.principal.proxy.PrincipalProxy.request_filtered_principals', return_value={ 'status_code': 200, 'data': [] }) def test_missing_invalid_username(self, mock_request): """Test that we get expected failure when missing required query params.""" url = '{}?application={}&username={}'.format(reverse('access'), 'app', uuid4()) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
class GroupViewsetTests(IdentityRequest): """Test the group viewset.""" def setUp(self): """Set up the group viewset tests.""" super().setUp() request = self.request_context['request'] user = User(username=self.user_data['username'], tenant=self.tenant) user.save() request.user = user self.dummy_role_id = uuid4() with tenant_context(self.tenant): self.principal = Principal(username=self.user_data['username']) self.principal.save() self.group = Group(name='groupA') self.group.save() self.role = Role.objects.create(name='roleA') self.policy = Policy.objects.create(name='policyA', group=self.group) self.policy.roles.add(self.role) self.policy.save() self.group.policies.add(self.policy) self.group.principals.add(self.principal) self.group.save() self.defGroup = Group(name='groupDef', platform_default=True, system=True) self.defGroup.save() self.defGroup.principals.add(self.principal) self.defGroup.save() self.groupB = Group.objects.create(name='groupB') self.groupB.principals.add(self.principal) self.policyB = Policy.objects.create(name='policyB', group=self.groupB) self.roleB = Role.objects.create(name='roleB') self.policyB.roles.add(self.roleB) self.policyB.save() def tearDown(self): """Tear down group viewset tests.""" User.objects.all().delete() with tenant_context(self.tenant): Group.objects.all().delete() Principal.objects.all().delete() Role.objects.all().delete() Policy.objects.all().delete() @patch( 'management.principal.proxy.PrincipalProxy.request_filtered_principals', return_value={ 'status_code': 200, 'data': [] }) def test_create_group_success(self, mock_request): """Test that we can create a group.""" group_name = 'groupC' test_data = {'name': group_name} # create a group url = reverse('group-list') client = APIClient() response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_201_CREATED) # test that we can retrieve the group url = reverse('group-detail', kwargs={'uuid': response.data.get('uuid')}) response = client.get(url, **self.headers) self.assertIsNotNone(response.data.get('uuid')) self.assertIsNotNone(response.data.get('name')) self.assertEqual(group_name, response.data.get('name')) def test_create_default_group(self): """Test that system groups can be created.""" group_name = 'groupDef' # test group retrieval client = APIClient() url = reverse('group-detail', kwargs={'uuid': self.defGroup.uuid}) response = client.get(url, **self.headers) self.assertIsNotNone(response.data.get('uuid')) self.assertIsNotNone(response.data.get('name')) self.assertTrue(response.data.get('platform_default')) self.assertEqual(group_name, response.data.get('name')) def test_create_group_invalid(self): """Test that creating an invalid group returns an error.""" test_data = {} url = reverse('group-list') client = APIClient() response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @patch( 'management.principal.proxy.PrincipalProxy.request_filtered_principals', return_value={ 'status_code': 200, 'data': [] }) def test_read_group_success(self, mock_request): """Test that we can read a group.""" url = reverse('group-detail', kwargs={'uuid': self.group.uuid}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get('name')) self.assertEqual(self.group.name, response.data.get('name')) self.assertEqual(len(response.data.get('roles')), 1) self.assertEqual( response.data.get('roles')[0]['uuid'], str(self.role.uuid)) def test_read_group_invalid(self): """Test that reading an invalid group returns an error.""" url = reverse('group-detail', kwargs={'uuid': uuid4()}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_read_group_list_success(self): """Test that we can read a list of groups.""" url = reverse('group-list') client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) for keyname in ['meta', 'links', 'data']: self.assertIn(keyname, response.data) self.assertIsInstance(response.data.get('data'), list) self.assertEqual(len(response.data.get('data')), 3) group = response.data.get('data')[0] self.assertIsNotNone(group.get('name')) self.assertEqual(group.get('name'), self.group.name) @patch( 'management.principal.proxy.PrincipalProxy.request_filtered_principals', return_value={ 'status_code': 200, 'data': [] }) def test_update_group_success(self, mock_request): """Test that we can update an existing group.""" group = Group.objects.first() updated_name = group.name + '_update' test_data = {'name': updated_name} url = reverse('group-detail', kwargs={'uuid': group.uuid}) client = APIClient() response = client.put(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get('uuid')) self.assertEqual(updated_name, response.data.get('name')) def test_update_group_invalid(self): """Test that updating an invalid group returns an error.""" url = reverse('group-detail', kwargs={'uuid': uuid4()}) client = APIClient() response = client.put(url, {}, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_delete_group_success(self): """Test that we can delete an existing group.""" group = Group.objects.first() url = reverse('group-detail', kwargs={'uuid': group.uuid}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) # verify the group no longer exists response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_delete_default_group(self): """Test that platform_default groups are protected from deletion""" url = reverse('group-detail', kwargs={'uuid': self.defGroup.uuid}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_delete_group_invalid(self): """Test that deleting an invalid group returns an error.""" url = reverse('group-detail', kwargs={'uuid': uuid4()}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_group_principals_invalid_method(self): """Test that using an unsupported REST method returns an error.""" url = reverse('group-principals', kwargs={'uuid': uuid4()}) client = APIClient() response = client.put(url, {}, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) @patch( 'management.principal.proxy.PrincipalProxy.request_filtered_principals', return_value={ 'status_code': 200, 'data': [] }) def test_add_group_principals_success(self, mock_request): """Test that adding a principal to a group returns successfully.""" url = reverse('group-principals', kwargs={'uuid': self.group.uuid}) client = APIClient() new_username = uuid4() test_data = { 'principals': [{ 'username': self.principal.username }, { 'username': new_username }] } response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) url = reverse('group-list') response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data.get('meta').get('count'), 3) self.assertEqual(response.data.get('data')[0].get('principalCount'), 1) self.assertEqual(response.data.get('data')[0].get('policyCount'), None) self.assertEqual(response.data.get('data')[0].get('roleCount'), 1) def test_remove_group_principals_success(self): """Test that removing a principal to a group returns successfully.""" url = reverse('group-principals', kwargs={'uuid': self.group.uuid}) client = APIClient() url = '{}?usernames={}'.format(url, self.principal.username) response = client.delete(url, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_remove_group_principals_invalid(self): """Test that removing a principal returns an error with invalid data format.""" url = reverse('group-principals', kwargs={'uuid': self.group.uuid}) client = APIClient() response = client.delete(url, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @patch( 'management.principal.proxy.PrincipalProxy.request_filtered_principals', return_value={ 'status_code': 200, 'data': [] }) def test_get_group_by_username(self, mock_request): """Test that getting groups for a principalreturns successfully.""" url = reverse('group-principals', kwargs={'uuid': self.group.uuid}) client = APIClient() new_username = uuid4() test_data = { 'principals': [{ 'username': self.principal.username }, { 'username': new_username }] } response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) url = reverse('group-list') url = '{}?username={}'.format(url, self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.data.get('meta').get('count'), 3) url = reverse('group-list') url = '{}?username={}'.format(url, uuid4()) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.data.get('meta').get('count'), 0) def test_get_group_roles_success(self): """Test that getting roles for a group returns successfully.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get('data') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 1) self.assertEqual(roles[0].get('uuid'), str(self.role.uuid)) self.assertEqual(roles[0].get('name'), self.role.name) self.assertEqual(roles[0].get('description'), self.role.description) def test_add_group_roles_system_policy_create_success(self): """Test that adding a role to a group without a system policy returns successfully.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) client = APIClient() test_data = {'roles': [self.roleB.uuid, self.dummy_role_id]} self.assertCountEqual([self.role], list(self.group.roles())) self.assertCountEqual([self.policy], list(self.group.policies.all())) response = client.post(url, test_data, format='json', **self.headers) roles = response.data.get('data') system_policies = Policy.objects.filter(system=True) system_policy = system_policies.get(group=self.group) self.assertEqual(len(system_policies), 1) self.assertCountEqual([system_policy, self.policy], list(self.group.policies.all())) self.assertCountEqual([self.roleB], list(system_policy.roles.all())) self.assertCountEqual([self.role], list(self.policy.roles.all())) self.assertCountEqual([self.role, self.roleB], list(self.group.roles())) self.assertEqual(len(roles), 2) self.assertEqual(roles[0].get('uuid'), str(self.role.uuid)) self.assertEqual(roles[0].get('name'), self.role.name) self.assertEqual(roles[0].get('description'), self.role.description) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_system_flag_update_on_add(self): """Test that adding a role to a platform_default group flips the system flag.""" url = reverse('group-roles', kwargs={'uuid': self.defGroup.uuid}) client = APIClient() test_data = {'roles': [self.roleB.uuid, self.dummy_role_id]} self.assertTrue(self.defGroup.system) response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.defGroup.refresh_from_db() self.assertFalse(self.defGroup.system) def test_system_flag_update_on_remove(self): """Test that removing a role from a platform_default group flips the system flag.""" url = reverse('group-roles', kwargs={'uuid': self.defGroup.uuid}) client = APIClient() url = '{}?roles={}'.format(url, self.roleB.uuid) self.policy.roles.add(self.roleB) self.policy.save() self.assertTrue(self.defGroup.system) response = client.delete(url, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) self.defGroup.refresh_from_db() self.assertFalse(self.defGroup.system) def test_add_group_roles_system_policy_create_new_group_success(self): """Test that adding a role to a group without a system policy returns successfully.""" group_url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) groupB_url = reverse('group-roles', kwargs={'uuid': self.groupB.uuid}) client = APIClient() test_data = {'roles': [self.roleB.uuid]} response = client.post(group_url, test_data, format='json', **self.headers) responseB = client.post(groupB_url, test_data, format='json', **self.headers) system_policies = Policy.objects.filter(system=True) system_policy = system_policies.get(group=self.group) system_policyB = system_policies.get(group=self.groupB) self.assertEqual(len(system_policies), 2) self.assertCountEqual([self.roleB], list(system_policy.roles.all())) self.assertCountEqual([self.roleB], list(system_policyB.roles.all())) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(responseB.status_code, status.HTTP_200_OK) def test_add_group_roles_system_policy_get_success(self): """Test that adding a role to a group with existing system policy returns successfully.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) client = APIClient() test_data = {'roles': [self.roleB.uuid, self.dummy_role_id]} system_policy_name = 'System Policy for Group {}'.format( self.group.uuid) system_policy = Policy.objects.create(system=True, group=self.group, name=system_policy_name) self.assertCountEqual([self.role], list(self.group.roles())) self.assertCountEqual([system_policy, self.policy], list(self.group.policies.all())) response = client.post(url, test_data, format='json', **self.headers) roles = response.data.get('data') system_policies = Policy.objects.filter(system=True, group=self.group) system_policy = system_policies.first() self.assertEqual(len(system_policies), 1) self.assertCountEqual([system_policy, self.policy], list(self.group.policies.all())) self.assertCountEqual([self.roleB], list(system_policy.roles.all())) self.assertCountEqual([self.role], list(self.policy.roles.all())) self.assertCountEqual([self.role, self.roleB], list(self.group.roles())) self.assertEqual(len(roles), 2) self.assertEqual(roles[0].get('uuid'), str(self.role.uuid)) self.assertEqual(roles[0].get('name'), self.role.name) self.assertEqual(roles[0].get('description'), self.role.description) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_add_group_multiple_roles_success(self): """Test that adding multiple roles to a group returns successfully.""" with tenant_context(self.tenant): groupC = Group.objects.create(name='groupC') url = reverse('group-roles', kwargs={'uuid': groupC.uuid}) client = APIClient() test_data = {'roles': [self.role.uuid, self.roleB.uuid]} self.assertCountEqual([], list(groupC.roles())) response = client.post(url, test_data, format='json', **self.headers) self.assertCountEqual([self.role, self.roleB], list(groupC.roles())) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_add_group_multiple_roles_invalid(self): """Test that adding invalid roles to a group fails the request and does not add any.""" with tenant_context(self.tenant): groupC = Group.objects.create(name='groupC') url = reverse('group-roles', kwargs={'uuid': groupC.uuid}) client = APIClient() test_data = {'roles': ['abc123', self.roleB.uuid]} self.assertCountEqual([], list(groupC.roles())) response = client.post(url, test_data, format='json', **self.headers) self.assertCountEqual([], list(groupC.roles())) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_add_group_multiple_roles_not_found_success(self): """Test that adding roles to a group skips ids not found, and returns success.""" with tenant_context(self.tenant): groupC = Group.objects.create(name='groupC') url = reverse('group-roles', kwargs={'uuid': groupC.uuid}) client = APIClient() test_data = {'roles': [self.dummy_role_id, self.roleB.uuid]} self.assertCountEqual([], list(groupC.roles())) response = client.post(url, test_data, format='json', **self.headers) self.assertCountEqual([self.roleB], list(groupC.roles())) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_remove_group_roles_success(self): """Test that removing a role from a group returns successfully.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) client = APIClient() url = '{}?roles={}'.format(url, self.role.uuid) self.policyB.roles.add(self.role) self.policyB.save() self.assertCountEqual([self.role], list(self.group.roles())) response = client.delete(url, format='json', **self.headers) self.assertCountEqual([], list(self.group.roles())) self.assertCountEqual([self.role, self.roleB], list(self.groupB.roles())) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_remove_group_multiple_roles_success(self): """Test that removing multiple roles from a group returns successfully.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) client = APIClient() url = '{}?roles={},{}'.format(url, self.role.uuid, self.roleB.uuid) self.policy.roles.add(self.roleB) self.policy.save() self.assertCountEqual([self.role, self.roleB], list(self.group.roles())) response = client.delete(url, format='json', **self.headers) self.assertCountEqual([], list(self.group.roles())) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_remove_group_multiple_roles_invalid(self): """Test that removing invalid roles from a group fails the request and does not remove any.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) client = APIClient() url = '{}?roles={},{}'.format(url, 'abc123', self.roleB.uuid) self.policy.roles.add(self.roleB) self.policy.save() self.assertCountEqual([self.role, self.roleB], list(self.group.roles())) response = client.delete(url, format='json', **self.headers) self.assertCountEqual([self.role, self.roleB], list(self.group.roles())) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_remove_group_multiple_roles_not_found_success(self): """Test that removing roles from a group skips ids not found, and returns success.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) client = APIClient() url = '{}?roles={},{},{}'.format(url, self.role.uuid, self.roleB.uuid, self.dummy_role_id) self.policy.roles.add(self.roleB) self.policy.save() self.assertCountEqual([self.role, self.roleB], list(self.group.roles())) response = client.delete(url, format='json', **self.headers) self.assertCountEqual([], list(self.group.roles())) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_remove_group_roles_invalid(self): """Test that removing a role returns an error with invalid data format.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) client = APIClient() response = client.delete(url, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
class InternalViewsetTests(IdentityRequest): """Test the internal viewset.""" def valid_destructive_time(): return datetime.utcnow().replace(tzinfo=pytz.UTC) + timedelta(hours=1) def invalid_destructive_time(): return datetime.utcnow().replace(tzinfo=pytz.UTC) - timedelta(hours=1) def setUp(self): """Set up the internal viewset tests.""" super().setUp() self.client = APIClient() self.customer = self._create_customer_data() self.internal_request_context = self._create_request_context( self.customer, self.user_data, create_customer=False, is_internal=True, create_tenant=True) self.request = self.internal_request_context["request"] user = User() user.username = self.user_data["username"] user.account = self.customer_data["account_id"] self.request.user = user with tenant_context(self.tenant): self.group = Group(name="System Group", system=True) self.group.save() self.role = Role.objects.create(name="System Role", description="A role for a group.", system=True) self.policy = Policy.objects.create(name="System Policy", group=self.group) self.policy.roles.add(self.role) self.policy.save() self.group.policies.add(self.policy) self.group.save() def tearDown(self): """Tear down internal viewset tests.""" with tenant_context(self.tenant): Group.objects.all().delete() Role.objects.all().delete() Policy.objects.all().delete() def test_delete_tenant_disallowed(self): """Test that we cannot delete a tenant when disallowed.""" response = self.client.delete( f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.content.decode(), "Destructive operations disallowed.") @override_settings( INTERNAL_DESTRUCTIVE_API_OK_UNTIL=invalid_destructive_time()) def test_delete_tenant_disallowed_with_past_timestamp(self): """Test that we cannot delete a tenant when disallowed.""" response = self.client.delete( f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.content.decode(), "Destructive operations disallowed.") @override_settings( INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time()) @patch.object(Tenant, "delete") def test_delete_tenant_allowed_and_unmodified(self, mock): """Test that we can delete a tenant when allowed and unmodified.""" response = self.client.delete( f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) @override_settings( INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time()) def test_delete_tenant_allowed_but_multiple_groups(self): """Test that we cannot delete a tenant when allowed but modified.""" with tenant_context(self.tenant): Group.objects.create(name="Custom Group") response = self.client.delete( f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.content.decode(), "Tenant cannot be deleted.") @override_settings( INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time()) def test_delete_tenant_allowed_but_group_is_not_system(self): """Test that we cannot delete a tenant when allowed but modified.""" with tenant_context(self.tenant): self.group.system = False self.group.save() response = self.client.delete( f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.content.decode(), "Tenant cannot be deleted.") @override_settings( INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time()) def test_delete_tenant_allowed_but_role_is_not_system(self): """Test that we cannot delete a tenant when allowed but modified.""" with tenant_context(self.tenant): self.role.system = False self.role.save() response = self.client.delete( f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.content.decode(), "Tenant cannot be deleted.") @override_settings( INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time()) def test_delete_tenant_allowed_but_custom_one_role_is_not_system(self): """Test that we cannot delete a tenant when allowed but modified.""" with tenant_context(self.tenant): Role.objects.create(name="Custom Role") response = self.client.delete( f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.content.decode(), "Tenant cannot be deleted.") def test_list_unmodified_tenants(self): """Test that only unmodified tenants are returned""" modified_tenant_groups = Tenant.objects.create( schema_name="acctmodifiedgroups") modified_tenant_roles = Tenant.objects.create( schema_name="acctmodifiedroles") unmodified_tenant_2 = Tenant.objects.create( schema_name="acctunmodified2") with tenant_context(modified_tenant_groups): Group.objects.create(name="Custom Group") with tenant_context(modified_tenant_roles): Role.objects.create(name="Custom Role") with tenant_context(unmodified_tenant_2): Group.objects.create(name="System Group", system=True) Role.objects.create(name="System Role", system=True) response = self.client.get(f"/_private/api/tenant/unmodified/", **self.request.META) response_data = json.loads(response.content) self.assertCountEqual( response_data["unmodified_tenants"], [self.tenant.schema_name, unmodified_tenant_2.schema_name]) self.assertEqual(response_data["unmodified_tenants_count"], 2) self.assertEqual(response_data["total_tenants_count"], 4) self.assertEqual(Tenant.objects.count(), 4)
class AccessViewTests(IdentityRequest): """Test the access view.""" def setUp(self): """Set up the access view tests.""" super().setUp() request = self.request_context["request"] user = User() user.username = self.user_data["username"] user.account = self.customer_data["account_id"] request.user = user self.access_data = { "permission": "app:*:*", "resourceDefinitions": [{ "attributeFilter": { "key": "key1", "operation": "equal", "value": "value1" } }], } with tenant_context(self.tenant): self.principal = Principal(username=self.user_data["username"]) self.principal.save() self.admin_principal = Principal(username="******") self.admin_principal.save() self.group = Group(name="groupA") self.group.save() self.group.principals.add(self.principal) self.group.save() self.permission = Permission.objects.create(permission="app:*:*") Permission.objects.create(permission="app:foo:bar") def tearDown(self): """Tear down access view tests.""" with tenant_context(self.tenant): Group.objects.all().delete() Principal.objects.all().delete() Role.objects.all().delete() Policy.objects.all().delete() def create_role(self, role_name, in_access_data=None): """Create a role.""" access_data = self.access_data if in_access_data: access_data = in_access_data test_data = {"name": role_name, "access": [access_data]} # create a role url = reverse("role-list") client = APIClient() response = client.post(url, test_data, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_201_CREATED) return response def create_policy(self, policy_name, group, roles, status=status.HTTP_201_CREATED): """Create a policy.""" # create a policy test_data = {"name": policy_name, "group": group, "roles": roles} url = reverse("policy-list") client = APIClient() response = client.post(url, test_data, format="json", **self.headers) self.assertEqual(response.status_code, status) return response def create_platform_default_resource(self): """Setup default group and role.""" with tenant_context(self.tenant): default_permission = Permission.objects.create( permission="default:*:*") default_role = Role.objects.create(name="default role", platform_default=True, system=True) default_access = Access.objects.create( permission=default_permission, role=default_role) default_policy = Policy.objects.create(name="default policy", system=True) default_policy.roles.add(default_role) default_group = Group.objects.create(name="default group", system=True, platform_default=True) default_group.policies.add(default_policy) def create_role_and_permission(self, role_name, permission): role = Role.objects.create(name=role_name) assigned_permission = Permission.objects.create(permission=permission) access = Access.objects.create(role=role, permission=assigned_permission) return role def test_get_access_success(self): """Test that we can obtain the expected access without pagination.""" role_name = "roleA" response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get("uuid") role = Role.objects.get(uuid=role_uuid) access = Access.objects.create(role=role, permission=self.permission) policy_name = "policyA" response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) # Create platform default group, and add roles to it. self.create_platform_default_resource() # Test that we can retrieve the principal access url = "{}?application={}".format(reverse("access"), "app") client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get("data")) self.assertIsInstance(response.data.get("data"), list) self.assertEqual(len(response.data.get("data")), 2) self.assertEqual(response.data.get("meta").get("limit"), 1000) self.assertEqual(self.access_data, response.data.get("data")[0]) # the platform default permission could also be retrieved url = "{}?application={}".format(reverse("access"), "default") response = client.get(url, **self.headers) self.assertEqual( { "permission": "default:*:*", "resourceDefinitions": [] }, response.data.get("data")[0]) def test_access_for_cross_account_principal_return_permissions_based_on_assigned_role( self): """Test that the expected access for cross account principal return permissions based on assigned role.""" # setup default group/role self.create_platform_default_resource() client = APIClient() url = "{}?application=".format(reverse("access")) account_id = self.customer_data["account_id"] user_id = "123456" user_name = f"{account_id}-{user_id}" # setup cross account request, role and permission in public schema ## This CAR will provide permission: "test:assigned:permission" role = self.create_role_and_permission("Test Role one", "test:assigned:permission1") cross_account_request = CrossAccountRequest.objects.create( target_account=account_id, user_id=user_id, end_date=timezone.now() + timedelta(10), status="approved") cross_account_request.roles.add(role) ## CAR below will provide permission: "app:*:*" role = self.create_role_and_permission("Test Role two", "test:assigned:permission2") cross_account_request = CrossAccountRequest.objects.create( target_account=account_id, user_id=user_id, end_date=timezone.now() + timedelta(20), status="approved") cross_account_request.roles.add(role) # Create cross_account principal and role, permission in the account user_data = {"username": user_name, "email": "*****@*****.**"} request_context = self._create_request_context(self.customer_data, user_data, is_org_admin=False) request = request_context["request"] headers = request.META with tenant_context(self.tenant): Principal.objects.create(username=user_name, cross_account=True) self.create_role_and_permission("Test Role one", "test:assigned:permission1") self.create_role_and_permission("Test Role two", "test:assigned:permission2") response = client.get(url, **headers) # only assigned role permissions without platform default permission self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(response.data.get("data")), 2) permissions = [ access["permission"] for access in response.data.get("data") ] self.assertListEqual( permissions, ["test:assigned:permission1", "test:assigned:permission2"]) def test_get_access_no_app_supplied(self): """Test that we return all permissions when no app supplied.""" role_name = "roleA" policy_name = "policyA" access_data = { "permission": "app:foo:bar", "resourceDefinitions": [{ "attributeFilter": { "key": "keyA", "operation": "equal", "value": "valueA" } }], } response = self.create_role(role_name, access_data) role_uuid = response.data.get("uuid") role = Role.objects.get(uuid=role_uuid) access = Access.objects.create(role=role, permission=self.permission) self.create_policy(policy_name, self.group.uuid, [role_uuid]) url = "{}?application=&username={}".format(reverse("access"), self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get("data")) self.assertIsInstance(response.data.get("data"), list) self.assertEqual(len(response.data.get("data")), 2) self.assertEqual(response.data.get("meta").get("limit"), 1000) def test_get_access_multiple_apps_supplied(self): """Test that we return all permissions for multiple apps when supplied.""" role_name = "roleA" policy_name = "policyA" access_data = { "permission": "app:foo:bar", "resourceDefinitions": [{ "attributeFilter": { "key": "keyA", "operation": "equal", "value": "valueA" } }], } response = self.create_role(role_name, access_data) role_uuid = response.data.get("uuid") role = Role.objects.get(uuid=role_uuid) access = Access.objects.create(role=role, permission=self.permission) self.create_policy(policy_name, self.group.uuid, [role_uuid]) url = "{}?application={}&username={}".format(reverse("access"), "app,app2", self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsInstance(response.data.get("data"), list) self.assertEqual(len(response.data.get("data")), 2) def test_get_access_no_partial_match(self): """Test that we can have a partial match on app/permission.""" role_name = "roleA" policy_name = "policyA" access_data = { "permission": "app:foo:bar", "resourceDefinitions": [{ "attributeFilter": { "key": "keyA", "operation": "equal", "value": "valueA" } }], } response = self.create_role(role_name, access_data) role_uuid = response.data.get("uuid") self.create_policy(policy_name, self.group.uuid, [role_uuid]) url = "{}?application={}&username={}".format(reverse("access"), "ap", self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get("data")) self.assertIsInstance(response.data.get("data"), list) self.assertEqual(len(response.data.get("data")), 0) self.assertEqual(response.data.get("meta").get("limit"), 1000) def test_get_access_no_subset_match(self): """Test that we cannot have a subset match on app/permission.""" role_name = "roleA" policy_name = "policyA" access_data = { "permission": "app:foo:bar", "resourceDefinitions": [{ "attributeFilter": { "key": "keyA", "operation": "equal", "value": "valueA" } }], } response = self.create_role(role_name, access_data) role_uuid = response.data.get("uuid") self.create_policy(policy_name, self.group.uuid, [role_uuid]) url = "{}?application={}&username={}".format(reverse("access"), "appfoo", self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get("data")) self.assertIsInstance(response.data.get("data"), list) self.assertEqual(len(response.data.get("data")), 0) self.assertEqual(response.data.get("meta").get("limit"), 1000) def test_get_access_no_match(self): """Test that we only match on the application name of the permission data.""" role_name = "roleA" policy_name = "policyA" access_data = { "permission": "app:foo:bar", "resourceDefinitions": [{ "attributeFilter": { "key": "keyA", "operation": "equal", "value": "valueA" } }], } response = self.create_role(role_name, access_data) role_uuid = response.data.get("uuid") self.create_policy(policy_name, self.group.uuid, [role_uuid]) url = "{}?application={}&username={}".format(reverse("access"), "foo", self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get("data")) self.assertIsInstance(response.data.get("data"), list) self.assertEqual(len(response.data.get("data")), 0) self.assertEqual(response.data.get("meta").get("limit"), 1000) def test_get_access_with_limit(self): """Test that we can obtain the expected access with pagination.""" role_name = "roleA" response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get("uuid") policy_name = "policyA" response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) # test that we can retrieve the principal access url = "{}?application={}&username={}&limit=1".format( reverse("access"), "app", self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get("data")) self.assertIsInstance(response.data.get("data"), list) self.assertEqual(len(response.data.get("data")), 1) self.assertEqual(response.data.get("meta").get("count"), 1) self.assertEqual(response.data.get("meta").get("limit"), 1) self.assertEqual(self.access_data, response.data.get("data")[0]) def test_missing_query_params(self): """Test that we get expected failure when missing required query params.""" url = "{}?page={}".format(reverse("access"), "3") client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @patch( "management.principal.proxy.PrincipalProxy.request_filtered_principals", return_value={ "status_code": 200, "data": [] }, ) def test_missing_invalid_username(self, mock_request): """Test that we get expected failure when missing required query params.""" url = "{}?application={}&username={}".format(reverse("access"), "app", uuid4()) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @patch("management.cache.AccessCache.get_policy", return_value=None) @patch("management.cache.AccessCache.save_policy", return_value=None) def test_get_access_with_pagination_and_cache(self, save_policy, get_policy): """Test that we can obtain the expected access with pagination and cache.""" role_name = "roleA" response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get("uuid") policy_name = "policyA" response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) schema_name = self.tenant.schema_name principal_id = self.principal.uuid key = f"rbac::policy::tenant={schema_name}::user={principal_id}" client = APIClient() ######## access_policy are cached with desired sub_key ############ url = "{}?application={}&username={}&offset=1&limit=1".format( reverse("access"), "app", self.principal.username) response = client.get(url, **self.headers) # Cache is called saved with sub_key "app_1_1" sub_key = "app_1_1" get_policy.assert_called_with(principal_id, sub_key) save_policy.assert_called_with(principal_id, sub_key, []) ################################################################### #### access_policy are cached with desired sub_key when proper defaults #### url = "{}?application=&username={}".format(reverse("access"), self.principal.username) response = client.get(url, **self.headers) # Cache is called saved with sub_key "all_0_1000" sub_key = "all_0_1000" get_policy.assert_called_with(principal_id, sub_key) called_with_para = save_policy.mock_calls[1][1] self.assertEqual(principal_id, called_with_para[0]) self.assertEqual(sub_key, called_with_para[1]) self.assertEqual([self.access_data], json.loads(json.dumps(called_with_para[2])))
class RoleViewsetTests(IdentityRequest): """Test the role viewset.""" def setUp(self): """Set up the role viewset tests.""" super().setUp() request = self.request_context['request'] user = User(username=self.user_data['username'], tenant=self.tenant) user.save() request.user = user with tenant_context(self.tenant): self.principal = Principal(username=self.user_data['username']) self.principal.save() self.group = Group(name='groupA') self.group.save() self.group.principals.add(self.principal) self.group.save() def tearDown(self): """Tear down role viewset tests.""" User.objects.all().delete() with tenant_context(self.tenant): Group.objects.all().delete() Principal.objects.all().delete() Role.objects.all().delete() def create_role(self, role_name, in_access_data=None): """Create a role.""" access_data = { 'permission': 'app:*:*', 'resourceDefinitions': [{ 'attributeFilter': { 'key': 'key1', 'operation': 'equal', 'value': 'value1' } }] } if in_access_data: access_data = in_access_data test_data = {'name': role_name, 'access': [access_data]} # create a role url = reverse('role-list') client = APIClient() response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_201_CREATED) return response def test_create_role_success(self): """Test that we can create a role.""" role_name = 'roleA' access_data = { 'permission': 'app:*:*', 'resourceDefinitions': [{ 'attributeFilter': { 'key': 'keyA', 'operation': 'equal', 'value': 'valueA' } }] } response = self.create_role(role_name, access_data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) # test that we can retrieve the role url = reverse('role-detail', kwargs={'uuid': response.data.get('uuid')}) client = APIClient() response = client.get(url, **self.headers) self.assertIsNotNone(response.data.get('uuid')) self.assertIsNotNone(response.data.get('name')) self.assertEqual(role_name, response.data.get('name')) self.assertIsInstance(response.data.get('access'), list) self.assertEqual(access_data, response.data.get('access')[0]) def test_create_role_invalid(self): """Test that creating an invalid role returns an error.""" test_data = {} url = reverse('role-list') client = APIClient() response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_create_role_invalid_permission(self): """Test that creating an invalid role returns an error.""" test_data = { 'name': 'role1', 'access': [{ 'permission': 'foo:bar', 'resourceDefinitions': [] }] } url = reverse('role-list') client = APIClient() response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_read_role_invalid(self): """Test that reading an invalid role returns an error.""" url = reverse('role-detail', kwargs={'uuid': uuid4()}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_read_role_list_success(self): """Test that we can read a list of roles.""" role_name = 'roleA' response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) # list a roles url = reverse('role-list') client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) for keyname in ['meta', 'links', 'data']: self.assertIn(keyname, response.data) self.assertIsInstance(response.data.get('data'), list) self.assertEqual(len(response.data.get('data')), 1) role = response.data.get('data')[0] self.assertIsNotNone(role.get('name')) self.assertEqual(role.get('name'), role_name) def test_update_role_success(self): """Test that we can update an existing role.""" role_name = 'roleA' response = self.create_role(role_name) updated_name = role_name + '_update' role_uuid = response.data.get('uuid') test_data = response.data test_data['name'] = updated_name del test_data['uuid'] url = reverse('role-detail', kwargs={'uuid': role_uuid}) client = APIClient() response = client.put(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get('uuid')) self.assertEqual(updated_name, response.data.get('name')) def test_update_role_invalid(self): """Test that updating an invalid role returns an error.""" url = reverse('role-detail', kwargs={'uuid': uuid4()}) client = APIClient() response = client.put(url, {}, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_delete_role_success(self): """Test that we can delete an existing role.""" role_name = 'roleA' response = self.create_role(role_name) role_uuid = response.data.get('uuid') url = reverse('role-detail', kwargs={'uuid': role_uuid}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) # verify the role no longer exists response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_delete_role_invalid(self): """Test that deleting an invalid role returns an error.""" url = reverse('role-detail', kwargs={'uuid': uuid4()}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
class GroupViewsetTests(IdentityRequest): """Test the group viewset.""" def setUp(self): """Set up the group viewset tests.""" super().setUp() request = self.request_context['request'] user = User(username=self.user_data['username'], email=self.user_data['email'], tenant=self.tenant) user.save() request.user = user with tenant_context(self.tenant): self.principal = Principal(username=self.user_data['username'], email=self.user_data['email']) self.principal.save() self.group = Group(name='groupA') self.group.save() self.group.principals.add(self.principal) self.group.save() def tearDown(self): """Tear down group viewset tests.""" User.objects.all().delete() with tenant_context(self.tenant): Group.objects.all().delete() Principal.objects.all().delete() def test_create_group_success(self): """Test that we can create a group.""" group_name = 'groupB' test_data = {'name': group_name} # create a group url = reverse('group-list') client = APIClient() response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_201_CREATED) # test that we can retrieve the group url = reverse('group-detail', kwargs={'uuid': response.data.get('uuid')}) response = client.get(url, **self.headers) self.assertIsNotNone(response.data.get('uuid')) self.assertIsNotNone(response.data.get('name')) self.assertEqual(group_name, response.data.get('name')) def test_create_group_invalid(self): """Test that creating an invalid group returns an error.""" test_data = {} url = reverse('group-list') client = APIClient() response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_read_group_success(self): """Test that we can read a group.""" url = reverse('group-detail', kwargs={'uuid': self.group.uuid}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get('name')) self.assertEqual(self.group.name, response.data.get('name')) def test_read_group_invalid(self): """Test that reading an invalid group returns an error.""" url = reverse('group-detail', kwargs={'uuid': uuid4()}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_read_group_list_success(self): """Test that we can read a list of groups.""" url = reverse('group-list') client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) for keyname in ['meta', 'links', 'data']: self.assertIn(keyname, response.data) self.assertIsInstance(response.data.get('data'), list) self.assertEqual(len(response.data.get('data')), 1) group = response.data.get('data')[0] self.assertIsNotNone(group.get('name')) self.assertEqual(group.get('name'), self.group.name) def test_update_group_success(self): """Test that we can update an existing group.""" group = Group.objects.first() updated_name = group.name + '_update' test_data = {'name': updated_name} url = reverse('group-detail', kwargs={'uuid': group.uuid}) client = APIClient() response = client.put(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get('uuid')) self.assertEqual(updated_name, response.data.get('name')) def test_update_group_invalid(self): """Test that updating an invalid group returns an error.""" url = reverse('group-detail', kwargs={'uuid': uuid4()}) client = APIClient() response = client.put(url, {}, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_delete_group_success(self): """Test that we can delete an existing group.""" group = Group.objects.first() url = reverse('group-detail', kwargs={'uuid': group.uuid}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) # verify the group no longer exists response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_delete_group_invalid(self): """Test that deleting an invalid group returns an error.""" url = reverse('group-detail', kwargs={'uuid': uuid4()}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_group_principals_invalid_method(self): """Test that using an unsupported REST method returns an error.""" url = reverse('group-principals', kwargs={'uuid': uuid4()}) client = APIClient() response = client.put(url, {}, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) def test_add_group_principals_success(self): """Test that adding a principal to a group returns successfully.""" url = reverse('group-principals', kwargs={'uuid': self.group.uuid}) client = APIClient() new_username = uuid4() test_data = { 'principals': [{ 'username': self.principal.username }, { 'username': new_username }] } response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_remove_group_principals_success(self): """Test that removing a principal to a group returns successfully.""" url = reverse('group-principals', kwargs={'uuid': self.group.uuid}) client = APIClient() url = '{}?usernames={}'.format(url, self.principal.username) response = client.delete(url, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_remove_group_principals_invalid(self): """Test that removing a principal returns an error with invalid data format.""" url = reverse('group-principals', kwargs={'uuid': self.group.uuid}) client = APIClient() response = client.delete(url, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
class PolicyViewsetTests(IdentityRequest): """Test the policy viewset.""" def setUp(self): """Set up the policy viewset tests.""" super().setUp() request = self.request_context["request"] user = User() user.username = self.user_data["username"] user.account = self.customer_data["account_id"] request.user = user with tenant_context(self.tenant): self.principal = Principal(username=self.user_data["username"]) self.principal.save() self.group = Group(name="groupA") self.group.save() self.group.principals.add(self.principal) self.group.save() Permission.objects.create(permission="app:*:*") def tearDown(self): """Tear down policy viewset tests.""" with tenant_context(self.tenant): Group.objects.all().delete() Principal.objects.all().delete() Role.objects.all().delete() Policy.objects.all().delete() def create_role(self, role_name, in_access_data=None): """Create a role.""" access_data = { "permission": "app:*:*", "resourceDefinitions": [{"attributeFilter": {"key": "key1", "operation": "equal", "value": "value1"}}], } if in_access_data: access_data = in_access_data test_data = {"name": role_name, "access": [access_data]} # create a role url = reverse("role-list") client = APIClient() response = client.post(url, test_data, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_201_CREATED) return response def create_policy(self, policy_name, group, roles, status=status.HTTP_201_CREATED): """Create a policy.""" # create a policy test_data = {"name": policy_name, "group": group, "roles": roles} url = reverse("policy-list") client = APIClient() response = client.post(url, test_data, format="json", **self.headers) self.assertEqual(response.status_code, status) return response def test_create_policy_success(self): """Test that we can create a policy.""" role_name = "roleA" response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get("uuid") policy_name = "policyA" response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) # test that we can retrieve the policy url = reverse("policy-detail", kwargs={"uuid": response.data.get("uuid")}) client = APIClient() response = client.get(url, **self.headers) self.assertIsNotNone(response.data.get("uuid")) self.assertIsNotNone(response.data.get("name")) self.assertEqual(policy_name, response.data.get("name")) self.assertEqual(str(self.group.uuid), response.data.get("group").get("uuid")) def test_create_policy_invalid_group(self): """Test that we cannot create a policy with invalid group.""" role_name = "roleA" response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get("uuid") policy_name = "policyA" response = self.create_policy(policy_name, uuid4(), [role_uuid], status.HTTP_400_BAD_REQUEST) def test_create_policy_invalid_role(self): """Test that we cannot create a policy with an invalid role.""" policy_name = "policyA" response = self.create_policy(policy_name, self.group.uuid, [uuid4()], status.HTTP_400_BAD_REQUEST) def test_create_policy_no_role(self): """Test that we cannot create a policy without roles.""" policy_name = "policyA" response = self.create_policy(policy_name, self.group.uuid, [], status.HTTP_400_BAD_REQUEST) def test_create_policy_invalid(self): """Test that creating an invalid policy returns an error.""" test_data = {} url = reverse("policy-list") client = APIClient() response = client.post(url, test_data, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_read_policy_invalid(self): """Test that reading an invalid policy returns an error.""" url = reverse("policy-detail", kwargs={"uuid": uuid4()}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_read_policy_list_success(self): """Test that we can read a list of policies.""" role_name = "roleA" response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get("uuid") policy_name = "policyA" response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) # list a policies url = reverse("policy-list") client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) for keyname in ["meta", "links", "data"]: self.assertIn(keyname, response.data) self.assertIsInstance(response.data.get("data"), list) self.assertEqual(len(response.data.get("data")), 1) policy = response.data.get("data")[0] self.assertIsNotNone(policy.get("name")) self.assertEqual(policy.get("name"), policy_name) def test_update_policy_success(self): """Test that we can update an existing policy.""" role_name = "roleA" response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get("uuid") policy_name = "policyA" response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) updated_name = policy_name + "_update" policy_uuid = response.data.get("uuid") test_data = response.data test_data["name"] = updated_name test_data["group"] = self.group.uuid test_data["roles"] = [role_uuid] del test_data["uuid"] url = reverse("policy-detail", kwargs={"uuid": policy_uuid}) client = APIClient() response = client.put(url, test_data, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get("uuid")) self.assertEqual(updated_name, response.data.get("name")) def test_update_policy_bad_group(self): """Test that we cannot update an existing policy with a bad group.""" role_name = "roleA" response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get("uuid") policy_name = "policyA" response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) updated_name = policy_name + "_update" policy_uuid = response.data.get("uuid") test_data = response.data test_data["name"] = updated_name test_data["group"] = uuid4() test_data["roles"] = [role_uuid] del test_data["uuid"] url = reverse("policy-detail", kwargs={"uuid": policy_uuid}) client = APIClient() response = client.put(url, test_data, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_update_policy_bad_role(self): """Test that we cannot update an existing policy with a bad role.""" role_name = "roleA" response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get("uuid") policy_name = "policyA" response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) updated_name = policy_name + "_update" policy_uuid = response.data.get("uuid") test_data = response.data test_data["name"] = updated_name test_data["group"] = self.group.uuid test_data["roles"] = [uuid4()] del test_data["uuid"] url = reverse("policy-detail", kwargs={"uuid": policy_uuid}) client = APIClient() response = client.put(url, test_data, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_update_policy_no_role(self): """Test that we can update an existing policy to have no roles.""" role_name = "roleA" response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get("uuid") policy_name = "policyA" response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) updated_name = policy_name + "_update" policy_uuid = response.data.get("uuid") test_data = response.data test_data["name"] = updated_name test_data["group"] = self.group.uuid test_data["roles"] = [] del test_data["uuid"] url = reverse("policy-detail", kwargs={"uuid": policy_uuid}) client = APIClient() response = client.put(url, test_data, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_update_policy_invalid(self): """Test that updating an invalid policy returns an error.""" url = reverse("policy-detail", kwargs={"uuid": uuid4()}) client = APIClient() response = client.put(url, {}, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_delete_role_success(self): """Test that we can delete an existing role.""" role_name = "roleA" response = self.create_role(role_name) role_uuid = response.data.get("uuid") policy_name = "policyA" response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) policy_uuid = response.data.get("uuid") url = reverse("policy-detail", kwargs={"uuid": policy_uuid}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) # verify the policy no longer exists response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_delete_policy_invalid(self): """Test that deleting an invalid policy returns an error.""" url = reverse("policy-detail", kwargs={"uuid": uuid4()}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_policy_removed_on_group_deletion(self): """Test that we can an existing policy is cleaned up when the group is deleted.""" role_name = "roleA" response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get("uuid") policy_name = "policyA" response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) policy_uuid = response.data.get("uuid") url = reverse("group-detail", kwargs={"uuid": self.group.uuid}) client = APIClient() response = client.delete(url, **self.headers) url = reverse("policy-detail", kwargs={"uuid": policy_uuid}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_policy_removed_on_all_role_deletion(self): """Test that we can an existing policy is cleaned up when the all roles are deleted.""" role_name = "roleA" response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get("uuid") policy_name = "policyA" response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) policy_uuid = response.data.get("uuid") url = reverse("role-detail", kwargs={"uuid": role_uuid}) client = APIClient() response = client.delete(url, **self.headers) url = reverse("policy-detail", kwargs={"uuid": policy_uuid}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_policy_removed_on_one_role_deletion(self): """Test that we can an existing policy remains when not all roles are deleted.""" roles = [] role_name = "roleA" response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) roles.append(response.data.get("uuid")) role_name = "roleB" response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) roles.append(response.data.get("uuid")) policy_name = "policyA" response = self.create_policy(policy_name, self.group.uuid, roles) policy_uuid = response.data.get("uuid") url = reverse("role-detail", kwargs={"uuid": roles[0]}) client = APIClient() response = client.delete(url, **self.headers) url = reverse("policy-detail", kwargs={"uuid": policy_uuid}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK)
class AccessViewTests(IdentityRequest): """Test the access view.""" def setUp(self): """Set up the access view tests.""" super().setUp() request = self.request_context['request'] user = User(username=self.user_data['username'], email=self.user_data['email'], tenant=self.tenant) user.save() request.user = user self.access_data = { 'permission': 'app:*:*', 'resourceDefinition': [{ 'attributeFilter': { 'key': 'key1', 'operation': 'equal', 'value': 'value1' } }] } with tenant_context(self.tenant): self.principal = Principal(username=self.user_data['username'], email=self.user_data['email']) self.principal.save() self.group = Group(name='groupA') self.group.save() self.group.principals.add(self.principal) self.group.save() def tearDown(self): """Tear down access view tests.""" User.objects.all().delete() with tenant_context(self.tenant): Group.objects.all().delete() Principal.objects.all().delete() Role.objects.all().delete() Policy.objects.all().delete() def create_role(self, role_name, in_access_data=None): """Create a role.""" access_data = self.access_data if in_access_data: access_data = in_access_data test_data = {'name': role_name, 'access': [access_data]} # create a role url = reverse('role-list') client = APIClient() response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_201_CREATED) return response def create_policy(self, policy_name, group, roles, status=status.HTTP_201_CREATED): """Create a policy.""" # create a policy test_data = {'name': policy_name, 'group': group, 'roles': roles} url = reverse('policy-list') client = APIClient() response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status) return response def test_get_access_success(self): """Test that we can obtain the expected access.""" role_name = 'roleA' response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get('uuid') policy_name = 'policyA' response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) # test that we can retrieve the principal access url = '{}?application={}&username={}'.format(reverse('access'), 'app', self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get('data')) self.assertIsInstance(response.data.get('data'), list) self.assertEqual(len(response.data.get('data')), 1) self.assertEqual(self.access_data, response.data.get('data')[0]) def test_missing_query_params(self): """Test that we get expected failure when missing required query params.""" url = '{}?page={}'.format(reverse('access'), '3') client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_missing_invalid_username(self): """Test that we get expected failure when missing required query params.""" url = '{}?application={}&username={}'.format(reverse('access'), 'app', uuid4()) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
class GroupViewsetTests(IdentityRequest): """Test the group viewset.""" def setUp(self): """Set up the group viewset tests.""" super().setUp() request = self.request_context['request'] user = User() user.username = self.user_data['username'] user.account = self.customer_data['account_id'] request.user = user self.dummy_role_id = uuid4() with tenant_context(self.tenant): self.principal = Principal(username=self.user_data['username']) self.principal.save() self.principalB = Principal(username='******') self.principalB.save() self.principalC = Principal( username='******') self.principalC.save() self.group = Group(name='groupA') self.group.save() self.role = Role.objects.create(name='roleA', description='A role for a group.') self.policy = Policy.objects.create(name='policyA', group=self.group) self.policy.roles.add(self.role) self.policy.save() self.group.policies.add(self.policy) self.group.principals.add(self.principal, self.principalB) self.group.save() self.defGroup = Group(name='groupDef', platform_default=True, system=True) self.defGroup.save() self.defGroup.principals.add(self.principal) self.defGroup.save() self.emptyGroup = Group(name='groupE') self.emptyGroup.save() self.groupB = Group.objects.create(name='groupB') self.groupB.principals.add(self.principal) self.policyB = Policy.objects.create(name='policyB', group=self.groupB) self.roleB = Role.objects.create(name='roleB') self.policyB.roles.add(self.roleB) self.policyB.save() # role that's not assigned to principal self.roleOrphan = Role.objects.create(name='roleOrphan') # group that associates with multipal roles self.groupMultiRole = Group.objects.create(name='groupMultiRole') self.policyMultiRole = Policy.objects.create( name='policyMultiRole') self.policyMultiRole.roles.add(self.role) self.policyMultiRole.roles.add(self.roleB) self.groupMultiRole.policies.add(self.policyMultiRole) def tearDown(self): """Tear down group viewset tests.""" with tenant_context(self.tenant): Group.objects.all().delete() Principal.objects.all().delete() Role.objects.all().delete() Policy.objects.all().delete() @patch( 'management.principal.proxy.PrincipalProxy.request_filtered_principals', return_value={ 'status_code': 200, 'data': [] }) def test_create_group_success(self, mock_request): """Test that we can create a group.""" group_name = 'groupC' test_data = {'name': group_name} # create a group url = reverse('group-list') client = APIClient() response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_201_CREATED) # test that we can retrieve the group url = reverse('group-detail', kwargs={'uuid': response.data.get('uuid')}) response = client.get(url, **self.headers) self.assertIsNotNone(response.data.get('uuid')) self.assertIsNotNone(response.data.get('name')) self.assertEqual(group_name, response.data.get('name')) def test_create_default_group(self): """Test that system groups can be created.""" group_name = 'groupDef' # test group retrieval client = APIClient() url = reverse('group-detail', kwargs={'uuid': self.defGroup.uuid}) response = client.get(url, **self.headers) self.assertIsNotNone(response.data.get('uuid')) self.assertIsNotNone(response.data.get('name')) self.assertTrue(response.data.get('platform_default')) self.assertEqual(group_name, response.data.get('name')) def test_create_group_invalid(self): """Test that creating an invalid group returns an error.""" test_data = {} url = reverse('group-list') client = APIClient() response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_group_filter_by_any_role_name_in_a_list_success(self): """Test default behaviour that filter groups by any role name in a list success.""" url = '{}?role_names={},{}'.format(reverse('group-list'), 'Rolea', 'RoleB') client = APIClient() response = client.get(url, **self.headers) self.assertTrue(response.data.get('meta').get('count') == 3) expected_groups = [ self.group.name, self.groupB.name, self.groupMultiRole.name ] self.assertEqual( expected_groups, [group.get('name') for group in response.data.get('data')]) def test_group_filter_by_all_role_name_in_a_list_success(self): """Test that filter groups by all role names in a list success.""" url = '{}?role_names={},{}&role_discriminator=all'.format( reverse('group-list'), 'Rolea', 'roleB') client = APIClient() response = client.get(url, **self.headers) self.assertTrue(response.data.get('meta').get('count') == 1) expected_groups = [self.groupMultiRole.name] self.assertEqual( expected_groups, [group.get('name') for group in response.data.get('data')]) def test_group_filter_with_invalid_discriminator_failure(self): """Test that filter groups with invalid discriminator returns failed validation.""" url = '{}?role_names={},{}&role_discriminator=invalid'.format( reverse('group-list'), 'roleA', 'ROLEb') client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @patch( 'management.principal.proxy.PrincipalProxy.request_filtered_principals', return_value={ 'status_code': 200, 'data': [] }) def test_read_group_success(self, mock_request): """Test that we can read a group.""" url = reverse('group-detail', kwargs={'uuid': self.group.uuid}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get('name')) self.assertEqual(self.group.name, response.data.get('name')) self.assertEqual(len(response.data.get('roles')), 1) self.assertEqual( response.data.get('roles')[0]['uuid'], str(self.role.uuid)) def test_read_group_invalid(self): """Test that reading an invalid group returns an error.""" url = reverse('group-detail', kwargs={'uuid': uuid4()}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_read_group_list_success(self): """Test that we can read a list of groups.""" url = reverse('group-list') client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) for keyname in ['meta', 'links', 'data']: self.assertIn(keyname, response.data) self.assertIsInstance(response.data.get('data'), list) self.assertEqual(len(response.data.get('data')), 5) group = response.data.get('data')[0] self.assertIsNotNone(group.get('name')) self.assertEqual(group.get('name'), self.group.name) def test_filter_group_list_by_uuid_success(self): """Test that we can filter a list of groups by uuid.""" url = f"{reverse('group-list')}?uuid={self.group.uuid}" client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) for keyname in ['meta', 'links', 'data']: self.assertIn(keyname, response.data) self.assertIsInstance(response.data.get('data'), list) self.assertEqual(len(response.data.get('data')), 1) group = response.data.get('data')[0] self.assertIsNotNone(group.get('name')) self.assertEqual(group.get('name'), self.group.name) def test_filter_group_list_by_uuid_multiple(self): """Test that we can filter a list of groups by uuid.""" url = f"{reverse('group-list')}?uuid={self.group.uuid},{self.groupB.uuid}" client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) for keyname in ['meta', 'links', 'data']: self.assertIn(keyname, response.data) self.assertIsInstance(response.data.get('data'), list) self.assertEqual(len(response.data.get('data')), 2) group = response.data.get('data')[0] self.assertIsNotNone(group.get('name')) self.assertEqual(group.get('name'), self.group.name) group = response.data.get('data')[1] self.assertIsNotNone(group.get('name')) self.assertEqual(group.get('name'), self.groupB.name) def test_filter_group_list_by_uuid_fail(self): """Test that filtering by a nonexistant uuid returns nothing.""" url = f"{reverse('group-list')}?uuid={uuid4()}" client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) for keyname in ['meta', 'links', 'data']: self.assertIn(keyname, response.data) self.assertEqual(response.data.get('data'), []) self.assertEqual(len(response.data.get('data')), 0) @patch( 'management.principal.proxy.PrincipalProxy.request_filtered_principals', return_value={ 'status_code': 200, 'data': [] }) def test_update_group_success(self, mock_request): """Test that we can update an existing group.""" group = Group.objects.first() updated_name = group.name + '_update' test_data = {'name': updated_name} url = reverse('group-detail', kwargs={'uuid': group.uuid}) client = APIClient() response = client.put(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get('uuid')) self.assertEqual(updated_name, response.data.get('name')) def test_update_default_group(self): """Test that platform_default groups are protected from updates""" url = reverse('group-detail', kwargs={'uuid': self.defGroup.uuid}) test_data = {'name': self.defGroup.name + '_updated'} client = APIClient() response = client.put(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_update_group_invalid(self): """Test that updating an invalid group returns an error.""" url = reverse('group-detail', kwargs={'uuid': uuid4()}) client = APIClient() response = client.put(url, {}, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_delete_group_success(self): """Test that we can delete an existing group.""" group = Group.objects.first() url = reverse('group-detail', kwargs={'uuid': group.uuid}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) # verify the group no longer exists response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_delete_default_group(self): """Test that platform_default groups are protected from deletion""" url = reverse('group-detail', kwargs={'uuid': self.defGroup.uuid}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_delete_group_invalid(self): """Test that deleting an invalid group returns an error.""" url = reverse('group-detail', kwargs={'uuid': uuid4()}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_group_principals_invalid_method(self): """Test that using an unsupported REST method returns an error.""" url = reverse('group-principals', kwargs={'uuid': uuid4()}) client = APIClient() response = client.put(url, {}, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) @patch( 'management.principal.proxy.PrincipalProxy.request_filtered_principals', return_value={ 'status_code': status.HTTP_500_INTERNAL_SERVER_ERROR, 'errors': [{ 'detail': 'Unexpected error.', 'status': status.HTTP_500_INTERNAL_SERVER_ERROR, 'source': 'principals' }] }) def test_add_group_principals_failure(self, mock_request): """Test that adding a principal to a group returns has proper response when it is failed.""" url = reverse('group-principals', kwargs={'uuid': self.group.uuid}) client = APIClient() new_username = uuid4() test_data = { 'principals': [{ 'username': self.principal.username }, { 'username': new_username }] } response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR) self.assertEqual(response.data[0]['detail'], 'Unexpected error.') self.assertEqual(response.data[0]['status'], 500) self.assertEqual(response.data[0]['source'], 'principals') @patch( 'management.principal.proxy.PrincipalProxy.request_filtered_principals', return_value={ 'status_code': 200, 'data': [] }) def test_add_group_principals_success(self, mock_request): """Test that adding a principal to a group returns successfully.""" url = reverse('group-principals', kwargs={'uuid': self.group.uuid}) client = APIClient() new_username = uuid4() test_data = { 'principals': [{ 'username': self.principal.username }, { 'username': new_username }] } response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) url = reverse('group-list') response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data.get('meta').get('count'), 5) self.assertEqual(response.data.get('data')[0].get('principalCount'), 2) self.assertEqual(response.data.get('data')[0].get('policyCount'), None) self.assertEqual(response.data.get('data')[0].get('roleCount'), 1) @patch( 'management.principal.proxy.PrincipalProxy.request_filtered_principals', return_value={ 'status_code': 200, 'data': [] }) def test_get_group_principals_empty(self, mock_request): """Test that getting principals from an empty group returns successfully.""" client = APIClient() url = reverse('group-principals', kwargs={'uuid': self.emptyGroup.uuid}) response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data.get('meta').get('count'), 0) self.assertEqual(response.data.get('data'), []) @patch( 'management.principal.proxy.PrincipalProxy.request_filtered_principals', return_value={ 'status_code': 200, 'data': [] }) def test_get_group_principals_nonempty(self, mock_request): """Test that getting principals from a nonempty group returns successfully.""" mock_request.return_value['data'] = [{ 'username': self.principal.username }, { 'username': self.principalB.username }] client = APIClient() url = reverse('group-principals', kwargs={'uuid': self.group.uuid}) response = client.get(url, **self.headers) call_args, kwargs = mock_request.call_args_list[0] username_arg = call_args[0] for username in [self.principal.username, self.principalB.username]: self.assertTrue(username in username_arg) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data.get('meta').get('count'), 2) self.assertEqual( response.data.get('data')[0].get('username'), self.principal.username) self.assertEqual( response.data.get('data')[1].get('username'), self.principalB.username) def test_remove_group_principals_success(self): """Test that removing a principal to a group returns successfully.""" url = reverse('group-principals', kwargs={'uuid': self.group.uuid}) client = APIClient() url = '{}?usernames={}'.format(url, self.principal.username) response = client.delete(url, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_remove_group_principals_invalid(self): """Test that removing a principal returns an error with invalid data format.""" url = reverse('group-principals', kwargs={'uuid': self.group.uuid}) client = APIClient() response = client.delete(url, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @patch( 'management.principal.proxy.PrincipalProxy.request_filtered_principals', return_value={ 'status_code': 200, 'data': [] }) def test_get_group_by_username(self, mock_request): """Test that getting groups for a principal returns successfully.""" url = reverse('group-list') url = '{}?username={}'.format(url, self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.data.get('meta').get('count'), 3) # User who is not added to a group explicitly will return platform default group url = reverse('group-list') url = '{}?username={}'.format(url, self.principalC.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.data.get('meta').get('count'), 1) # Return bad request when user does not exist url = reverse('group-list') url = '{}?username={}'.format(url, uuid4()) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_get_group_by_username_with_capitalization(self): """Test that getting groups for a user name with capitalization returns successfully.""" url = reverse('group-list') username = "".join( random.choice([k.upper(), k]) for k in self.principal.username) url = '{}?username={}'.format(url, username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.data.get('meta').get('count'), 3) def test_get_group_roles_success(self): """Test that getting roles for a group returns successfully.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get('data') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 1) self.assertEqual(roles[0].get('uuid'), str(self.role.uuid)) self.assertEqual(roles[0].get('name'), self.role.name) self.assertEqual(roles[0].get('description'), self.role.description) def test_get_group_roles_with_exclude_false_success(self): """Test that getting roles with 'exclude=false' for a group works as default.""" url = "%s?exclude=FALSE" % (reverse('group-roles', kwargs={'uuid': self.group.uuid})) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get('data') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 1) self.assertEqual(roles[0].get('uuid'), str(self.role.uuid)) self.assertEqual(roles[0].get('name'), self.role.name) self.assertEqual(roles[0].get('description'), self.role.description) def test_get_group_roles_with_exclude_success(self): """Test that getting roles with 'exclude=True' for a group returns successfully.""" url = "%s?exclude=True" % (reverse('group-roles', kwargs={'uuid': self.group.uuid})) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get('data') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 2) self.assertTrue(role.uuid in [self.roleB.uuid, self.roleOrphan.uuid] for role in roles) def test_get_group_roles_with_exclude_in_principal_scope_success(self): """Test that getting roles with 'exclude=True' for a group in principal scope.""" url = "%s?exclude=True&scope=principal" % (reverse( 'group-roles', kwargs={'uuid': self.group.uuid})) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get('data') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 1) self.assertEqual(roles[0].get('uuid'), str(self.roleB.uuid)) self.assertEqual(roles[0].get('name'), self.roleB.name) self.assertEqual(roles[0].get('description'), self.roleB.description) def test_get_group_roles_ordered(self): """Test getting roles with 'order_by=' returns properly.""" url = f"{reverse('group-roles', kwargs={'uuid': self.group.uuid})}?order_by=-name" client = APIClient() test_data = {'roles': [self.roleB.uuid]} response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) response = client.get(url, **self.headers) roles = response.data.get('data') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 2) self.assertEqual(roles[0].get('name'), self.roleB.name) self.assertEqual(roles[1].get('name'), self.role.name) def test_exclude_input_invalid(self): """Test that getting roles with 'exclude=' for a group returns failed validation.""" url = "%s?exclude=sth" % (reverse('group-roles', kwargs={'uuid': self.group.uuid})) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_role_name_filter_for_group_roles_no_match(self): """Test role_name filter for getting roles for a group.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) url = '{}?role_name=test'.format(url) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get('data') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 0) def test_role_name_filter_for_group_roles_match(self): """Test role_name filter for getting roles for a group.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) url = '{}?role_name={}'.format(url, self.role.name) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get('data') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 1) self.assertEqual(roles[0].get('uuid'), str(self.role.uuid)) def test_role_description_filter_for_group_roles_no_match(self): """Test role_description filter for getting roles for a group.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) url = '{}?role_description=test'.format(url) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get('data') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 0) def test_role_description_filter_for_group_roles_match(self): """Test role_description filter for getting roles for a group.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) url = '{}?role_description={}'.format(url, self.role.description) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get('data') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 1) self.assertEqual(roles[0].get('uuid'), str(self.role.uuid)) def test_all_role_filters_for_group_roles_no_match(self): """Test role filters for getting roles for a group.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) url = '{}?role_description=test&role_name=test'.format(url) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get('data') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 0) def test_all_role_filters_for_group_roles_match(self): """Test role filters for getting roles for a group.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) url = '{}?role_description={}&role_name={}'.format( url, self.role.description, self.role.name) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get('data') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 1) self.assertEqual(roles[0].get('uuid'), str(self.role.uuid)) @patch( 'management.principal.proxy.PrincipalProxy.request_filtered_principals', return_value={ 'status_code': 200, 'data': [] }) def test_principal_username_filter_for_group_roles_no_match( self, mock_request): """Test principal_username filter for getting principals for a group.""" url = reverse('group-principals', kwargs={'uuid': self.group.uuid}) url = '{}?principal_username=test'.format(url) client = APIClient() response = client.get(url, **self.headers) principals = response.data.get('data') mock_request.assert_called_with([], ANY, sort_order=None) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(principals), 0) @patch( 'management.principal.proxy.PrincipalProxy.request_filtered_principals', return_value={ 'status_code': 200, 'data': [{ 'username': '******' }] }) def test_principal_username_filter_for_group_roles_match( self, mock_request): """Test principal_username filter for getting principals for a group.""" url = reverse('group-principals', kwargs={'uuid': self.group.uuid}) url = '{}?principal_username={}'.format(url, self.principal.username) client = APIClient() response = client.get(url, **self.headers) principals = response.data.get('data') mock_request.assert_called_with([self.principal.username], ANY, sort_order=None) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(principals), 1) @patch( 'management.principal.proxy.PrincipalProxy.request_filtered_principals', return_value={ 'status_code': 200, 'data': [{ 'username': '******' }] }) def test_principal_get_ordering_username_success(self, mock_request): """Test that passing a username order_by parameter calls the proxy correctly.""" url = f"{reverse('group-principals', kwargs={'uuid': self.group.uuid})}?order_by=username" client = APIClient() response = client.get(url, **self.headers) principals = response.data.get('data') expected_principals = sorted( [self.principal.username, self.principalB.username]) mock_request.assert_called_with(expected_principals, ANY, sort_order='asc') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(principals), 1) @patch( 'management.principal.proxy.PrincipalProxy.request_filtered_principals', return_value={ 'status_code': 200, 'data': [{ 'username': '******' }] }) def test_principal_get_ordering_nonusername_fail(self, mock_request): """Test that passing a username order_by parameter calls the proxy correctly.""" url = f"{reverse('group-principals', kwargs={'uuid': self.group.uuid})}?order_by=best_joke" client = APIClient() response = client.get(url, **self.headers) principals = response.data.get('data') self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(principals, None) def test_add_group_roles_system_policy_create_success(self): """Test that adding a role to a group without a system policy returns successfully.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) client = APIClient() test_data = {'roles': [self.roleB.uuid, self.dummy_role_id]} self.assertCountEqual([self.role], list(self.group.roles())) self.assertCountEqual([self.policy], list(self.group.policies.all())) response = client.post(url, test_data, format='json', **self.headers) roles = response.data.get('data') system_policies = Policy.objects.filter(system=True) system_policy = system_policies.get(group=self.group) self.assertEqual(len(system_policies), 1) self.assertCountEqual([system_policy, self.policy], list(self.group.policies.all())) self.assertCountEqual([self.roleB], list(system_policy.roles.all())) self.assertCountEqual([self.role], list(self.policy.roles.all())) self.assertCountEqual([self.role, self.roleB], list(self.group.roles())) self.assertEqual(len(roles), 2) self.assertEqual(roles[0].get('uuid'), str(self.role.uuid)) self.assertEqual(roles[0].get('name'), self.role.name) self.assertEqual(roles[0].get('description'), self.role.description) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_system_flag_update_on_add(self): """Test that adding a role to a platform_default group flips the system flag.""" url = reverse('group-roles', kwargs={'uuid': self.defGroup.uuid}) client = APIClient() test_data = {'roles': [self.roleB.uuid, self.dummy_role_id]} self.assertTrue(self.defGroup.system) response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.defGroup.refresh_from_db() self.assertEqual(self.defGroup.name, "Custom default user access") self.assertFalse(self.defGroup.system) def test_system_flag_update_on_remove(self): """Test that removing a role from a platform_default group flips the system flag.""" url = reverse('group-roles', kwargs={'uuid': self.defGroup.uuid}) client = APIClient() url = '{}?roles={}'.format(url, self.roleB.uuid) self.policy.roles.add(self.roleB) self.policy.save() self.assertTrue(self.defGroup.system) response = client.delete(url, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) self.defGroup.refresh_from_db() self.assertEqual(self.defGroup.name, "Custom default user access") self.assertFalse(self.defGroup.system) def test_add_group_roles_system_policy_create_new_group_success(self): """Test that adding a role to a group without a system policy returns successfully.""" group_url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) groupB_url = reverse('group-roles', kwargs={'uuid': self.groupB.uuid}) client = APIClient() test_data = {'roles': [self.roleB.uuid]} response = client.post(group_url, test_data, format='json', **self.headers) responseB = client.post(groupB_url, test_data, format='json', **self.headers) system_policies = Policy.objects.filter(system=True) system_policy = system_policies.get(group=self.group) system_policyB = system_policies.get(group=self.groupB) self.assertEqual(len(system_policies), 2) self.assertCountEqual([self.roleB], list(system_policy.roles.all())) self.assertCountEqual([self.roleB], list(system_policyB.roles.all())) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(responseB.status_code, status.HTTP_200_OK) def test_add_group_roles_system_policy_get_success(self): """Test that adding a role to a group with existing system policy returns successfully.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) client = APIClient() test_data = {'roles': [self.roleB.uuid, self.dummy_role_id]} system_policy_name = 'System Policy for Group {}'.format( self.group.uuid) system_policy = Policy.objects.create(system=True, group=self.group, name=system_policy_name) self.assertCountEqual([self.role], list(self.group.roles())) self.assertCountEqual([system_policy, self.policy], list(self.group.policies.all())) response = client.post(url, test_data, format='json', **self.headers) roles = response.data.get('data') system_policies = Policy.objects.filter(system=True, group=self.group) system_policy = system_policies.first() self.assertEqual(len(system_policies), 1) self.assertCountEqual([system_policy, self.policy], list(self.group.policies.all())) self.assertCountEqual([self.roleB], list(system_policy.roles.all())) self.assertCountEqual([self.role], list(self.policy.roles.all())) self.assertCountEqual([self.role, self.roleB], list(self.group.roles())) self.assertEqual(len(roles), 2) self.assertEqual(roles[0].get('uuid'), str(self.role.uuid)) self.assertEqual(roles[0].get('name'), self.role.name) self.assertEqual(roles[0].get('description'), self.role.description) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_add_group_multiple_roles_success(self): """Test that adding multiple roles to a group returns successfully.""" with tenant_context(self.tenant): groupC = Group.objects.create(name='groupC') url = reverse('group-roles', kwargs={'uuid': groupC.uuid}) client = APIClient() test_data = {'roles': [self.role.uuid, self.roleB.uuid]} self.assertCountEqual([], list(groupC.roles())) response = client.post(url, test_data, format='json', **self.headers) self.assertCountEqual([self.role, self.roleB], list(groupC.roles())) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_add_group_multiple_roles_invalid(self): """Test that adding invalid roles to a group fails the request and does not add any.""" with tenant_context(self.tenant): groupC = Group.objects.create(name='groupC') url = reverse('group-roles', kwargs={'uuid': groupC.uuid}) client = APIClient() test_data = {'roles': ['abc123', self.roleB.uuid]} self.assertCountEqual([], list(groupC.roles())) response = client.post(url, test_data, format='json', **self.headers) self.assertCountEqual([], list(groupC.roles())) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_add_group_multiple_roles_not_found_success(self): """Test that adding roles to a group skips ids not found, and returns success.""" with tenant_context(self.tenant): groupC = Group.objects.create(name='groupC') url = reverse('group-roles', kwargs={'uuid': groupC.uuid}) client = APIClient() test_data = {'roles': [self.dummy_role_id, self.roleB.uuid]} self.assertCountEqual([], list(groupC.roles())) response = client.post(url, test_data, format='json', **self.headers) self.assertCountEqual([self.roleB], list(groupC.roles())) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_remove_group_roles_success(self): """Test that removing a role from a group returns successfully.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) client = APIClient() url = '{}?roles={}'.format(url, self.role.uuid) self.policyB.roles.add(self.role) self.policyB.save() self.assertCountEqual([self.role], list(self.group.roles())) response = client.delete(url, format='json', **self.headers) self.assertCountEqual([], list(self.group.roles())) self.assertCountEqual([self.role, self.roleB], list(self.groupB.roles())) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_remove_group_multiple_roles_success(self): """Test that removing multiple roles from a group returns successfully.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) client = APIClient() url = '{}?roles={},{}'.format(url, self.role.uuid, self.roleB.uuid) self.policy.roles.add(self.roleB) self.policy.save() self.assertCountEqual([self.role, self.roleB], list(self.group.roles())) response = client.delete(url, format='json', **self.headers) self.assertCountEqual([], list(self.group.roles())) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_remove_group_multiple_roles_invalid(self): """Test that removing invalid roles from a group fails the request and does not remove any.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) client = APIClient() url = '{}?roles={},{}'.format(url, 'abc123', self.roleB.uuid) self.policy.roles.add(self.roleB) self.policy.save() self.assertCountEqual([self.role, self.roleB], list(self.group.roles())) response = client.delete(url, format='json', **self.headers) self.assertCountEqual([self.role, self.roleB], list(self.group.roles())) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_remove_group_multiple_roles_not_found_success(self): """Test that removing roles from a group skips ids not found, and returns success.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) client = APIClient() url = '{}?roles={},{},{}'.format(url, self.role.uuid, self.roleB.uuid, self.dummy_role_id) self.policy.roles.add(self.roleB) self.policy.save() self.assertCountEqual([self.role, self.roleB], list(self.group.roles())) response = client.delete(url, format='json', **self.headers) self.assertCountEqual([], list(self.group.roles())) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_remove_group_roles_invalid(self): """Test that removing a role returns an error with invalid data format.""" url = reverse('group-roles', kwargs={'uuid': self.group.uuid}) client = APIClient() response = client.delete(url, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_admin_RonR(self): """Test that a admin user can group RBAC resources""" url = '{}?application={}'.format(reverse('group-list'), 'rbac') client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK)
class InternalViewsetTests(IdentityRequest): """Test the internal viewset.""" def valid_destructive_time(): return datetime.utcnow().replace(tzinfo=pytz.UTC) + timedelta(hours=1) def invalid_destructive_time(): return datetime.utcnow().replace(tzinfo=pytz.UTC) - timedelta(hours=1) def setUp(self): """Set up the internal viewset tests.""" super().setUp() self.client = APIClient() self.customer = self._create_customer_data() self.internal_request_context = self._create_request_context( self.customer, self.user_data, create_customer=False, is_internal=True, create_tenant=True ) self.request = self.internal_request_context["request"] user = User() user.username = self.user_data["username"] user.account = self.customer_data["account_id"] self.request.user = user with tenant_context(self.tenant): self.group = Group(name="System Group", system=True) self.group.save() self.role = Role.objects.create(name="System Role", description="A role for a group.", system=True) self.policy = Policy.objects.create(name="System Policy", group=self.group) self.policy.roles.add(self.role) self.policy.save() self.group.policies.add(self.policy) self.group.save() def tearDown(self): """Tear down internal viewset tests.""" with tenant_context(self.tenant): Group.objects.all().delete() Role.objects.all().delete() Policy.objects.all().delete() def test_delete_tenant_disallowed(self): """Test that we cannot delete a tenant when disallowed.""" response = self.client.delete(f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.content.decode(), "Destructive operations disallowed.") @override_settings(INTERNAL_DESTRUCTIVE_API_OK_UNTIL=invalid_destructive_time()) def test_delete_tenant_disallowed_with_past_timestamp(self): """Test that we cannot delete a tenant when disallowed.""" response = self.client.delete(f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.content.decode(), "Destructive operations disallowed.") @override_settings(INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time()) @patch.object(Tenant, "delete") def test_delete_tenant_allowed_and_unmodified(self, mock): """Test that we can delete a tenant when allowed and unmodified.""" response = self.client.delete(f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) @override_settings(INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time()) def test_delete_tenant_allowed_but_multiple_groups(self): """Test that we cannot delete a tenant when allowed but modified.""" with tenant_context(self.tenant): Group.objects.create(name="Custom Group") response = self.client.delete(f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.content.decode(), "Tenant cannot be deleted.") @override_settings(INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time()) def test_delete_tenant_allowed_but_group_is_not_system(self): """Test that we cannot delete a tenant when allowed but modified.""" with tenant_context(self.tenant): self.group.system = False self.group.save() response = self.client.delete(f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.content.decode(), "Tenant cannot be deleted.") @override_settings(INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time()) def test_delete_tenant_allowed_but_role_is_not_system(self): """Test that we cannot delete a tenant when allowed but modified.""" with tenant_context(self.tenant): self.role.system = False self.role.save() response = self.client.delete(f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.content.decode(), "Tenant cannot be deleted.") @override_settings(INTERNAL_DESTRUCTIVE_API_OK_UNTIL=valid_destructive_time()) def test_delete_tenant_allowed_but_custom_one_role_is_not_system(self): """Test that we cannot delete a tenant when allowed but modified.""" with tenant_context(self.tenant): Role.objects.create(name="Custom Role") response = self.client.delete(f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.content.decode(), "Tenant cannot be deleted.") def test_list_unmodified_tenants(self): """Test that only unmodified tenants are returned""" modified_tenant_groups = Tenant.objects.create(schema_name="acctmodifiedgroups") modified_tenant_roles = Tenant.objects.create(schema_name="acctmodifiedroles") unmodified_tenant_2 = Tenant.objects.create(schema_name="acctunmodified2") with tenant_context(modified_tenant_groups): Group.objects.create(name="Custom Group") with tenant_context(modified_tenant_roles): Role.objects.create(name="Custom Role") with tenant_context(unmodified_tenant_2): Group.objects.create(name="System Group", system=True) Role.objects.create(name="System Role", system=True) response = self.client.get(f"/_private/api/tenant/unmodified/", **self.request.META) response_data = json.loads(response.content) self.assertCountEqual( response_data["unmodified_tenants"], [self.tenant.schema_name, unmodified_tenant_2.schema_name] ) self.assertEqual(response_data["unmodified_tenants_count"], 2) self.assertEqual(response_data["total_tenants_count"], 4) self.assertEqual(Tenant.objects.count(), 4) response = self.client.get(f"/_private/api/tenant/unmodified/?limit=2", **self.request.META) response_data = json.loads(response.content) self.assertEqual(response_data["total_tenants_count"], 2) response = self.client.get(f"/_private/api/tenant/unmodified/?limit=2&offset=3", **self.request.META) response_data = json.loads(response.content) self.assertEqual(response_data["total_tenants_count"], 1) @patch("management.tasks.run_migrations_in_worker.delay") def test_run_migrations(self, migration_mock): """Test that we can trigger migrations.""" response = self.client.post(f"/_private/api/migrations/run/", **self.request.META) migration_mock.assert_called_once() self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) self.assertEqual(response.content.decode(), "Migrations are running in a background worker.") def test_list_migration_progress(self): """Test that we can get the status of migrations.""" migration_name = "foo_migration" app_name = "foo_app" tenant_migrations_complete = Tenant.objects.create(schema_name="acctcomplete") tenant_migrations_incomplete = Tenant.objects.create(schema_name="acctincomplete") with tenant_context(tenant_migrations_complete): migrations_have_run = MigrationRecorder.Migration.objects.create(name=migration_name, app=app_name) url = f"/_private/api/migrations/progress/?migration_name={migration_name}&app={app_name}" response = self.client.get(url, **self.request.META) response_data = json.loads(response.content) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response_data["migration_name"], migration_name) self.assertEqual(response_data["app_name"], app_name) self.assertEqual(response_data["tenants_completed_count"], 1) self.assertEqual(response_data["percent_completed"], 33) self.assertIn("acctincomplete", response_data["incomplete_tenants"]) self.assertNotIn("acctcomplete", response_data["incomplete_tenants"]) self.assertEqual(len(response_data["incomplete_tenants"]), 2) def test_list_migration_progress_without_migration_name(self): """Test that we get a 400 when no migration name supplied.""" url = f"/_private/api/migrations/progress/" response = self.client.get(url, **self.request.META) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.content.decode(), "Please specify a migration name in the `?migration_name=` param.") @patch("management.tasks.run_seeds_in_worker.delay") def test_run_seeds_with_defaults(self, seed_mock): """Test that we can trigger seeds with defaults.""" response = self.client.post(f"/_private/api/seeds/run/", **self.request.META) seed_mock.assert_called_once_with({}) self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) self.assertEqual(response.content.decode(), "Seeds are running in a background worker.") @patch("management.tasks.run_seeds_in_worker.delay") def test_run_seeds_with_options(self, seed_mock): """Test that we can trigger seeds with options.""" response = self.client.post(f"/_private/api/seeds/run/?seed_types=roles,groups", **self.request.META) seed_mock.assert_called_once_with({"roles": True, "groups": True}) self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) self.assertEqual(response.content.decode(), "Seeds are running in a background worker.") @patch("management.tasks.run_seeds_in_worker.delay") def test_run_seeds_with_invalid_options(self, seed_mock): """Test that we get a 400 when invalid option supplied.""" response = self.client.post(f"/_private/api/seeds/run/?seed_types=foo,bar", **self.request.META) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) seed_mock.assert_not_called() self.assertEqual( response.content.decode(), "Valid options for \"seed_types\": ['permissions', 'roles', 'groups']." )
class RoleViewsetTests(IdentityRequest): """Test the role viewset.""" def setUp(self): """Set up the role viewset tests.""" super().setUp() request = self.request_context['request'] user = User(username=self.user_data['username'], tenant=self.tenant) user.save() request.user = user sys_role_config = {'name': 'system_role', 'system': True} def_role_config = {'name': 'default_role', 'platform_default': True} with tenant_context(self.tenant): self.principal = Principal(username=self.user_data['username']) self.principal.save() self.group = Group(name='groupA') self.group.save() self.group.principals.add(self.principal) self.group.save() self.sysRole = Role(**sys_role_config) self.sysRole.save() self.defRole = Role(**def_role_config) self.defRole.save() def tearDown(self): """Tear down role viewset tests.""" User.objects.all().delete() with tenant_context(self.tenant): Group.objects.all().delete() Principal.objects.all().delete() Role.objects.all().delete() def create_role(self, role_name, in_access_data=None): """Create a role.""" access_data = [{ 'permission': 'app:*:*', 'resourceDefinitions': [{ 'attributeFilter': { 'key': 'key1', 'operation': 'equal', 'value': 'value1' } }] }] if in_access_data: access_data = in_access_data test_data = {'name': role_name, 'access': access_data} # create a role url = reverse('role-list') client = APIClient() response = client.post(url, test_data, format='json', **self.headers) return response def test_create_role_success(self): """Test that we can create a role.""" role_name = 'roleA' access_data = [{ 'permission': 'app:*:*', 'resourceDefinitions': [{ 'attributeFilter': { 'key': 'keyA', 'operation': 'equal', 'value': 'valueA' } }] }] response = self.create_role(role_name, access_data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) # test that we can retrieve the role url = reverse('role-detail', kwargs={'uuid': response.data.get('uuid')}) client = APIClient() response = client.get(url, **self.headers) self.assertIsNotNone(response.data.get('uuid')) self.assertIsNotNone(response.data.get('name')) self.assertEqual(role_name, response.data.get('name')) self.assertIsInstance(response.data.get('access'), list) self.assertEqual(access_data, response.data.get('access')) def test_create_role_invalid(self): """Test that creating an invalid role returns an error.""" test_data = {} url = reverse('role-list') client = APIClient() response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_create_role_invalid_permission(self): """Test that creating an invalid role returns an error.""" test_data = { 'name': 'role1', 'access': [{ 'permission': 'foo:bar', 'resourceDefinitions': [] }] } url = reverse('role-list') client = APIClient() response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_create_role_whitelist(self): """Test that we can create a role in a whitelisted application via API.""" role_name = 'C-MRole' access_data = [{ 'permission': 'cost-management:*:*', 'resourceDefinitions': [{ 'attributeFilter': { 'key': 'keyA', 'operation': 'equal', 'value': 'valueA' } }] }] response = self.create_role(role_name, access_data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) # test that we can retrieve the role url = reverse('role-detail', kwargs={'uuid': response.data.get('uuid')}) client = APIClient() response = client.get(url, **self.headers) self.assertIsNotNone(response.data.get('uuid')) self.assertIsNotNone(response.data.get('name')) self.assertEqual(role_name, response.data.get('name')) self.assertIsInstance(response.data.get('access'), list) self.assertEqual(access_data, response.data.get('access')) def test_create_role_whitelist_fail(self): """Test that we cannot create a role for a non-whitelisted app.""" role_name = 'roleFail' access_data = [{ 'permission': 'someApp:*:*', 'resourceDefinitions': [{ 'attributeFilter': { 'key': 'keyA', 'operation': 'equal', 'value': 'valueA' } }] }] response = self.create_role(role_name, access_data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_create_role_fail_with_access_not_list(self): """Test that we cannot create a role for a non-whitelisted app.""" role_name = 'AccessNotList' access_data = 'some data' response = self.create_role(role_name, access_data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_create_role_fail_with_invalid_access(self): """Test that we cannot create a role for invalid access data.""" role_name = 'AccessInvalid' access_data = [{'per': 'some data'}] response = self.create_role(role_name, access_data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_read_role_invalid(self): """Test that reading an invalid role returns an error.""" url = reverse('role-detail', kwargs={'uuid': uuid4()}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_read_role_list_success(self): """Test that we can read a list of roles.""" role_name = 'roleA' response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get('uuid') # list a role url = reverse('role-list') client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) for keyname in ['meta', 'links', 'data']: self.assertIn(keyname, response.data) self.assertIsInstance(response.data.get('data'), list) self.assertEqual(len(response.data.get('data')), 3) role = None for iterRole in response.data.get('data'): self.assertIsNotNone(iterRole.get('name')) if iterRole.get('name') == role_name: role = iterRole break self.assertEqual(role.get('name'), role_name) def test_update_role_success(self): """Test that we can update an existing role.""" role_name = 'roleA' response = self.create_role(role_name) updated_name = role_name + '_update' role_uuid = response.data.get('uuid') test_data = response.data test_data['name'] = updated_name del test_data['uuid'] url = reverse('role-detail', kwargs={'uuid': role_uuid}) client = APIClient() response = client.put(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get('uuid')) self.assertEqual(updated_name, response.data.get('name')) def test_update_role_invalid(self): """Test that updating an invalid role returns an error.""" url = reverse('role-detail', kwargs={'uuid': uuid4()}) client = APIClient() response = client.put(url, {}, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_delete_role_success(self): """Test that we can delete an existing role.""" role_name = 'roleA' response = self.create_role(role_name) role_uuid = response.data.get('uuid') url = reverse('role-detail', kwargs={'uuid': role_uuid}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) # verify the role no longer exists response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_delete_system_role(self): """Test that system roles are protected from deletion""" url = reverse('role-detail', kwargs={'uuid': self.sysRole.uuid}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) # verify the role still exists response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_delete_default_role(self): """Test that default roles are protected from deletion""" url = reverse('role-detail', kwargs={'uuid': self.defRole.uuid}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) # verify the role still exists response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_delete_role_invalid(self): """Test that deleting an invalid role returns an error.""" url = reverse('role-detail', kwargs={'uuid': uuid4()}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
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)
class GroupViewsetTests(IdentityRequest): """Test the group viewset.""" def setUp(self): """Set up the group viewset tests.""" super().setUp() request = self.request_context["request"] user = User() user.username = self.user_data["username"] user.account = self.customer_data["account_id"] request.user = user self.dummy_role_id = uuid4() with tenant_context(self.tenant): self.principal = Principal(username=self.user_data["username"]) self.principal.save() self.principalB = Principal(username="******") self.principalB.save() self.principalC = Principal(username="******") self.principalC.save() self.group = Group(name="groupA") self.group.save() self.role = Role.objects.create(name="roleA", description="A role for a group.", system=True) self.policy = Policy.objects.create(name="policyA", group=self.group) self.policy.roles.add(self.role) self.policy.save() self.group.policies.add(self.policy) self.group.principals.add(self.principal, self.principalB) self.group.save() self.defGroup = Group(name="groupDef", platform_default=True, system=True) self.defGroup.save() self.defGroup.principals.add(self.principal) self.defGroup.save() self.emptyGroup = Group(name="groupE") self.emptyGroup.save() self.groupB = Group.objects.create(name="groupB") self.groupB.principals.add(self.principal) self.policyB = Policy.objects.create(name="policyB", group=self.groupB) self.roleB = Role.objects.create(name="roleB", system=False) self.policyB.roles.add(self.roleB) self.policyB.save() # role that's not assigned to principal self.roleOrphan = Role.objects.create(name="roleOrphan") # group that associates with multipal roles self.groupMultiRole = Group.objects.create(name="groupMultiRole") self.policyMultiRole = Policy.objects.create(name="policyMultiRole") self.policyMultiRole.roles.add(self.role) self.policyMultiRole.roles.add(self.roleB) self.groupMultiRole.policies.add(self.policyMultiRole) def tearDown(self): """Tear down group viewset tests.""" with tenant_context(self.tenant): Group.objects.all().delete() Principal.objects.all().delete() Role.objects.all().delete() Policy.objects.all().delete() @patch( "management.principal.proxy.PrincipalProxy.request_filtered_principals", return_value={"status_code": 200, "data": []}, ) def test_create_group_success(self, mock_request): """Test that we can create a group.""" group_name = "groupC" test_data = {"name": group_name} # create a group url = reverse("group-list") client = APIClient() response = client.post(url, test_data, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_201_CREATED) # test that we can retrieve the group url = reverse("group-detail", kwargs={"uuid": response.data.get("uuid")}) response = client.get(url, **self.headers) self.assertIsNotNone(response.data.get("uuid")) self.assertIsNotNone(response.data.get("name")) self.assertEqual(group_name, response.data.get("name")) def test_create_default_group(self): """Test that system groups can be created.""" group_name = "groupDef" # test group retrieval client = APIClient() url = reverse("group-detail", kwargs={"uuid": self.defGroup.uuid}) response = client.get(url, **self.headers) self.assertIsNotNone(response.data.get("uuid")) self.assertIsNotNone(response.data.get("name")) self.assertTrue(response.data.get("platform_default")) self.assertEqual(group_name, response.data.get("name")) def test_create_group_invalid(self): """Test that creating an invalid group returns an error.""" test_data = {} url = reverse("group-list") client = APIClient() response = client.post(url, test_data, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_group_filter_by_any_role_name_in_a_list_success(self): """Test default behaviour that filter groups by any role name in a list success.""" url = "{}?role_names={},{}".format(reverse("group-list"), "Rolea", "RoleB") client = APIClient() response = client.get(url, **self.headers) self.assertTrue(response.data.get("meta").get("count") == 3) expected_groups = [self.group.name, self.groupB.name, self.groupMultiRole.name] self.assertEqual(expected_groups, [group.get("name") for group in response.data.get("data")]) def test_group_filter_by_all_role_name_in_a_list_success(self): """Test that filter groups by all role names in a list success.""" url = "{}?role_names={},{}&role_discriminator=all".format(reverse("group-list"), "Rolea", "roleB") client = APIClient() response = client.get(url, **self.headers) self.assertTrue(response.data.get("meta").get("count") == 1) expected_groups = [self.groupMultiRole.name] self.assertEqual(expected_groups, [group.get("name") for group in response.data.get("data")]) def test_group_filter_with_invalid_discriminator_failure(self): """Test that filter groups with invalid discriminator returns failed validation.""" url = "{}?role_names={},{}&role_discriminator=invalid".format(reverse("group-list"), "roleA", "ROLEb") client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @patch( "management.principal.proxy.PrincipalProxy.request_filtered_principals", return_value={"status_code": 200, "data": []}, ) def test_read_group_success(self, mock_request): """Test that we can read a group.""" url = reverse("group-detail", kwargs={"uuid": self.group.uuid}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get("name")) self.assertEqual(self.group.name, response.data.get("name")) self.assertEqual(len(response.data.get("roles")), 1) self.assertEqual(response.data.get("roles")[0]["uuid"], str(self.role.uuid)) def test_read_group_invalid(self): """Test that reading an invalid group returns an error.""" url = reverse("group-detail", kwargs={"uuid": uuid4()}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_read_group_nonguid(self): """Test that reading a group with an invalid UUID returns an error.""" url = reverse("group-detail", kwargs={"uuid": "potato"}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_read_group_list_success(self): """Test that we can read a list of groups.""" url = reverse("group-list") client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) for keyname in ["meta", "links", "data"]: self.assertIn(keyname, response.data) self.assertIsInstance(response.data.get("data"), list) self.assertEqual(len(response.data.get("data")), 5) group = response.data.get("data")[0] self.assertIsNotNone(group.get("name")) self.assertEqual(group.get("name"), self.group.name) def test_get_group_by_partial_name_by_default(self): """Test that getting groups by name returns partial match by default.""" url = reverse("group-list") url = "{}?name={}".format(url, "group") client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.data.get("meta").get("count"), 5) def test_get_group_by_partial_name_explicit(self): """Test that getting groups by name returns partial match when specified.""" url = reverse("group-list") url = "{}?name={}&name_match={}".format(url, "group", "partial") client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.data.get("meta").get("count"), 5) def test_get_group_by_name_invalid_criteria(self): """Test that getting groups by name fails with invalid name_match.""" url = reverse("group-list") url = "{}?name={}&name_match={}".format(url, "group", "bad_criteria") client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_get_group_by_exact_name_match(self): """Test that getting groups by name returns exact match.""" url = reverse("group-list") url = "{}?name={}&name_match={}".format(url, self.group.name, "exact") client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.data.get("meta").get("count"), 1) group = response.data.get("data")[0] self.assertEqual(group.get("name"), self.group.name) def test_get_group_by_exact_name_no_match(self): """Test that getting groups by name returns no results with exact match.""" url = reverse("group-list") url = "{}?name={}&name_match={}".format(url, "group", "exact") client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.data.get("meta").get("count"), 0) def test_filter_group_list_by_uuid_success(self): """Test that we can filter a list of groups by uuid.""" url = f"{reverse('group-list')}?uuid={self.group.uuid}" client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) for keyname in ["meta", "links", "data"]: self.assertIn(keyname, response.data) self.assertIsInstance(response.data.get("data"), list) self.assertEqual(len(response.data.get("data")), 1) group = response.data.get("data")[0] self.assertIsNotNone(group.get("name")) self.assertEqual(group.get("name"), self.group.name) def test_filter_group_list_by_uuid_multiple(self): """Test that we can filter a list of groups by uuid.""" url = f"{reverse('group-list')}?uuid={self.group.uuid},{self.groupB.uuid}" client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) for keyname in ["meta", "links", "data"]: self.assertIn(keyname, response.data) self.assertIsInstance(response.data.get("data"), list) self.assertEqual(len(response.data.get("data")), 2) group = response.data.get("data")[0] self.assertIsNotNone(group.get("name")) self.assertEqual(group.get("name"), self.group.name) group = response.data.get("data")[1] self.assertIsNotNone(group.get("name")) self.assertEqual(group.get("name"), self.groupB.name) def test_filter_group_list_by_uuid_fail(self): """Test that filtering by a nonexistant uuid returns nothing.""" url = f"{reverse('group-list')}?uuid={uuid4()}" client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) for keyname in ["meta", "links", "data"]: self.assertIn(keyname, response.data) self.assertEqual(response.data.get("data"), []) self.assertEqual(len(response.data.get("data")), 0) @patch( "management.principal.proxy.PrincipalProxy.request_filtered_principals", return_value={"status_code": 200, "data": []}, ) def test_update_group_success(self, mock_request): """Test that we can update an existing group.""" group = Group.objects.first() updated_name = group.name + "_update" test_data = {"name": updated_name} url = reverse("group-detail", kwargs={"uuid": group.uuid}) client = APIClient() response = client.put(url, test_data, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get("uuid")) self.assertEqual(updated_name, response.data.get("name")) def test_update_default_group(self): """Test that platform_default groups are protected from updates""" url = reverse("group-detail", kwargs={"uuid": self.defGroup.uuid}) test_data = {"name": self.defGroup.name + "_updated"} client = APIClient() response = client.put(url, test_data, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_update_group_invalid(self): """Test that updating an invalid group returns an error.""" url = reverse("group-detail", kwargs={"uuid": uuid4()}) client = APIClient() response = client.put(url, {}, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_delete_group_success(self): """Test that we can delete an existing group.""" group = Group.objects.first() url = reverse("group-detail", kwargs={"uuid": group.uuid}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) # verify the group no longer exists response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_delete_default_group(self): """Test that platform_default groups are protected from deletion""" url = reverse("group-detail", kwargs={"uuid": self.defGroup.uuid}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_delete_group_invalid(self): """Test that deleting an invalid group returns an error.""" url = reverse("group-detail", kwargs={"uuid": uuid4()}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_group_principals_invalid_method(self): """Test that using an unsupported REST method returns an error.""" url = reverse("group-principals", kwargs={"uuid": uuid4()}) client = APIClient() response = client.put(url, {}, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) @patch( "management.principal.proxy.PrincipalProxy.request_filtered_principals", return_value={ "status_code": status.HTTP_500_INTERNAL_SERVER_ERROR, "errors": [ { "detail": "Unexpected error.", "status": status.HTTP_500_INTERNAL_SERVER_ERROR, "source": "principals", } ], }, ) def test_add_group_principals_failure(self, mock_request): """Test that adding a principal to a group returns has proper response when it is failed.""" url = reverse("group-principals", kwargs={"uuid": self.group.uuid}) client = APIClient() new_username = uuid4() test_data = {"principals": [{"username": self.principal.username}, {"username": new_username}]} response = client.post(url, test_data, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR) self.assertEqual(response.data[0]["detail"], "Unexpected error.") self.assertEqual(response.data[0]["status"], 500) self.assertEqual(response.data[0]["source"], "principals") @patch( "management.principal.proxy.PrincipalProxy.request_filtered_principals", return_value={"status_code": 200, "data": [{"username": "******"}]}, ) def test_add_group_principals_success(self, mock_request): """Test that adding a principal to a group returns successfully.""" # Create a group and a cross account user. with tenant_context(self.tenant): test_group = Group.objects.create(name="test") cross_account_user = Principal.objects.create(username="******", cross_account=True) url = reverse("group-principals", kwargs={"uuid": test_group.uuid}) client = APIClient() test_data = {"principals": [{"username": "******"}, {"username": "******"}]} response = client.post(url, test_data, format="json", **self.headers) # Only the user exists in IT will be added to the group. self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(response.data.get("principals")), 1) self.assertEqual(response.data.get("principals")[0], {"username": "******"}) test_group.delete() cross_account_user.delete() @patch( "management.principal.proxy.PrincipalProxy.request_filtered_principals", return_value={"status_code": 200, "data": []}, ) def test_get_group_principals_empty(self, mock_request): """Test that getting principals from an empty group returns successfully.""" client = APIClient() url = reverse("group-principals", kwargs={"uuid": self.emptyGroup.uuid}) response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data.get("meta").get("count"), 0) self.assertEqual(response.data.get("data"), []) @patch( "management.principal.proxy.PrincipalProxy.request_filtered_principals", return_value={"status_code": 200, "data": []}, ) def test_get_group_principals_nonempty(self, mock_request): """Test that getting principals from a nonempty group returns successfully.""" mock_request.return_value["data"] = [ {"username": self.principal.username}, {"username": self.principalB.username}, ] client = APIClient() url = reverse("group-principals", kwargs={"uuid": self.group.uuid}) response = client.get(url, **self.headers) call_args, kwargs = mock_request.call_args_list[0] username_arg = call_args[0] for username in [self.principal.username, self.principalB.username]: self.assertTrue(username in username_arg) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data.get("meta").get("count"), 2) self.assertEqual(response.data.get("data")[0].get("username"), self.principal.username) self.assertEqual(response.data.get("data")[1].get("username"), self.principalB.username) def test_remove_group_principals_success(self): """Test that removing a principal to a group returns successfully.""" url = reverse("group-principals", kwargs={"uuid": self.group.uuid}) client = APIClient() url = "{}?usernames={}".format(url, self.principal.username) response = client.delete(url, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_remove_group_principals_invalid(self): """Test that removing a principal returns an error with invalid data format.""" url = reverse("group-principals", kwargs={"uuid": self.group.uuid}) client = APIClient() response = client.delete(url, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @patch( "management.principal.proxy.PrincipalProxy.request_filtered_principals", return_value={"status_code": 200, "data": []}, ) def test_get_group_by_username(self, mock_request): """Test that getting groups for a principal returns successfully.""" url = reverse("group-list") url = "{}?username={}".format(url, self.principal.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.data.get("meta").get("count"), 3) # User who is not added to a group explicitly will return platform default group url = reverse("group-list") url = "{}?username={}".format(url, self.principalC.username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.data.get("meta").get("count"), 1) # Return bad request when user does not exist url = reverse("group-list") url = "{}?username={}".format(url, uuid4()) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_get_group_by_username_for_cross_account_principal(self): """Test that getting groups for a cross account principal won't have platform default group.""" with tenant_context(self.tenant): self.principalC.cross_account = True self.principalC.save() url = reverse("group-list") url = "{}?username={}".format(url, self.principalC.username) client = APIClient() # User who is not added to a group explicitly will not return platform default group if he is cross account principal. response = client.get(url, **self.headers) self.assertEqual(response.data.get("meta").get("count"), 0) def test_get_group_by_username_with_capitalization(self): """Test that getting groups for a user name with capitalization returns successfully.""" url = reverse("group-list") username = "".join(random.choice([k.upper(), k]) for k in self.principal.username) url = "{}?username={}".format(url, username) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.data.get("meta").get("count"), 3) def test_get_group_roles_success(self): """Test that getting roles for a group returns successfully.""" url = reverse("group-roles", kwargs={"uuid": self.group.uuid}) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get("data") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 1) self.assertEqual(roles[0].get("uuid"), str(self.role.uuid)) self.assertEqual(roles[0].get("name"), self.role.name) self.assertEqual(roles[0].get("description"), self.role.description) def test_get_group_roles_with_exclude_false_success(self): """Test that getting roles with 'exclude=false' for a group works as default.""" url = "%s?exclude=FALSE" % (reverse("group-roles", kwargs={"uuid": self.group.uuid})) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get("data") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 1) self.assertEqual(roles[0].get("uuid"), str(self.role.uuid)) self.assertEqual(roles[0].get("name"), self.role.name) self.assertEqual(roles[0].get("description"), self.role.description) def test_get_group_roles_with_exclude_success(self): """Test that getting roles with 'exclude=True' for a group returns successfully.""" url = "%s?exclude=True" % (reverse("group-roles", kwargs={"uuid": self.group.uuid})) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get("data") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 2) self.assertTrue(role.uuid in [self.roleB.uuid, self.roleOrphan.uuid] for role in roles) def test_get_group_roles_with_exclude_in_principal_scope_success(self): """Test that getting roles with 'exclude=True' for a group in principal scope.""" url = "%s?exclude=True&scope=principal" % (reverse("group-roles", kwargs={"uuid": self.group.uuid})) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get("data") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 1) self.assertEqual(roles[0].get("uuid"), str(self.roleB.uuid)) self.assertEqual(roles[0].get("name"), self.roleB.name) self.assertEqual(roles[0].get("description"), self.roleB.description) def test_get_group_roles_ordered(self): """Test getting roles with 'order_by=' returns properly.""" url = f"{reverse('group-roles', kwargs={'uuid': self.group.uuid})}?order_by=-name" client = APIClient() test_data = {"roles": [self.roleB.uuid]} response = client.post(url, test_data, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) response = client.get(url, **self.headers) roles = response.data.get("data") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 2) self.assertEqual(roles[0].get("name"), self.roleB.name) self.assertEqual(roles[1].get("name"), self.role.name) def test_exclude_input_invalid(self): """Test that getting roles with 'exclude=' for a group returns failed validation.""" url = "%s?exclude=sth" % (reverse("group-roles", kwargs={"uuid": self.group.uuid})) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_role_name_filter_for_group_roles_no_match(self): """Test role_name filter for getting roles for a group.""" url = reverse("group-roles", kwargs={"uuid": self.group.uuid}) url = "{}?role_name=test".format(url) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get("data") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 0) def test_role_name_filter_for_group_roles_match(self): """Test role_name filter for getting roles for a group.""" url = reverse("group-roles", kwargs={"uuid": self.group.uuid}) url = "{}?role_name={}".format(url, self.role.name) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get("data") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 1) self.assertEqual(roles[0].get("uuid"), str(self.role.uuid)) def test_role_display_name_filter_for_group_roles_no_match(self): """Test role_display_name filter for getting roles for a group.""" url = reverse("group-roles", kwargs={"uuid": self.group.uuid}) url = "{}?role_display_name=test".format(url) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get("data") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 0) def test_role_display_name_filter_for_group_roles_match(self): """Test role_display_name filter for getting roles for a group.""" url = reverse("group-roles", kwargs={"uuid": self.group.uuid}) url = "{}?role_display_name={}".format(url, self.role.name) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get("data") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 1) self.assertEqual(roles[0].get("uuid"), str(self.role.uuid)) def test_role_description_filter_for_group_roles_no_match(self): """Test role_description filter for getting roles for a group.""" url = reverse("group-roles", kwargs={"uuid": self.group.uuid}) url = "{}?role_description=test".format(url) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get("data") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 0) def test_role_description_filter_for_group_roles_match(self): """Test role_description filter for getting roles for a group.""" url = reverse("group-roles", kwargs={"uuid": self.group.uuid}) url = "{}?role_description={}".format(url, self.role.description) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get("data") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 1) self.assertEqual(roles[0].get("uuid"), str(self.role.uuid)) def test_all_role_filters_for_group_roles_no_match(self): """Test role filters for getting roles for a group.""" url = reverse("group-roles", kwargs={"uuid": self.group.uuid}) url = "{}?role_description=test&role_name=test".format(url) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get("data") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 0) def test_all_role_filters_for_group_roles_match(self): """Test role filters for getting roles for a group.""" url = reverse("group-roles", kwargs={"uuid": self.group.uuid}) url = "{}?role_description={}&role_name={}".format(url, self.role.description, self.role.name) client = APIClient() response = client.get(url, **self.headers) roles = response.data.get("data") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(roles), 1) self.assertEqual(roles[0].get("uuid"), str(self.role.uuid)) def test_role_system_filter_for_group_roles(self): """Test role_system filter for getting roles for a group.""" base_url = reverse("group-roles", kwargs={"uuid": self.groupMultiRole.uuid}) client = APIClient() response = client.get(base_url, **self.headers) self.assertEqual(len(response.data.get("data")), 2) url = f"{base_url}?role_system=true" client = APIClient() response = client.get(url, **self.headers) self.assertEqual(len(response.data.get("data")), 1) role = response.data.get("data")[0] self.assertEqual(role.get("system"), True) url = f"{base_url}?role_system=false" client = APIClient() response = client.get(url, **self.headers) self.assertEqual(len(response.data.get("data")), 1) role = response.data.get("data")[0] self.assertEqual(role.get("system"), False) @patch( "management.principal.proxy.PrincipalProxy.request_filtered_principals", return_value={"status_code": 200, "data": []}, ) def test_principal_username_filter_for_group_roles_no_match(self, mock_request): """Test principal_username filter for getting principals for a group.""" url = reverse("group-principals", kwargs={"uuid": self.group.uuid}) url = "{}?principal_username=test".format(url) client = APIClient() response = client.get(url, **self.headers) principals = response.data.get("data") mock_request.assert_called_with([], ANY, options={"sort_order": None}) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(principals), 0) @patch( "management.principal.proxy.PrincipalProxy.request_filtered_principals", return_value={"status_code": 200, "data": [{"username": "******"}]}, ) def test_principal_username_filter_for_group_roles_match(self, mock_request): """Test principal_username filter for getting principals for a group.""" url = reverse("group-principals", kwargs={"uuid": self.group.uuid}) url = "{}?principal_username={}".format(url, self.principal.username) client = APIClient() response = client.get(url, **self.headers) principals = response.data.get("data") mock_request.assert_called_with([self.principal.username], ANY, options={"sort_order": None}) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(principals), 1) @patch( "management.principal.proxy.PrincipalProxy.request_filtered_principals", return_value={"status_code": 200, "data": [{"username": "******"}]}, ) def test_principal_get_ordering_username_success(self, mock_request): """Test that passing a username order_by parameter calls the proxy correctly.""" url = f"{reverse('group-principals', kwargs={'uuid': self.group.uuid})}?order_by=username" client = APIClient() response = client.get(url, **self.headers) principals = response.data.get("data") expected_principals = sorted([self.principal.username, self.principalB.username]) mock_request.assert_called_with(expected_principals, ANY, options={"sort_order": "asc"}) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(principals), 1) @patch( "management.principal.proxy.PrincipalProxy.request_filtered_principals", return_value={"status_code": 200, "data": [{"username": "******"}]}, ) def test_principal_get_ordering_nonusername_fail(self, mock_request): """Test that passing a username order_by parameter calls the proxy correctly.""" url = f"{reverse('group-principals', kwargs={'uuid': self.group.uuid})}?order_by=best_joke" client = APIClient() response = client.get(url, **self.headers) principals = response.data.get("data") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(principals, None) def test_add_group_roles_system_policy_create_success(self): """Test that adding a role to a group without a system policy returns successfully.""" url = reverse("group-roles", kwargs={"uuid": self.group.uuid}) client = APIClient() test_data = {"roles": [self.roleB.uuid, self.dummy_role_id]} self.assertCountEqual([self.role], list(self.group.roles())) self.assertCountEqual([self.policy], list(self.group.policies.all())) response = client.post(url, test_data, format="json", **self.headers) roles = response.data.get("data") system_policies = Policy.objects.filter(system=True) system_policy = system_policies.get(group=self.group) self.assertEqual(len(system_policies), 1) self.assertCountEqual([system_policy, self.policy], list(self.group.policies.all())) self.assertCountEqual([self.roleB], list(system_policy.roles.all())) self.assertCountEqual([self.role], list(self.policy.roles.all())) self.assertCountEqual([self.role, self.roleB], list(self.group.roles())) self.assertEqual(len(roles), 2) self.assertEqual(roles[0].get("uuid"), str(self.role.uuid)) self.assertEqual(roles[0].get("name"), self.role.name) self.assertEqual(roles[0].get("description"), self.role.description) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_system_flag_update_on_add(self): """Test that adding a role to a platform_default group flips the system flag.""" url = reverse("group-roles", kwargs={"uuid": self.defGroup.uuid}) client = APIClient() test_data = {"roles": [self.roleB.uuid, self.dummy_role_id]} self.assertTrue(self.defGroup.system) response = client.post(url, test_data, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.defGroup.refresh_from_db() self.assertEqual(self.defGroup.name, "Custom default access") self.assertFalse(self.defGroup.system) def test_system_flag_update_on_remove(self): """Test that removing a role from a platform_default group flips the system flag.""" url = reverse("group-roles", kwargs={"uuid": self.defGroup.uuid}) client = APIClient() url = "{}?roles={}".format(url, self.roleB.uuid) self.policy.roles.add(self.roleB) self.policy.save() self.assertTrue(self.defGroup.system) response = client.delete(url, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) self.defGroup.refresh_from_db() self.assertEqual(self.defGroup.name, "Custom default access") self.assertFalse(self.defGroup.system) def test_add_group_roles_system_policy_create_new_group_success(self): """Test that adding a role to a group without a system policy returns successfully.""" group_url = reverse("group-roles", kwargs={"uuid": self.group.uuid}) groupB_url = reverse("group-roles", kwargs={"uuid": self.groupB.uuid}) client = APIClient() test_data = {"roles": [self.roleB.uuid]} response = client.post(group_url, test_data, format="json", **self.headers) responseB = client.post(groupB_url, test_data, format="json", **self.headers) system_policies = Policy.objects.filter(system=True) system_policy = system_policies.get(group=self.group) system_policyB = system_policies.get(group=self.groupB) self.assertEqual(len(system_policies), 2) self.assertCountEqual([self.roleB], list(system_policy.roles.all())) self.assertCountEqual([self.roleB], list(system_policyB.roles.all())) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(responseB.status_code, status.HTTP_200_OK) def test_add_group_roles_system_policy_get_success(self): """Test that adding a role to a group with existing system policy returns successfully.""" url = reverse("group-roles", kwargs={"uuid": self.group.uuid}) client = APIClient() test_data = {"roles": [self.roleB.uuid, self.dummy_role_id]} system_policy_name = "System Policy for Group {}".format(self.group.uuid) system_policy = Policy.objects.create(system=True, group=self.group, name=system_policy_name) self.assertCountEqual([self.role], list(self.group.roles())) self.assertCountEqual([system_policy, self.policy], list(self.group.policies.all())) response = client.post(url, test_data, format="json", **self.headers) roles = response.data.get("data") system_policies = Policy.objects.filter(system=True, group=self.group) system_policy = system_policies.first() self.assertEqual(len(system_policies), 1) self.assertCountEqual([system_policy, self.policy], list(self.group.policies.all())) self.assertCountEqual([self.roleB], list(system_policy.roles.all())) self.assertCountEqual([self.role], list(self.policy.roles.all())) self.assertCountEqual([self.role, self.roleB], list(self.group.roles())) self.assertEqual(len(roles), 2) self.assertEqual(roles[0].get("uuid"), str(self.role.uuid)) self.assertEqual(roles[0].get("name"), self.role.name) self.assertEqual(roles[0].get("description"), self.role.description) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_add_group_multiple_roles_success(self): """Test that adding multiple roles to a group returns successfully.""" with tenant_context(self.tenant): groupC = Group.objects.create(name="groupC") url = reverse("group-roles", kwargs={"uuid": groupC.uuid}) client = APIClient() test_data = {"roles": [self.role.uuid, self.roleB.uuid]} self.assertCountEqual([], list(groupC.roles())) response = client.post(url, test_data, format="json", **self.headers) self.assertCountEqual([self.role, self.roleB], list(groupC.roles())) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_add_group_multiple_roles_invalid(self): """Test that adding invalid roles to a group fails the request and does not add any.""" with tenant_context(self.tenant): groupC = Group.objects.create(name="groupC") url = reverse("group-roles", kwargs={"uuid": groupC.uuid}) client = APIClient() test_data = {"roles": ["abc123", self.roleB.uuid]} self.assertCountEqual([], list(groupC.roles())) response = client.post(url, test_data, format="json", **self.headers) self.assertCountEqual([], list(groupC.roles())) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_add_group_multiple_roles_not_found_success(self): """Test that adding roles to a group skips ids not found, and returns success.""" with tenant_context(self.tenant): groupC = Group.objects.create(name="groupC") url = reverse("group-roles", kwargs={"uuid": groupC.uuid}) client = APIClient() test_data = {"roles": [self.dummy_role_id, self.roleB.uuid]} self.assertCountEqual([], list(groupC.roles())) response = client.post(url, test_data, format="json", **self.headers) self.assertCountEqual([self.roleB], list(groupC.roles())) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_remove_group_roles_success(self): """Test that removing a role from a group returns successfully.""" url = reverse("group-roles", kwargs={"uuid": self.group.uuid}) client = APIClient() url = "{}?roles={}".format(url, self.role.uuid) self.policyB.roles.add(self.role) self.policyB.save() self.assertCountEqual([self.role], list(self.group.roles())) response = client.delete(url, format="json", **self.headers) self.assertCountEqual([], list(self.group.roles())) self.assertCountEqual([self.role, self.roleB], list(self.groupB.roles())) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_remove_group_multiple_roles_success(self): """Test that removing multiple roles from a group returns successfully.""" url = reverse("group-roles", kwargs={"uuid": self.group.uuid}) client = APIClient() url = "{}?roles={},{}".format(url, self.role.uuid, self.roleB.uuid) self.policy.roles.add(self.roleB) self.policy.save() self.assertCountEqual([self.role, self.roleB], list(self.group.roles())) response = client.delete(url, format="json", **self.headers) self.assertCountEqual([], list(self.group.roles())) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_remove_group_multiple_roles_invalid(self): """Test that removing invalid roles from a group fails the request and does not remove any.""" url = reverse("group-roles", kwargs={"uuid": self.group.uuid}) client = APIClient() url = "{}?roles={},{}".format(url, "abc123", self.roleB.uuid) self.policy.roles.add(self.roleB) self.policy.save() self.assertCountEqual([self.role, self.roleB], list(self.group.roles())) response = client.delete(url, format="json", **self.headers) self.assertCountEqual([self.role, self.roleB], list(self.group.roles())) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_remove_group_multiple_roles_not_found_success(self): """Test that removing roles from a group skips ids not found, and returns success.""" url = reverse("group-roles", kwargs={"uuid": self.group.uuid}) client = APIClient() url = "{}?roles={},{},{}".format(url, self.role.uuid, self.roleB.uuid, self.dummy_role_id) self.policy.roles.add(self.roleB) self.policy.save() self.assertCountEqual([self.role, self.roleB], list(self.group.roles())) response = client.delete(url, format="json", **self.headers) self.assertCountEqual([], list(self.group.roles())) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_remove_group_roles_invalid(self): """Test that removing a role returns an error with invalid data format.""" url = reverse("group-roles", kwargs={"uuid": self.group.uuid}) client = APIClient() response = client.delete(url, format="json", **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_admin_RonR(self): """Test that a admin user can group RBAC resources""" url = "{}?application={}".format(reverse("group-list"), "rbac") client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK)
class PolicyViewsetTests(IdentityRequest): """Test the policy viewset.""" def setUp(self): """Set up the policy viewset tests.""" super().setUp() request = self.request_context['request'] user = User(username=self.user_data['username'], email=self.user_data['email'], tenant=self.tenant) user.save() request.user = user with tenant_context(self.tenant): self.principal = Principal(username=self.user_data['username'], email=self.user_data['email']) self.principal.save() self.group = Group(name='groupA') self.group.save() self.group.principals.add(self.principal) self.group.save() def tearDown(self): """Tear down policy viewset tests.""" User.objects.all().delete() with tenant_context(self.tenant): Group.objects.all().delete() Principal.objects.all().delete() Role.objects.all().delete() Policy.objects.all().delete() def create_role(self, role_name, in_access_data=None): """Create a role.""" access_data = { 'permission': 'app:*:*', 'resourceDefinition': [{ 'attributeFilter': { 'key': 'key1', 'operation': 'equal', 'value': 'value1' } }] } if in_access_data: access_data = in_access_data test_data = {'name': role_name, 'access': [access_data]} # create a role url = reverse('role-list') client = APIClient() response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_201_CREATED) return response def create_policy(self, policy_name, group, roles, status=status.HTTP_201_CREATED): """Create a policy.""" # create a policy test_data = {'name': policy_name, 'group': group, 'roles': roles} url = reverse('policy-list') client = APIClient() response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status) return response def test_create_policy_success(self): """Test that we can create a policy.""" role_name = 'roleA' response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get('uuid') policy_name = 'policyA' response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) # test that we can retrieve the policy url = reverse('policy-detail', kwargs={'uuid': response.data.get('uuid')}) client = APIClient() response = client.get(url, **self.headers) self.assertIsNotNone(response.data.get('uuid')) self.assertIsNotNone(response.data.get('name')) self.assertEqual(policy_name, response.data.get('name')) self.assertEqual(str(self.group.uuid), response.data.get('group').get('uuid')) def test_create_policy_invalid_group(self): """Test that we cannot create a policy with invalid group.""" role_name = 'roleA' response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get('uuid') policy_name = 'policyA' response = self.create_policy(policy_name, uuid4(), [role_uuid], status.HTTP_400_BAD_REQUEST) def test_create_policy_invalid_role(self): """Test that we cannot create a policy with an invalid role.""" policy_name = 'policyA' response = self.create_policy(policy_name, self.group.uuid, [uuid4()], status.HTTP_400_BAD_REQUEST) def test_create_policy_no_role(self): """Test that we cannot create a policy without roles.""" policy_name = 'policyA' response = self.create_policy(policy_name, self.group.uuid, [], status.HTTP_400_BAD_REQUEST) def test_create_policy_invalid(self): """Test that creating an invalid policy returns an error.""" test_data = {} url = reverse('policy-list') client = APIClient() response = client.post(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_read_policy_invalid(self): """Test that reading an invalid policy returns an error.""" url = reverse('policy-detail', kwargs={'uuid': uuid4()}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_read_policy_list_success(self): """Test that we can read a list of policies.""" role_name = 'roleA' response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get('uuid') policy_name = 'policyA' response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) # list a policies url = reverse('policy-list') client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) for keyname in ['meta', 'links', 'data']: self.assertIn(keyname, response.data) self.assertIsInstance(response.data.get('data'), list) self.assertEqual(len(response.data.get('data')), 1) policy = response.data.get('data')[0] self.assertIsNotNone(policy.get('name')) self.assertEqual(policy.get('name'), policy_name) def test_update_policy_success(self): """Test that we can update an existing policy.""" role_name = 'roleA' response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get('uuid') policy_name = 'policyA' response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) updated_name = policy_name + '_update' policy_uuid = response.data.get('uuid') test_data = response.data test_data['name'] = updated_name test_data['group'] = self.group.uuid test_data['roles'] = [role_uuid] del test_data['uuid'] url = reverse('policy-detail', kwargs={'uuid': policy_uuid}) client = APIClient() response = client.put(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIsNotNone(response.data.get('uuid')) self.assertEqual(updated_name, response.data.get('name')) def test_update_policy_bad_group(self): """Test that we cannot update an existing policy with a bad group.""" role_name = 'roleA' response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get('uuid') policy_name = 'policyA' response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) updated_name = policy_name + '_update' policy_uuid = response.data.get('uuid') test_data = response.data test_data['name'] = updated_name test_data['group'] = uuid4() test_data['roles'] = [role_uuid] del test_data['uuid'] url = reverse('policy-detail', kwargs={'uuid': policy_uuid}) client = APIClient() response = client.put(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_update_policy_bad_role(self): """Test that we cannot update an existing policy with a bad role.""" role_name = 'roleA' response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get('uuid') policy_name = 'policyA' response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) updated_name = policy_name + '_update' policy_uuid = response.data.get('uuid') test_data = response.data test_data['name'] = updated_name test_data['group'] = self.group.uuid test_data['roles'] = [uuid4()] del test_data['uuid'] url = reverse('policy-detail', kwargs={'uuid': policy_uuid}) client = APIClient() response = client.put(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_update_policy_no_role(self): """Test that we can update an existing policy to have no roles.""" role_name = 'roleA' response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get('uuid') policy_name = 'policyA' response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) updated_name = policy_name + '_update' policy_uuid = response.data.get('uuid') test_data = response.data test_data['name'] = updated_name test_data['group'] = self.group.uuid test_data['roles'] = [] del test_data['uuid'] url = reverse('policy-detail', kwargs={'uuid': policy_uuid}) client = APIClient() response = client.put(url, test_data, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_update_policy_invalid(self): """Test that updating an invalid policy returns an error.""" url = reverse('policy-detail', kwargs={'uuid': uuid4()}) client = APIClient() response = client.put(url, {}, format='json', **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_delete_role_success(self): """Test that we can delete an existing role.""" role_name = 'roleA' response = self.create_role(role_name) role_uuid = response.data.get('uuid') policy_name = 'policyA' response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) policy_uuid = response.data.get('uuid') url = reverse('policy-detail', kwargs={'uuid': policy_uuid}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) # verify the policy no longer exists response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_delete_policy_invalid(self): """Test that deleting an invalid policy returns an error.""" url = reverse('policy-detail', kwargs={'uuid': uuid4()}) client = APIClient() response = client.delete(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_policy_removed_on_group_deletion(self): """Test that we can an existing policy is cleaned up when the group is deleted.""" role_name = 'roleA' response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get('uuid') policy_name = 'policyA' response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) policy_uuid = response.data.get('uuid') url = reverse('group-detail', kwargs={'uuid': self.group.uuid}) client = APIClient() response = client.delete(url, **self.headers) url = reverse('policy-detail', kwargs={'uuid': policy_uuid}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_policy_removed_on_all_role_deletion(self): """Test that we can an existing policy is cleaned up when the all roles are deleted.""" role_name = 'roleA' response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) role_uuid = response.data.get('uuid') policy_name = 'policyA' response = self.create_policy(policy_name, self.group.uuid, [role_uuid]) policy_uuid = response.data.get('uuid') url = reverse('role-detail', kwargs={'uuid': role_uuid}) client = APIClient() response = client.delete(url, **self.headers) url = reverse('policy-detail', kwargs={'uuid': policy_uuid}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_policy_removed_on_one_role_deletion(self): """Test that we can an existing policy remains when not all roles are deleted.""" roles = [] role_name = 'roleA' response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) roles.append(response.data.get('uuid')) role_name = 'roleB' response = self.create_role(role_name) self.assertEqual(response.status_code, status.HTTP_201_CREATED) roles.append(response.data.get('uuid')) policy_name = 'policyA' response = self.create_policy(policy_name, self.group.uuid, roles) policy_uuid = response.data.get('uuid') url = reverse('role-detail', kwargs={'uuid': roles[0]}) client = APIClient() response = client.delete(url, **self.headers) url = reverse('policy-detail', kwargs={'uuid': policy_uuid}) client = APIClient() response = client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK)
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)