def _modify_groups(cloud_node, request): action = request.args['action'] resp = { 'groups': request.json['groups'], 'action': action, f'{cloud_node.object_type}_id': cloud_node.name } try: Group.exists(request.json['groups']) if action == 'add': cloud_node.add_groups(request.json['groups']) elif action == 'remove': cloud_node.remove_groups(request.json['groups']) except cd_client.exceptions.BatchWriteException as ex: resp['msg'] = ex.response['Error']['Message'] code = 304 except FusilladeLimitException as ex: raise FusilladeHTTPException(detail=ex.reason, status=requests.codes.conflict, title="Conflict") else: resp[ 'msg'] = f"{cloud_node.object_type}'s groups successfully modified." code = 200 return resp, code
def test_get_group(self): headers = {'Content-Type': "application/json"} headers.update(get_auth_header(service_accounts['admin'])) name = "test_get_group_Groupx" resp = self.app.get(f'/v1/group/{name}/', headers=headers) self.assertEqual(404, resp.status_code) Group.create(name) resp = self.app.get(f'/v1/group/{name}/', headers=headers) self.assertEqual(name, json.loads(resp.body)['group_id']) self.assertTrue(json.loads(resp.body)['policies'])
def test_get_groups(self): name = "*****@*****.**" test_groups = [(f"group_{i}", create_test_IAMPolicy(f"GroupPolicy{i}")) for i in range(5)] groups = [Group.create(*i) for i in test_groups] user = User.provision_user(name) with self.subTest( "A user is in the public group when user is first created."): self.assertEqual( Group(object_ref=user.groups[0]).name, 'user_default') user.add_groups([]) with self.subTest( "A user is added to no groups when add_groups is called with no groups" ): self.assertEqual(len(user.groups), 1) with self.subTest( "An error is returned when add a user to a group that does not exist." ): with self.assertRaises( cd_client.exceptions.BatchWriteException) as ex: user.add_groups(["ghost_group"]) self.assertTrue('ResourceNotFoundException' in ex.exception.response['Error']['Message']) self.assertEqual(len(user.groups), 1) with self.subTest( "An error is returned when add a user to a group that they are already apart." ): with self.assertRaises( cd_client.exceptions.BatchWriteException) as ex: user.add_groups(["user_default"]) self.assertTrue('InvalidAttachmentException' in ex.exception.response['Error']['Message']) self.assertEqual(len(user.groups), 1) user.add_groups([group.name for group in groups]) with self.subTest( "A user is added to multiple groups when add_groups is called with multiple groups" ): self.assertEqual(len(user.groups), 6) with self.subTest( "A user inherits the groups policies when joining a group"): policies = set([ normalize_json(p['policy_document']) for p in user.get_authz_params()['IAMPolicy'] ]) expected_policies = set( [normalize_json(i[1]) for i in test_groups]) expected_policies.update(self.default_user_policies) self.assertSetEqual(policies, expected_policies)
def test_ownership(self): user = User.provision_user('test_user') group = Group.create("group_ownership") with self.subTest("A user is not an owner when new group is created"): self.assertFalse(user.is_owner(group)) user.add_ownership(group) with self.subTest("A user is owner after assigning ownership."): self.assertTrue(user.is_owner(group)) group2 = Group.create("group_ownership2") user.add_ownership(group2) with self.subTest("List groups owned, when list_owned is called"): resp = user.list_owned(Group) user.remove_ownership(group) self.assertFalse(user.is_owner(group))
def backup_groups(): groups = [] for name in list_node(Group, 'groups'): group = Group(name) info = { 'name': group.name, 'members': [User(object_ref=u).name for u in group.get_users_iter()], 'policies': format_policies([(p, group.get_policy(p)) for p in group.allowed_policy_types]), 'owners': group.list_owners(), 'roles': [Role(object_ref=r).name for r in group.roles] } groups.append(info) print("GROUPS:", *groups, sep='\n\t') return groups
def get_resource_authz_parameters(user: str, resources: Union[List[str], str]): """ Get all policy ids, and send them to lookup policy, group them by policy type. :param user: :param resource: :return: """ policies = [] _user = User(user) try: groups = _user.groups except cd_client.exceptions.ResourceNotFoundException: _user = User.provision_user(user) groups = _user.groups # Only support a single resource for now resource = resources[0] if isinstance(resources, list) else resources r_type, r_id, *_ = resource.split(':')[-1].split('/') if r_type in ResourceType.get_types(): r_id = ResourceId(r_type, r_id) resource_policies = r_id.check_access( [_user] + [Group(object_ref=g) for g in groups]) if not resource_policies: raise ResourceNotFound("ResourceNotFound") policies.extend(resource_policies) policies.extend(list(_user.get_policy_ids())) authz_params = Config.get_directory().get_policies(policies) if authz_params.get('ResourcePolicy'): authz_params['ResourcePolicy'] = combine( [i['policy_document'] for i in authz_params.get('ResourcePolicy')]) return authz_params
def test_policy(self): group = Group.create("new_group") with self.subTest( "Only one policy is attached when lookup policy is called on a group without any roles" ): policies = [ p['policy_document'] for p in group.get_authz_params()['IAMPolicy'] ] self.assertEqual(len(policies), 1) self.assertJSONEqual(policies[0], self.default_group_statement) group_name = "NewGroup1234" statement = create_test_IAMPolicy(group_name) with self.subTest("The group policy changes when satement is set"): group.set_policy(statement) policies = [ p['policy_document'] for p in group.get_authz_params()['IAMPolicy'] ] self.assertJSONEqual(policies[0], statement) with self.subTest( "error raised when invalid statement assigned to group.get_policy()." ): with self.assertRaises(FusilladeHTTPException): group.set_policy({"Statement": "Something else"})
def test_remove_groups(self): name = "*****@*****.**" test_groups = [(f"group_{i}", create_test_IAMPolicy(f"GroupPolicy{i}")) for i in range(5)] groups = [Group.create(*i).name for i in test_groups] user = User.provision_user(name) with self.subTest( "A user is removed from a group when remove_group is called for a group the user belongs " "to."): user.add_groups(groups) self.assertEqual(len(user.groups), 6) user.remove_groups(groups) self.assertEqual(len(user.groups), 1) with self.subTest( "Error is raised when removing a user from a group it's not in." ): self.assertRaises(cd_client.exceptions.BatchWriteException, user.remove_groups, groups) self.assertEqual(len(user.groups), 1) with self.subTest( "An error is raised and the user is not removed from any groups when the user is in some of " "the groups to remove."): user.add_groups(groups[:2]) self.assertEqual(len(user.groups), 3) self.assertRaises(cd_client.exceptions.BatchWriteException, user.remove_groups, groups) self.assertEqual(len(user.groups), 3)
def test_put_username_groups(self): tests = [ { 'name': "*****@*****.**", 'action': 'add', 'json_request_body': { "groups": [Group.create("test_put_username_groups_0").name] }, 'responses': [ {'code': 200}, {'code': 304} ] }, { 'name': "*****@*****.**", 'action': 'remove', 'json_request_body': { "groups": [Group.create("test_put_username_groups_1").name] }, 'responses': [ {'code': 200}, {'code': 304} ] } ] for test in tests: with self.subTest(test['json_request_body']): data = json.dumps(test['json_request_body']) headers = {'Content-Type': "application/json"} headers.update(get_auth_header(service_accounts['admin'])) url = furl(f'/v1/user/{test["name"]}/groups/') query_params = { 'user_id': test['name'], 'action': test['action'] } url.add(query_params=query_params) user = User.provision_user(test['name']) if test['action'] == 'remove': user.add_groups(test['json_request_body']['groups']) resp = self.app.put(url.url, headers=headers, data=data) self.assertEqual(test['responses'][0]['code'], resp.status_code) resp = self.app.put(url.url, headers=headers, data=data) self.assertEqual(test['responses'][1]['code'], resp.status_code)
def test_get_username_groups(self): headers = {'Content-Type': "application/json"} headers.update(get_auth_header(service_accounts['admin'])) name = "*****@*****.**" key = 'groups' user = User.provision_user(name) resp = self.app.get(f'/v1/user/{name}/groups', headers=headers) self.assertEqual(1, len(json.loads(resp.body)[key])) groups = [Group.create(f"test_get_username_groups_{i}").name for i in range(8)] user.add_groups(groups) self._test_paging(f'/v1/user/{name}/groups', headers, 5, key)
def test_get_group_users(self): headers = {'Content-Type': "application/json"} headers.update(get_auth_header(service_accounts['admin'])) name = "test_get_group_users_group" key = 'users' group = Group.create(name) resp = self.app.get(f'/v1/group/{name}/users', headers=headers) group_user_names = [User(user).name for user in group.get_users_iter()] self.assertEqual(0, len(json.loads(resp.body)[key])) users = [User.provision_user(f"test_get_group_user_{i}", groups=[name]).name for i in range(10)] self._test_paging(f'/v1/group/{name}/users', headers, 5, key)
def test_get_group_roles(self): headers = {'Content-Type': "application/json"} headers.update(get_auth_header(service_accounts['admin'])) name = "test_get_group_roles_group" key = 'roles' group = Group.create(name) resp = self.app.get(f'/v1/group/{name}/roles', headers=headers) group_role_names = [Role(None, role).name for role in group.roles] self.assertEqual(0, len(json.loads(resp.body)[key])) roles = [Role.create(f"test_get_group_roles_role_{i}").name for i in range(10)] group.add_roles(roles) self._test_paging(f'/v1/group/{name}/roles', headers, 5, key)
def test_users(self): emails = ["*****@*****.**", "*****@*****.**", "*****@*****.**"] users = [User.provision_user(email).name for email in emails] with self.subTest( "A user is added to the group when add_users is called"): group = Group.create("test") user = User.provision_user("*****@*****.**") group.add_users([user.name]) actual_users = [i for i in group.get_users_iter()] self.assertEqual(len(actual_users), 1) self.assertEqual(User(object_ref=actual_users[0]).name, user.name) with self.subTest( "Multiple users are added to the group when multiple users are passed to add_users" ): group = Group.create("test2") group.add_users(users) actual_users = [i[1] for i in group.get_users_iter()] self.assertEqual(len(actual_users), 3) with self.subTest( "Error returned when a user is added to a group it's already apart of." ): group = Group.create("test3") group.add_users(users) try: group.add_users(users) except cd_client.exceptions.BatchWriteException: pass actual_users = [i[1] for i in group.get_users_iter()] self.assertEqual(len(actual_users), 3) with self.subTest( "Error returned when adding a user that does not exist"): group = Group.create("test4") user = User("*****@*****.**") try: group.add_users([user.name]) except cd_client.exceptions.ResourceNotFoundException: pass
def test_group_and_role(self): """ A user inherits policies from groups and roles when the user is apart of a group and assigned a role. """ name = "*****@*****.**" user = User.provision_user(name) test_groups = [(f"group_{i}", create_test_IAMPolicy(f"GroupPolicy{i}")) for i in range(5)] [Group.create(*i) for i in test_groups] group_names, _ = zip(*test_groups) group_names = sorted(group_names) group_statements = [i[1] for i in test_groups] test_roles = [(f"role_{i}", create_test_IAMPolicy(f"RolePolicy{i}")) for i in range(5)] [Role.create(*i) for i in test_roles] role_names, _ = zip(*test_roles) role_names = sorted(role_names) role_statements = [i[1] for i in test_roles] user.add_roles(role_names) user.add_groups(group_names) user.set_policy(self.default_policy) user_role_names = [Role(object_ref=role).name for role in user.roles] user_group_names = [ Group(object_ref=group).name for group in user.groups ] self.assertListEqual(sorted(user_role_names), role_names) self.assertEqual(sorted(user_group_names), group_names + ['user_default']) authz_params = user.get_authz_params() self.assertListEqual(sorted(authz_params['roles']), sorted(['default_user'] + role_names)) self.assertListEqual(sorted(authz_params['groups']), sorted(['user_default'] + group_names)) self.assertJSONListEqual( [p['policy_document'] for p in authz_params['IAMPolicy']], [user.get_policy(), *self.default_user_policies] + group_statements + role_statements)
def test_create_group(self): with self.subTest( "an error is returned when creating a group with an invalid statement." ): with self.assertRaises(FusilladeHTTPException): group = Group.create("new_group1", {"random": "fields"}) with self.subTest( "The group is returned when the group has been created with default valid statement" ): group = Group.create("new_group2") self.assertEqual(group.name, "new_group2") self.assertJSONEqual(group.get_policy(), self.default_group_statement) with self.subTest( "The group is returned when the group has been created with specified valid statement." ): group_name = "NewGroup1234" statement = create_test_IAMPolicy(group_name) group = Group.create("new_group3", statement) self.assertEqual(group.name, "new_group3") self.assertJSONEqual(group.get_policy(), statement)
def userinfo(token_info): """ Part of OIDC """ from fusillade.directory import User, Group, Role user = User(token_info['email']) # TODO save user info in fusillade at the same time. token_info[f"https://{os.environ['API_DOMAIN_NAME']}/app_metadata"] = { 'authorization': { 'groups': Group.get_names(user.groups), 'roles': Role.get_names(user.roles), 'scope': [i for i in user.get_actions()] } } return make_response(json.jsonify(**token_info), requests.codes.ok)
def test_put_group_roles(self): tests = [ { 'group_id': "test_put_group_roles_Group1", 'action': 'add', 'json_request_body': { "roles": [Role.create("role_0").name] }, 'responses': [ {'code': 200}, {'code': 304} ] }, { 'group_id': "test_put_group_roles_Group2", 'action': 'remove', 'json_request_body': { "roles": [Role.create("role_1").name] }, 'responses': [ {'code': 200}, {'code': 304} ] } ] for test in tests: with self.subTest(test['json_request_body']): data = json.dumps(test['json_request_body']) headers = {'Content-Type': "application/json"} headers.update(get_auth_header(service_accounts['admin'])) url = furl(f'/v1/group/{test["group_id"]}/roles/') query_params = { 'group_id': test['group_id'], 'action': test['action'] } url.add(query_params=query_params) group = Group.create(test['group_id']) if test['action'] == 'remove': group.add_roles(test['json_request_body']['roles']) resp = self.app.put(url.url, headers=headers, data=data) self.assertEqual(test['responses'][0]['code'], resp.status_code) resp = self.app.put(url.url, headers=headers, data=data) self.assertEqual(test['responses'][1]['code'], resp.status_code)
def test_user_group_limit(self): groups = [Group.create(f"test_user_group_limit{i}").name for i in range(10)] name = "*****@*****.**" user = User.provision_user(name) tests = [ { 'action': 'add', 'json_request_body': { "groups": groups[:8] }, 'response': { 'code': 200 } }, { 'action': 'add', 'json_request_body': { "groups": [groups[9]] }, 'response': { 'code': 409 } } ] for test in tests: with self.subTest(test['json_request_body']): data = json.dumps(test['json_request_body']) headers = {'Content-Type': "application/json"} headers.update(get_auth_header(service_accounts['admin'])) url = furl(f'/v1/user/{name}/groups/') query_params = { 'user_id': name, 'action': test['action'] } url.add(query_params=query_params) if test['action'] == 'remove': user.add_groups(test['json_request_body']['groups']) resp = self.app.put(url.url, headers=headers, data=data) self.assertEqual(test['response']['code'], resp.status_code)
def test_roles(self): roles = ['role1', 'role2'] role_objs = [ Role.create(name, create_test_IAMPolicy(name)) for name in roles ] with self.subTest( "multiple roles return when multiple roles are attached to group." ): group = Group.create("test_roles") group.add_roles(roles) self.assertEqual(len(group.roles), 2) with self.subTest( "policies inherited from roles are returned when lookup policies is called" ): group_policies = sorted([ normalize_json(p['policy_document']) for p in group.get_authz_params()['IAMPolicy'] ]) role_policies = sorted( [normalize_json(role.get_policy()) for role in role_objs] + [self.default_group_statement]) self.assertListEqual(group_policies, role_policies)
def test_put_users(self): users = [User.provision_user(f"test_put_user_{i}").name for i in range(11)] tests = [ { 'action': 'add', 'json_request_body': { "users": [users[0]] }, 'responses': [ {'code': 200}, {'code': 304} ] }, { 'action': 'remove', 'json_request_body': { "users": [users[0]] }, 'responses': [ {'code': 200}, {'code': 304} ] }, { 'action': 'add', 'json_request_body': { "users": users[:-1] }, 'responses': [ {'code': 200}, {'code': 304} ] }, { 'action': 'remove', 'json_request_body': { "users": users[:-1] }, 'responses': [ {'code': 200}, {'code': 304} ] }, { 'action': 'add', 'json_request_body': { "users": users }, 'responses': [ {'code': 400}, {'code': 400} ] }, { 'action': 'remove', 'json_request_body': { "users": users }, 'responses': [ {'code': 400}, {'code': 400} ] } ] for i, test in enumerate(tests): group_id = Group.create(f"Group{i}").name with self.subTest(test['json_request_body']): data = json.dumps(test['json_request_body']) headers = {'Content-Type': "application/json"} headers.update(get_auth_header(service_accounts['admin'])) if test['action'] == 'remove': url = furl(f'/v1/group/{group_id}/users', query_params={'action': 'add'}) resp = self.app.put(url.url, headers=headers, data=data) url = furl(f'/v1/group/{group_id}/users', query_params={'action': test['action']}) resp = self.app.put(url.url, headers=headers, data=data) self.assertEqual(test['responses'][0]['code'], resp.status_code) resp = self.app.put(url.url, headers=headers, data=data) self.assertEqual(test['responses'][1]['code'], resp.status_code)
def test_post_new_user(self): tests = [ { 'name': f'201 returned when creating a user', 'json_request_body': { "user_id": "*****@*****.**" }, 'response': { 'code': 201 } }, { 'name': f'201 returned when creating a user with group only', 'json_request_body': { "user_id": "*****@*****.**", "groups": [Group.create("test_post_new_user_group_01").name] }, 'response': { 'code': 201 } }, { 'name': f'201 returned when creating a user with role only', 'json_request_body': { "user_id": "*****@*****.**", "roles": [Role.create("test_post_new_user_role_02").name] }, 'response': { 'code': 201 } }, { 'name': f'201 returned when creating a user with policy only', 'json_request_body': { "user_id": "*****@*****.**", "policy": create_test_IAMPolicy("policy_03") }, 'response': { 'code': 201 } }, { 'name': f'201 returned when creating a user with group, role and policy', 'json_request_body': { "user_id": "*****@*****.**", "groups": [Group.create("test_post_new_user_group_04").name], "roles": [Role.create("test_post_new_user_role_04").name], "policy": create_test_IAMPolicy("policy_04") }, 'response': { 'code': 201 } }, { 'name': f'400 returned when creating a user without username', 'json_request_body': { "groups": [Group.create("test_post_new_user_group_05").name], "roles": [Role.create("test_post_new_user_role_05").name], "policy": create_test_IAMPolicy("policy_05") }, 'response': { 'code': 400 } }, { 'name': f'409 returned when creating a user that already exists', 'json_request_body': { "user_id": "*****@*****.**" }, 'response': { 'code': 409 } } ] tests.extend([{ 'name': f'201 returned when creating a role when name is {description}', 'json_request_body': { "user_id": name }, 'response': { 'code': 201 } } for name, description in TEST_NAMES_POS ]) tests.extend([{ 'name': f'400 returned when creating a role when name is {description}', 'json_request_body': { "user_id": name }, 'response': { 'code': 400 } } for name, description in TEST_NAMES_NEG ]) for test in tests: with self.subTest(test['name']): headers = {'Content-Type': "application/json"} headers.update(get_auth_header(service_accounts['admin'])) if test['name'] == "409 returned when creating a user that already exists": self.app.post('/v1/user', headers=headers, data=json.dumps(test['json_request_body'])) resp = self.app.post('/v1/user', headers=headers, data=json.dumps(test['json_request_body'])) self.assertEqual(test['response']['code'], resp.status_code) if resp.status_code == 201: resp = self.app.get(f'/v1/user/{test["json_request_body"]["user_id"]}/', headers=headers) self.assertEqual(test["json_request_body"]["user_id"], json.loads(resp.body)['user_id'])