def delete_region(keycloak: KeycloakClient, region_id, user): region = model.Region.query.get(region_id) if not region: return problem(404, 'Not Found', f'Region {region_id} does not exist') if not keycloak.user_check_role(user, ADMIN_ROLE): if not keycloak.user_check_group(user, region.owner_group): raise Forbidden("You don't have write access to this region.") q = model.RegionProduct.query.filter( model.RegionProduct.region_id == region.id, ) if q.count() > 0: for relation in q.all(): db.session.delete(relation) db.session.flush() db.session.delete(region) try: owner_group = keycloak.group_get(region.owner_group) keycloak.group_delete(owner_group['id']) logger.info(f'Deleted owners group {owner_group["id"]}') except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', f'Failed to delete owner group in Keycloak, {e}') db.session.commit() logger.info( f'Region {region.name} (id {region.id}) deleted by user {user}')
def add_region_product(keycloak: KeycloakClient, region_id, body, user): region = model.Region.query.get(region_id) if not region: return problem(404, 'Not Found', f'Region {region_id} does not exist') if not keycloak.user_check_role(user, ADMIN_ROLE): if not keycloak.user_check_group(user, region.owner_group): raise Forbidden("You don't have write access to this region.") product = model.Product.query.get(body['id']) if not product: return problem(404, 'Not Found', f'Product {body["id"]} does not exist') q = model.RegionProduct.query.filter( sqlalchemy.and_( model.RegionProduct.region_id == region.id, model.RegionProduct.product_id == product.id, )) if q.count() == 0: relation = model.RegionProduct( region_id=region.id, product_id=product.id, enabled=body.get('enabled', True), ) db.session.add(relation) db.session.commit() logger.info( f'Added Product {product.name} (id {product.id}) to Region {region.name} ' f'(id {region.id}) by user {user}') elif 'enabled' in body: for relation in q.all(): relation.enabled = body['enabled'] db.session.commit()
def list_region_products(keycloak: KeycloakClient, region_id, user, filter_): region = model.Region.query.get(region_id) if not region: return problem(404, 'Not Found', f'Region {region_id} does not exist') if region.users_group is not None: if not keycloak.user_check_role(user, ADMIN_ROLE): if not keycloak.user_check_group_any( user, [region.users_group, region.owner_group]): raise Forbidden("You don't have access to this region.") products_relation = region.products_relation if 'name' in filter_: products_relation = products_relation.filter( model.Region.name.ilike(filter_['enabled']), ) if 'enabled' in filter_: products_relation = products_relation.filter( model.Product.enabled == filter_['enabled'], ) return [{ 'id': r.product_id, 'region_id': r.region.id, 'product_id': r.product.id, 'product': r.product.to_dict(), 'enabled': r.enabled, } | { '_href': _region_href(r.region) | _product_href(r.product) } for r in products_relation]
def update_region(keycloak: KeycloakClient, vault: Vault, region_id, body, user): region = model.Region.query.get(region_id) if not region: return problem(404, 'Not Found', f'Region {region_id} does not exist') if not keycloak.user_check_role(user, ADMIN_ROLE): if not keycloak.user_check_group(user, region.owner_group): raise Forbidden("You don't have write access to this region.") try: if body.get('users_group'): keycloak.group_get(body['users_group']) except KeycloakGetError as e: logger.exception(e) return problem( 400, 'Users group does not exist', f'Users group {body["users_group"]} does not exist in Keycloak, ' 'you have to create group first or use existing group.') if 'quota' in body: if body['quota']: if region.quota is None: region.quota = model.Quota(**body['quota']) else: for k, v in body['quota'].items(): setattr(region.quota, k, v) else: region.quota = None del body['quota'] openstack_credentials = dpath.get(body, 'openstack/credentials', default=region.openstack_credentials) if not isinstance(openstack_credentials, str): vault.write(region.openstack_credentials, openstack_credentials) dpath.delete(body, 'openstack/credentials') satellite_credentials = dpath.get(body, 'satellite/credentials', default=region.satellite_credentials) if not isinstance(satellite_credentials, str): vault.write(region.satellite_credentials, satellite_credentials) dpath.delete(body, 'satellite/credentials') dns_server_key = dpath.get(body, 'dns_server/key', default=region.dns_server_key) if not isinstance(dns_server_key, str): vault.write(region.dns_server_key, dns_server_key) dpath.delete(body, 'dns_server/key') region.update_from_dict(body) db.session.commit() logger.info( f'Region {region.name} (id {region.id}) updated by user {user}') return region.to_dict() | {'_href': _region_href(region)}
def add_user_group(keycloak: KeycloakClient, user_id, body, user): try: keycloak.group_user_add(user_id, body['id']) return {}, 200 except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', str(e))
def delete_user_group(keycloak: KeycloakClient, user_id, user): try: keycloak.group_user_remove(user_id, request.json['id']) return {}, 200 except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', str(e))
def delete_group(keycloak: KeycloakClient, group_id, user): try: keycloak.group_delete(group_id) logger.info(f'Deleted group {group_id}') return {}, 200 except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', str(e))
def delete_role(keycloak: KeycloakClient, role_id, user): try: keycloak.role_delete(role_id) logger.info(f'Deleted role {role_id}') return {}, 200 except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', str(e))
def get_region(keycloak: KeycloakClient, region_id, user): region = model.Region.query.get(region_id) if not region: return problem(404, 'Not Found', f'Region {region_id} does not exist') if region.users_group is not None: if not keycloak.user_check_role(user, ADMIN_ROLE): if not keycloak.user_check_group_any( user, [region.users_group, region.owner_group]): raise Forbidden("You don't have access to this region.") return region.to_dict() | {'_href': _region_href(region)}
def update_group(keycloak: KeycloakClient, group_id, body, user): try: keycloak.group_update(group_id, body) logger.info(f'Updated group {group_id}') group_data = keycloak.group_get(group_id) return group_data | {'_href': _group_href(group_data)} except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', str(e))
def create_role(keycloak: KeycloakClient, body, user): try: role_id = keycloak.role_create(body) logger.info(f'Create role {role_id}') role_data = keycloak.role_get(role_id) return role_data | {'_href': _role_href(role_data)} except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', str(e))
def update_user(keycloak: KeycloakClient, user_id, body, user): try: keycloak.user_update(user_id, body) logger.info(f'Updated user {user_id}') user_data = keycloak.user_get(user_id) return user_data | {'_href': _user_href(user_data)} except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', str(e))
def update_role(keycloak: KeycloakClient, role_id, body, user): try: keycloak.role_update(role_id, body) role_name = body['name'] logger.info(f'Updated role {role_id}') role_data = keycloak.role_get(role_name) return role_data | {'_href': _role_href(role_data)} except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', str(e))
def list_product_regions(keycloak: KeycloakClient, product_id, user, filter_, page=0, limit=DEFAULT_PAGE_LIMIT): product = model.Product.query.get(product_id) if not product: return problem(404, 'Not Found', f'Product {product_id} does not exist') regions_relation = product.regions_relation if not keycloak.user_check_role(user, ADMIN_ROLE): user_groups = [group['id'] for group in keycloak.user_group_list(user)] regions_relation = regions_relation.filter( sqlalchemy.or_( model.Region.users_group.is_(None), model.Region.users_group.in_(user_groups), model.Region.owner_group.in_(user_groups), )) if 'name' in filter_: regions_relation = regions_relation.filter( model.Region.name.ilike(filter_['name']), ) if 'location' in filter_: regions_relation = regions_relation.filter( model.Region.location.ilike(filter_['location']), ) if 'enabled' in filter_: regions_relation = regions_relation.filter( sqlalchemy.and_( model.RegionProduct.enabled == filter_['enabled'], model.Region.enabled == filter_['enabled'], )) if 'reservations_enabled' in filter_: regions_relation = regions_relation.filter( model.Region.reservations_enabled == filter_['reservations_enabled'], ) return [{ 'id': r.region_id, 'region': r.region.to_dict(), 'enabled': r.enabled } for r in regions_relation]
def get_user(keycloak: KeycloakClient, user_id): try: user_data = keycloak.user_get(user_id) return user_data | {'_href': _user_href(user_data)} except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', str(e))
def list_regions(keycloak: KeycloakClient, user, filter_, sort=None, page=0, limit=DEFAULT_PAGE_LIMIT): if keycloak.user_check_role(user, ADMIN_ROLE): regions = model.Region.query else: user_groups = [group['id'] for group in keycloak.user_group_list(user)] regions = model.Region.query.filter( sqlalchemy.or_( model.Region.users_group.is_(None), model.Region.users_group.in_(user_groups), model.Region.owner_group.in_(user_groups), )) if 'name' in filter_: regions = regions.filter(model.Region.name.ilike(filter_['name'])) if 'location' in filter_: regions = regions.filter( model.Region.location.ilike(filter_['location'])) if 'enabled' in filter_: regions = regions.filter(model.Region.enabled == filter_['enabled']) if 'reservations_enabled' in filter_: regions = regions.filter(model.Region.reservations_enabled == filter_['reservations_enabled']) if sort: regions = db_sort(regions, sort) return { 'data': [ region.to_dict() | { '_href': _region_href(region) } for region in regions.limit(limit).offset(page * limit) ], 'total': regions.count(), }
def get_role(keycloak: KeycloakClient, role_id): try: role_data = keycloak.role_get(role_id) return role_data | {'_href': _role_href(role_data)} except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', str(e))
def get_group(keycloak: KeycloakClient, group_id): try: group_data = keycloak.group_get(group_id) return group_data | {'_href': _group_href(group_data)} except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', str(e))
def get_token_info(keycloak: KeycloakClient): # Bearer auth is enforced by connexion (see openapi spec) _, access_token = request.headers['Authorization'].split() try: return keycloak.token_info(access_token), 200 except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', str(e))
def list_groups(keycloak: KeycloakClient): try: return [ group | {'_href': _group_href(group)} for group in keycloak.group_list() ] except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', str(e))
def get_keycloak() -> KeycloakClient: """Get KeycloakClient instance.""" if 'keycloak' not in g: g.keycloak = KeycloakClient( server=current_app.config['KEYCLOAK_SERVER'], resource=current_app.config['KEYCLOAK_RESOURCE'], realm=current_app.config['KEYCLOAK_REALM'], secret=current_app.config['KEYCLOAK_SECRET'], admin_user=current_app.config['KEYCLOAK_ADMIN_USER'], admin_pass=current_app.config['KEYCLOAK_ADMIN_PASS'], ) return g.keycloak
def list_roles(keycloak: KeycloakClient): try: return [ role | { '_href': _role_href(role) } for role in keycloak.role_list() ] except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', str(e))
def list_group_users(keycloak: KeycloakClient, group_id): try: from rhub.api.auth.user import _user_href return [ user | {'_href': _user_href(user)} for user in keycloak.group_user_list(group_id) ] except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', str(e))
def list_user_groups(keycloak: KeycloakClient, user_id): try: from rhub.api.auth.group import _group_href return [ group | { '_href': _group_href(group) } for group in keycloak.user_group_list(user_id) ] except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', str(e))
def delete_policy(keycloak: KeycloakClient, user, policy_id): """ API endpoint to delete policy given policy id """ policy = model.Policy.query.get(policy_id) if not policy: return problem(404, 'Not Found', 'Record Does Not Exist') try: groups = {group['name']: group for group in keycloak.group_list()} group_name = f'policy-{policy_id}-owners' group_id = groups[group_name]['id'] keycloak.group_delete(group_id) except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', f'Failed to delete owner group in Keycloak, {e}') db.session.delete(policy) db.session.commit()
def create_policy(keycloak: KeycloakClient, user, body): """ API endpoint to create a policy (JSON formatted) """ policy = model.Policy.from_dict(body) try: db.session.add(policy) db.session.flush() group_id = keycloak.group_create( {'name': f'policy-{policy.id}-owners'}) keycloak.group_user_add(user, group_id) keycloak.group_role_add('policy-owner', group_id) db.session.commit() except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', f'Failed to delete owner group in Keycloak, {e}') return policy.to_dict()
def delete_region_product(keycloak: KeycloakClient, region_id, user): region = model.Region.query.get(region_id) if not region: return problem(404, 'Not Found', f'Region {region_id} does not exist') if not keycloak.user_check_role(user, ADMIN_ROLE): if not keycloak.user_check_group(user, region.owner_group): raise Forbidden("You don't have write access to this region.") product = model.Product.query.get(request.json['id']) if not product: return problem(404, 'Not Found', f'Product {request.json["id"]} does not exist') q = model.RegionProduct.query.filter( sqlalchemy.and_( model.RegionProduct.region_id == region.id, model.RegionProduct.product_id == product.id, )) if q.count() > 0: for relation in q.all(): db.session.delete(relation) db.session.commit()
def create_token(keycloak: KeycloakClient): if not request.authorization: return problem(401, 'Unauthorized', 'Missing basic auth credentials') username = request.authorization['username'] password = request.authorization['password'] try: return keycloak.login(username, password), 200 except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', str(e))
def refresh_token(keycloak: KeycloakClient): if 'Authorization' not in request.headers: return problem(401, 'Unauthorized', 'Missing refresh token') try: _, refresh_token = request.headers['Authorization'].split() except Exception: return problem(401, 'Unauthorized', 'Invalid token') try: return keycloak.token_refresh(refresh_token), 200 except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', str(e))
def list_users(keycloak: KeycloakClient, filter_, page=0, limit=DEFAULT_PAGE_LIMIT): try: return [ user | { '_href': _user_href(user) } for user in keycloak.user_list({ 'first': page * limit, 'max': limit, **filter_, }) ] except KeycloakGetError as e: logger.exception(e) return problem_from_keycloak_error(e) except Exception as e: logger.exception(e) return problem(500, 'Unknown Error', str(e))