def get_users(user_info): try: # This method is just a proxy to the IDM for reading available users keyrock_client = KeyrockClient(IDM_URL, IDM_USER, IDM_PASSWD) return build_response(keyrock_client.get_users(), 200) except KeyrockError as e: return build_response({'error': str(e)}, 503)
def check_client_accpets_application_json(): accept_header = request.headers.get('accept', '*/*') best_response_mimetype = mimeparse.best_match(('application/json', ), accept_header) if best_response_mimetype == '': msg = "The requested resource is only capable of generating content not acceptable according to the Accept headers sent in the request" details = {'supported_mime_types': ['application/json']} return build_response({'error': msg, 'details': details}, 406)
def get_tenant(user_info, tenant_id): tenant_info = None try: database_controller = DatabaseController(host=MONGO_HOST, port=MONGO_PORT) tenant_info = database_controller.get_tenant(tenant_id) if tenant_info is None: return build_response( {'error': 'Tenant {} does not exist'.format(tenant_id)}, 404) if tenant_info['owner_id'] != user_info['id'] and not is_member( user_info['id'], tenant_info): return build_response( {'error': 'You are not authorized to retrieve tenant info'}, 403) # Get tenant members from the IDM to keep the list # of members syncronized keyrock_client = KeyrockClient(IDM_URL, IDM_USER, IDM_PASSWD) members = keyrock_client.get_organization_members( tenant_info['tenant_organization']) tenant_info['users'] = [ { 'id': member['user_id'], 'name': member['name'], 'roles': _map_roles(member) } for member in members if member['user_id'] != IDM_USER_ID ] # The admin user used to create the org is not a tenant member database_controller.update_tenant(tenant_id, tenant_info) except KeyrockError: return build_response( {'error': 'An error occurred reading tenant info from Keyrock'}, 503) if tenant_info['owner_id'] != user_info['id']: tenant_info['users'] = [ user for user in tenant_info['users'] if user['id'] == user_info['id'] ] return build_response(tenant_info, 200)
def get(user_info): response_data = [] database_controller = DatabaseController(host=MONGO_HOST, port=MONGO_PORT) response_data = database_controller.read_tenants(user_info['id']) # Filter tenant members if user making the request is not the tenant owner for tenant in response_data: if tenant['owner_id'] != user_info['id']: tenant['users'] = [user for user in tenant['users'] if user['id'] == user_info['id']] return build_response(response_data, 200)
def delete_tenant(user_info, tenant_id): try: database_controller = DatabaseController(host=MONGO_HOST, port=MONGO_PORT) tenant_info = database_controller.get_tenant(tenant_id) if tenant_info is None: return build_response({ 'error': 'Tenant {} does not exist'.format(tenant_id) }, 404) if tenant_info['owner_id'] != user_info['id']: return build_response({ 'error': 'You are not authorized to delete tenant' }, 403) # Delete organization in the IDM keyrock_client = KeyrockClient(IDM_URL, IDM_USER, IDM_PASSWD) keyrock_client.delete_organization(tenant_info['tenant_organization']) # Delete policies in API Umbrella umbrella_client = UmbrellaClient(UMBRELLA_URL, UMBRELLA_TOKEN, UMBRELLA_KEY) broker_api = umbrella_client.get_api_from_app_id(BROKER_APP_ID) for broker_api_sg in broker_api: sub_settings = [setting for setting in broker_api_sg['sub_settings'] if not is_tenant_setting(setting, tenant_id)] broker_api_sg['sub_settings'] = sub_settings umbrella_client.update_api(broker_api_sg) # Delete tenant from database database_controller.delete_tenant(tenant_id) except (KeyrockError, UmbrellaError) as e: return build_response({ 'error': str(e) }, 503) return make_response('', 204)
def create(user_info): # Get tenant info for JSON request if 'name' not in request.json: return build_response({ 'error': 'Missing required field name' }, 422) if 'description' not in request.json: return build_response({ 'error': 'Missing required field description' }, 422) if 'users' in request.json: for user in request.json.get('users'): if 'name' not in user or 'roles' not in user: return build_response({ 'error': 'Missing required field in user specification' }, 422) options = {} if 'options' in request.json: if not isinstance(request.json.get('options'), dict): return build_response({ 'error': 'Options field must be an object' }, 422) options = request.json.get('options') tenant_id = None try: # Build tenant-id tenant_id = URLify(request.json.get('name')) if not len(tenant_id): # All the provided characters were invalid return build_response({ 'error': 'It was not possible to generate a tenant ID as all the characters were invalid' }, 422) database_controller = DatabaseController(host=MONGO_HOST, port=MONGO_PORT) prev_t = database_controller.get_tenant(tenant_id) if prev_t is not None: return build_response({ 'error': 'The tenant {} is already registered'.format(tenant_id) }, 409) keyrock_client = KeyrockClient(IDM_URL, IDM_USER, IDM_PASSWD) org_id = keyrock_client.create_organization( request.json.get('name'), request.json.get('description'), user_info['id']) # Add context broker role keyrock_client.authorize_organization(org_id, BROKER_APP_ID, BROKER_ADMIN_ROLE, BROKER_CONSUMER_ROLE) # Add BAE roles keyrock_client.authorize_organization_role(org_id, BAE_APP_ID, BAE_SELLER_ROLE, 'owner') keyrock_client.authorize_organization_role(org_id, BAE_APP_ID, BAE_CUSTOMER_ROLE, 'owner') keyrock_client.authorize_organization_role(org_id, BAE_APP_ID, BAE_ADMIN_ROLE, 'owner') # Add tenant users if provided users = [] for user in request.json.get('users', []): # User names are not used to identify users in Keyrock if 'id' not in user: user_id = keyrock_client.get_user_id(user['name']) else: user_id = user['id'] user_obj = { 'id': user_id, 'name': user['name'], 'roles': [] } # Keyrock IDM only supports a single organization role user_obj['roles'].append(BROKER_CONSUMER_ROLE) if BROKER_ADMIN_ROLE in user['roles']: keyrock_client.grant_organization_role(org_id, user_id, 'owner') user_obj['roles'].append(BROKER_ADMIN_ROLE) else: keyrock_client.grant_organization_role(org_id, user_id, 'member') users.append(user_obj) _create_access_policies(tenant_id, org_id, user_info) database_controller.save_tenant( tenant_id, request.json.get('name'), request.json.get('description'), user_info['id'], users, org_id, options=options) except (KeyrockError, UmbrellaError) as e: return build_response({ 'error': str(e) }, 503) response = make_response('', 201) response.headers['Location'] = request.path + '/' + tenant_id return response
def internal_server_error(e): return build_response({ 'error': 'Internal server error' }, 500)
def not_found(e): return build_response({ 'error': 'API endpoint not found' }, 404)
def bad_request(e): return build_response({ 'error': e.description }, 400)
def update_tenant(user_info, tenant_id): try: database_controller = DatabaseController(host=MONGO_HOST, port=MONGO_PORT) tenant_info = database_controller.get_tenant(tenant_id) if tenant_info is None: return build_response({ 'error': 'Tenant {} does not exist'.format(tenant_id) }, 404) if tenant_info['owner_id'] != user_info['id'] and IDM_USER_ID != user_info['id']: return build_response({ 'error': 'You are not authorized to update tenant' }, 403) patch = jsonpatch.JsonPatch(request.json) # Apply JSON patch # Valid operations replace description, add user, remove user keyrock_client = KeyrockClient(IDM_URL, IDM_USER, IDM_PASSWD) tenant_update = patch.apply(tenant_info) if len(tenant_update) != len(tenant_info): raise ValueError('It is not allowed to add or remove fields from tenant') if tenant_update['id'] != tenant_id: raise ValueError('Tenant ID cannot be modified') if tenant_update['tenant_organization'] != tenant_info['tenant_organization']: raise ValueError('Tenant organization cannot be modified') if tenant_update['owner_id'] != tenant_info['owner_id']: raise ValueError('Tenant owner ID cannot be modified') if tenant_update['description'] != tenant_info['description'] \ or tenant_update['name'] != tenant_info['name']: update = {} if tenant_update['description'] != tenant_info['description']: update['description'] = tenant_update['description'] if tenant_update['name'] != tenant_info['name']: update['name'] = tenant_update['name'] keyrock_client.update_organization(tenant_update['tenant_organization'], update) if tenant_update['users'] != tenant_info['users']: roles_update = {} to_add = process_users_diff(tenant_update['users'], tenant_info['users'], roles_update=roles_update) to_del = process_users_diff(tenant_info['users'], tenant_update['users']) for user in to_add: add_tenant_user(keyrock_client, tenant_info, user) for user in to_del: remove_tenant_user(keyrock_client, tenant_info, user) for user_id, roles in roles_update.items(): update_tenant_roles(keyrock_client, tenant_info, user_id, roles['old'], roles['new']) # Normalize user information to prevent ewrong role info new_users = [] for user in tenant_update['users']: roles = [BROKER_CONSUMER_ROLE] if BROKER_ADMIN_ROLE in user['roles']: roles.append(BROKER_ADMIN_ROLE) user['roles'] = roles database_controller.update_tenant(tenant_id, tenant_update) except ValueError as e: return build_response({ 'error': str(e) }, 422) except jsonpatch.JsonPatchTestFailed: return build_response({ 'error': 'Test operation not successful' }, 409) except jsonpatch.JsonPatchConflict: return build_response({ 'error': 'Conflict applying PATCH, verify indexes and keys' }, 409) except jsonpatch.InvalidJsonPatch as e: return build_response({ 'error': 'Invalid JSON PATCH format: ' + str(e) }, 400) except KeyrockError as e: return build_response({ 'error': str(e) }, 503) return make_response('', 200)