def test_get_role_id(self): role_id = 'test_get_role_id' admin_auth_header = get_auth_header(service_accounts['admin']) tests = [{ 'name': '401 return when no auth headers.', 'headers': {}, 'role_id': role_id, 'expected_resp': 401 }, { 'name': '403 return when unauthorized user.', 'headers': get_auth_header(service_accounts['user']), 'role_id': role_id, 'expected_resp': 403 }, { 'name': '200 returned when user is authorized.', 'headers': admin_auth_header, 'role_id': role_id, 'expected_resp': 200 }, { 'name': 'error returned when role does not exist.', 'headers': admin_auth_header, 'role_id': 'ghost_role', 'expected_resp': 404 }] tests.extend([{ 'name': f'200 returned when getting a role when name is {description}', 'role_id': role_id, 'headers': admin_auth_header, 'expected_resp': 200 } for name, description in TEST_NAMES_POS]) tests.extend([{ 'name': f'400 returned when getting a role when name is {description}', 'role_id': role_id, 'headers': admin_auth_header, 'expected_resp': 400 } for role_id, description in TEST_NAMES_NEG if role_id is not '']) policy = create_test_IAMPolicy("test_role") role = Role.create(role_id, policy) expected_policy = policy [Role.create(role_id, policy) for role_id, _ in TEST_NAMES_POS] for test in tests: with self.subTest(test['name']): url = furl('/v1/role/{}'.format(test['role_id'])) headers = {'Content-Type': "application/json"} headers.update(test['headers']) resp = self.app.get(url.url, headers=headers) self.assertEqual(test['expected_resp'], resp.status_code) if test['expected_resp'] == 200: expected_body = { 'role_id': test['role_id'], 'policies': { 'IAMPolicy': expected_policy } } self.assertEqual(expected_body, json.loads(resp.body))
def test_put_role_id_policy(self): role_id = 'test_put_role_id_policy' policy_1 = create_test_IAMPolicy(role_id) policy_2 = create_test_IAMPolicy('ABCD') policy_invalid = "invalid policy" Role.create(role_id, policy_1) admin_auth_header = get_auth_header(service_accounts['admin']) tests = [{ 'name': '401 return when no auth headers.', 'headers': {}, 'role_id': role_id, 'data': { 'policy': policy_2 }, 'expected_resp': 401 }, { 'name': '403 return when unauthorized user.', 'headers': get_auth_header(service_accounts['user']), 'role_id': role_id, 'data': { 'policy': policy_2 }, 'expected_resp': 403 }, { 'name': '200 returned when user is authorized.', 'headers': admin_auth_header, 'role_id': role_id, 'data': { 'policy': policy_2 }, 'expected_resp': 200 }, { 'name': '400 returned when an invalid policy is used.', 'headers': admin_auth_header, 'role_id': role_id, 'data': { 'policy': policy_invalid }, 'expected_resp': 400 }, { 'name': '404 returned when role does not exist.', 'headers': admin_auth_header, 'role_id': 'ghost_role', 'data': { 'policy': policy_2 }, 'expected_resp': 404 }] for test in tests: with self.subTest(test['name']): headers = {'Content-Type': "application/json"} headers.update(test['headers']) url = furl(f"/v1/role/{test['role_id']}/policy") data = json.dumps(test['data']) resp = self.app.put(url.url, data=data, headers=headers) self.assertEqual(test['expected_resp'], resp.status_code)
def backup_roles(): roles = [] for name in list_node(Role, 'roles'): role = Role(name) info = { 'name': role.name, 'policies': format_policies([(p, role.get_policy(p)) for p in role.allowed_policy_types]), 'owners': role.list_owners() } roles.append(info) print("ROLES:", *roles, sep='\n\t') return roles
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_get_username_roles(self): headers = {'Content-Type': "application/json"} headers.update(get_auth_header(service_accounts['admin'])) name = "*****@*****.**" key = 'roles' user = User.provision_user(name) resp = self.app.get(f'/v1/user/{name}/roles', headers=headers) user_role_names = [Role(None, role).name for role in user.roles] self.assertEqual(0, len(json.loads(resp.body)[key])) roles = [Role.create(f"test_get_username_role_{i}").name for i in range(11)] user.add_roles(roles) self._test_paging(f'/v1/user/{name}/roles', headers, 6, key)
def test_user_owned(self): headers = {'Content-Type': "application/json"} headers.update(get_auth_header(service_accounts['admin'])) name = "*****@*****.**" key = 'roles' user = User.provision_user(name) url = furl(f"/v1/user/{name}/owns", query_params={'resource_type': 'role'}).url resp = self.app.request(url, headers=headers) self.assertEqual('False', resp.headers['X-OpenAPI-Pagination']) user_role_names = [Role(object_ref=role).name for role in user.roles] roles = [Role.create(f"test_user_owned_role_{i}") for i in range(11)] user.add_roles([role.name for role in roles]) [user.add_ownership(role) for role in roles] self._test_paging(url, headers, 6, key)
def test_delete_group(self): headers = {'Content-Type': "application/json"} headers.update(get_auth_header(service_accounts['admin'])) role = Role.create("test_delete_group_role").name user = User.provision_user("test_delete_group_user").name policy = create_test_IAMPolicy("test_delete_group_policy") group_id = "test_delete_group_group" with self.subTest("Group delete with users and roles."): resp = self.app.post(f'/v1/group', headers=headers, data=json.dumps({ "group_id": group_id, "roles": [role], "policy": policy })) resp.raise_for_status() resp = self.app.put(f'/v1/user/{user}/groups?action=add', headers=headers, data=json.dumps({"groups": [group_id]})) resp.raise_for_status() resp = self.app.delete(f'/v1/group/{group_id}', headers=headers) self.assertEqual(resp.status_code, 200) resp = self.app.get(f'/v1/user/{user}/groups', headers=headers) groups = json.loads(resp.body)['groups'] self.assertNotIn(group_id, groups) with self.subTest("delete a group that does not exist."): resp = self.app.delete(f'/v1/group/{group_id}', headers=headers) self.assertEqual(resp.status_code, 404)
def test_role_default(self): with self.subTest( "a role is set to default policy when role.create is called without a statement." ): role_name = "test_role_default" role = Role.create(role_name) self.assertEqual(role.name, role_name) self.assertJSONEqual(role.get_policy(), self.default_role_statement)
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_put_username_roles(self): tests = [ { 'name': "*****@*****.**", 'action': 'add', 'json_request_body': { "roles": [Role.create("test_put_username_roles_role_0").name] }, 'responses': [ {'code': 200}, {'code': 304} ] }, { 'name': "*****@*****.**", 'action': 'remove', 'json_request_body': { "roles": [Role.create("test_put_username_roles_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/user/{test["name"]}/roles/') 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_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_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_role_statement(self): role_name = "test_role_specified" statement = create_test_IAMPolicy(role_name) role = Role.create(role_name, statement) with self.subTest( "a role is created with specified statement when role.create is called with a statement" ): self.assertEqual(role.name, role_name) with self.subTest( "a roles statement is retrieved when role.get_policy() is called" ): self.assertJSONEqual(role.get_policy(), statement) with self.subTest( "a roles statement is changed when role.get_policy() is assigned" ): statement = create_test_IAMPolicy(f"UserPolicySomethingElse") role.set_policy(statement) self.assertJSONEqual(role.get_policy(), statement) with self.subTest( "Error raised when setting policy to an invalid statement"): with self.assertRaises(FusilladeHTTPException): role.set_policy({"Statement": "Something else"}) self.assertJSONEqual(role.get_policy(), statement) statement = create_test_statements(150) with self.subTest( "an error is returned when a policy that exceeds 10 Kb for a pre-existing role" ): with self.assertRaises(FusilladeHTTPException) as ex: role.set_policy(statement) with self.subTest( "an error is returned when a policy that exceeds 10 Kb for a new role" ): with self.assertRaises(FusilladeHTTPException) as ex: Role.create("test_role_specified_2", statement)
def _modify_roles(cloud_node, request): action = request.args['action'] resp = { 'roles': request.json['roles'], 'action': action, f'{cloud_node.object_type}_id': cloud_node.name } try: Role.exists(request.json['roles']) if action == 'add': cloud_node.add_roles(request.json['roles']) elif action == 'remove': cloud_node.remove_roles(request.json['roles']) except cd_client.exceptions.BatchWriteException as ex: # TODO inspect the error. Return 304 if link exists error. Return 404 if object does not exist error. resp['msg'] = ex.response['Error']['Message'] code = 304 else: resp[ 'msg'] = f"{cloud_node.object_type}'s roles successfully modified." code = 200 return resp, code
def backup_users(): users = [] for name in list_node(User, 'users'): user = User(name) info = { 'name': user.name, 'status': user.status, 'policies': format_policies([(p, user.get_policy(p)) for p in user.allowed_policy_types]), 'roles': [Role(object_ref=r).name for r in user.roles] } users.append(info) print("USERS:", *users, sep='\n\t') return users
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 test_eval(self): actions = ['test:readproject', 'test:writeproject', 'test:deleteproject'] resource_type = 'test_type' test_type = ResourceType.create(resource_type, actions) access_level = 'Reader' resource_policy = { "Version": "2012-10-17", "Statement": [ { "Principal": "*", "Sid": "project_reader", "Effect": "Allow", "Action": ['test:readproject'], "Resource": f"{self.arn_prefix}{resource_type}/*" } ] } test_type.create_policy(access_level, resource_policy, 'ResourcePolicy') user = User.provision_user('test_user') type_id = '1234455' resource = f'{self.arn_prefix}{resource_type}/{type_id}' with self.subTest("A user does not have access when they only have permitting resource_policy and no " "permitting IAMPolicy"): test_id = test_type.create_id(type_id) test_id.add_principals([user], access_level) x = get_resource_authz_parameters(user.name, resource) resp = evaluate_policy(user.name, ['test:readproject'], [resource], x['IAMPolicy'], x['ResourcePolicy']) self.assertFalse(resp['result']) with self.subTest("A user has a access when they have a permitting resource policy and IAMPolicy"): IAMpolicy = { "Statement": [ { "Sid": "project_reader", "Effect": "Allow", "Action": [ "test:readproject" ], "Resource": f"{self.arn_prefix}{resource_type}/*" } ] } role = Role.create('project_reader', IAMpolicy) user.add_roles([role.name]) x = get_resource_authz_parameters(user.name, resource) resp = evaluate_policy(user.name, ['test:readproject'], [resource], x['IAMPolicy'], x['ResourcePolicy']) self.assertTrue(resp['result'])
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_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 post_role(token_info: dict): json_body = request.json Role.create(json_body['role_id'], statement=json_body.get('policy'), creator=get_email_claim(token_info)) return make_response(f"New role {json_body['role_id']} created.", 201)
def delete_role(token_info: dict, role_id): Role(role_id).delete_node() return make_response(f"{role_id} deleted.", 200)
def put_role_policy(token_info: dict, role_id: str): role = Role(role_id) role.set_policy(request.json['policy']) return make_response('Role policy updated.', 200)
def get_role(token_info: dict, role_id: str): role = Role(role_id) return make_response(jsonify(role.get_info()), 200)
def test_roles(self): name = "*****@*****.**" test_roles = [(f"Role_{i}", create_test_IAMPolicy(f"RolePolicy{i}")) for i in range(5)] roles = [Role.create(*i).name 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 = User.provision_user(name) user_role_names = [Role(None, role).name for role in user.roles] with self.subTest("a user has the default_user roles when created."): self.assertEqual(user_role_names, []) role_name, role_statement = test_roles[0] with self.subTest("A user has one role when a role is added."): user.add_roles([role_name]) user_role_names = [Role(None, role).name for role in user.roles] self.assertEqual(user_role_names, [role_name]) with self.subTest( "An error is raised when adding a role a user already has."): with self.assertRaises( cd_client.exceptions.BatchWriteException) as ex: user.add_roles([role_name]) self.assertTrue('LinkNameAlreadyInUseException' in ex.response['Error']['Message']) with self.subTest( "An error is raised when adding a role that does not exist."): with self.assertRaises( cd_client.exceptions.BatchWriteException) as ex: user.add_roles(["ghost_role"]) self.assertTrue(ex.response['Error']['Message'].endswith( "/ role / ghost_role\\' does not exist.'")) user.set_policy(self.default_policy) with self.subTest( "A user inherits a roles policies when a role is added to a user." ): policies = [ p['policy_document'] for p in user.get_authz_params()['IAMPolicy'] ] self.assertJSONListEqual(policies, [ user.get_policy(), role_statement, *self.default_user_policies ]) with self.subTest( "A role is removed from user when remove role is called."): user.remove_roles([role_name]) self.assertEqual(user.roles, []) with self.subTest( "A user has multiple roles when multiple roles are added to user." ): user.add_roles(role_names) user_role_names = [Role(None, role).name for role in user.roles] self.assertEqual(sorted(user_role_names), role_names) with self.subTest( "A user inherits multiple role policies when the user has multiple roles." ): policies = [ p['policy_document'] for p in user.get_authz_params()['IAMPolicy'] ] self.assertJSONListEqual(policies, [ user.get_policy(), *self.default_user_policies, *role_statements ]) with self.subTest( "A user's roles are listed when a listing a users roles."): user_role_names = [Role(None, role).name for role in user.roles] self.assertListEqual(sorted(user_role_names), role_names) with self.subTest( "Multiple roles are removed from a user when a multiple roles are specified for removal." ): user.remove_roles(role_names) self.assertEqual(user.roles, [])
def test_post_group(self): tests = [ { 'name': f'201 returned when creating a group', 'json_request_body': { "group_id": "test_post_group_Group0" }, 'response': { 'code': 201 } }, { 'name': f'201 returned when creating a group with role only', 'json_request_body': { "group_id": "test_post_group_Group1", "roles": [Role.create("test_post_group_role_02").name] }, 'response': { 'code': 201 } }, { 'name': f'201 returned when creating a group with policy only', 'json_request_body': { "group_id": "test_post_group_Group2", "policy": create_test_IAMPolicy("policy_03") }, 'response': { 'code': 201 } }, { 'name': f'201 returned when creating a group with role and policy', 'json_request_body': { "group_id": "test_post_group_Group3", "roles": [Role.create("test_post_group_role_04").name], "policy": create_test_IAMPolicy("policy_04") }, 'response': { 'code': 201 } }, { 'name': f'400 returned when creating a group without group_id', 'json_request_body': { "roles": [Role.create("test_post_group_role_05").name], "policy": create_test_IAMPolicy("policy_05") }, 'response': { 'code': 400 } }, { 'name': f'409 returned when creating a group that already exists', 'json_request_body': { "group_id": "test_post_group_Group3" }, 'response': { 'code': 409 } } ] tests.extend([{ 'name': f'201 returned when creating a role when name is {description}', 'json_request_body': { "group_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': { "group_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'] == "400 returned when creating a group that already exists": self.app.post('/v1/group', headers=headers, data=json.dumps(test['json_request_body'])) resp = self.app.post('/v1/group', 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/group/{test["json_request_body"]["group_id"]}/', headers=headers) self.assertEqual(test["json_request_body"]["group_id"], json.loads(resp.body)['group_id'])