def update_user_fields(data, user): if user.id != 1: original_username = str(user.username) if 'username' in data and data['username']: user_db = User.query.filter_by(username=data['username']).first() if user_db is None or user_db.id == user.id: user.username = data['username'] else: return Problem(HTTPStatus.BAD_REQUEST, 'Cannot update user.', f"Username {data['username']} is already taken.") elif 'new_username' in data and data['new_username']: user_db = User.query.filter_by(username=data['old_username']).first() if user_db is None or user_db.id == user.id: user.username = data['new_username'] else: return Problem(HTTPStatus.BAD_REQUEST, 'Cannot update user.', f"Username {data['new_username']} is already taken.") if 'old_password' in data and 'password' in data and \ data['old_password'] != "" and data['password'] != "": logger.info("go there") if user.verify_password(data['old_password']): user.password = data['password'] else: user.username = original_username return Problem.from_crud_resource( HTTPStatus.UNAUTHORIZED, 'user', 'update', 'Current password is incorrect.') db.session.commit() current_app.logger.info(f"Updated user {user.id}. Updated to: {user.as_json()}") return user.as_json(), HTTPStatus.OK else: return None, HTTPStatus.FORBIDDEN
def update_personal_user(username): data = request.get_json() current_user = get_jwt_identity() # check for internal user if username.id == 1: return Problem.from_crud_resource( HTTPStatus.FORBIDDEN, 'user', 'update', f"Current user does not have permission to update user {username.id}.") # check password if username.verify_password(data['old_password']): if username.id == current_user: # allow ability to update username/password but not roles/active if username.id == 2: username.set_roles([2]) username.active = True return update_user_fields(data, username) else: return update_user_fields(data, username) else: return Problem.from_crud_resource( HTTPStatus.FORBIDDEN, 'user', 'update', f"Current user does not have permission to update user {username.id}.") else: return None, HTTPStatus.FORBIDDEN
def __func(): config_in = request.get_json() if not _reset_token_durations(access_token_duration=config_in.get( 'access_token_duration', None), refresh_token_duration=config_in.get( 'refresh_token_duration', None)): return Problem.from_crud_resource( HTTPStatus.BAD_REQUEST, 'configuration', 'update', 'Access token duration must be less than refresh token duration.' ) for config, config_value in config_in.items(): if hasattr(api_gateway.config.Config, config.upper()): setattr(api_gateway.config.Config, config.upper(), config_value) elif hasattr(current_app.config, config.upper()): setattr(current_app.config, config.upper(), config_value) current_app.logger.info('Changed configuration') try: api_gateway.config.Config.write_values_to_file() return __get_current_configuration(), HTTPStatus.OK except (IOError, OSError) as e: current_app.logger.error( 'Could not write changes to configuration to file') return Problem( HTTPStatus.INTERNAL_SERVER_ERROR, 'Could not write changes to file.', 'Could not write configuration changes to file. Problem: {}'. format(format_exception_message(e)))
def stream_console_events(): workflow_execution_id = request.args.get('workflow_execution_id') if workflow_execution_id is None: return Problem(HTTPStatus.BAD_REQUEST, 'Could not connect to log stream', 'workflow_execution_id is a required query param') try: UUID(workflow_execution_id) return console_stream.stream(subchannel=workflow_execution_id) except (ValueError, AttributeError): return Problem(HTTPStatus.BAD_REQUEST, 'Could not connect to log stream', 'workflow_execution_id must be a valid UUID')
def update_user(user_id): data = request.get_json() current_user = get_jwt_identity() # check for internal user if user_id.id == 1: return None, HTTPStatus.FORBIDDEN if user_id.id == current_user: # check for super_admin, allows ability to update username/password but not roles/active if user_id.id == 2: user_id.set_roles([2]) user_id.active = True return update_user_fields(data, user_id) return role_update_user_fields(data, user_id, update=True) else: # check for super_admin if user_id.id == 2: return None, HTTPStatus.FORBIDDEN else: response = role_update_user_fields(data, user_id, update=True) if isinstance(response, tuple) and response[1] == HTTPStatus.FORBIDDEN: current_app.logger.error(f"User {current_user} does not have permission to update user {user_id.id}") return Problem.from_crud_resource( HTTPStatus.FORBIDDEN, 'user', 'update', f"Current user does not have permission to update user {user_id.id}.") else: return response
def create_role(): json_data = request.get_json() if not Role.query.filter_by(name=json_data['name']).first(): resources = json_data['resources'] if 'resources' in json_data else [] if '/roles' in resources: resources.remove('/roles') role_params = { 'name': json_data['name'], 'description': json_data['description'] if 'description' in json_data else '', 'resources': resources } new_role = Role(**role_params) db.session.add(new_role) db.session.commit() current_app.logger.info(f"Role added: {role_params}") return new_role.as_json(), HTTPStatus.CREATED else: current_app.logger.warning( f"Role with name {json_data['name']} already exists") return Problem.from_crud_resource( HTTPStatus.BAD_REQUEST, 'role', 'create', f"Role with name {json_data['name']} already exists")
def __func(): data = request.get_json() refresh_token = data.get('refresh_token', None) if data else None if refresh_token is None: return Problem(HTTPStatus.BAD_REQUEST, 'Could not logout.', 'A refresh token is required to logout.') decoded_refresh_token = decode_token(refresh_token) refresh_token_identity = decoded_refresh_token[current_app.config['JWT_IDENTITY_CLAIM']] user_id = get_jwt_identity() if user_id == refresh_token_identity: user = User.query.filter(User.id == user_id).first() if user is not None: user.logout() revoke_token(decode_token(refresh_token)) return None, HTTPStatus.NO_CONTENT else: return Problem( HTTPStatus.BAD_REQUEST, 'Could not logout.', 'The identity of the refresh token does not match the identity of the authentication token.')
def delete_user(user_id): if user_id.id != get_jwt_identity() and user_id.id != 1 and user_id.id != 2: db.session.delete(user_id) db.session.commit() current_app.logger.info(f"User {user_id.username} deleted") return None, HTTPStatus.NO_CONTENT else: if user_id.id == get_jwt_identity(): current_app.logger.error(f"Could not delete user {user_id.id}. User is current user.") return Problem.from_crud_resource(HTTPStatus.FORBIDDEN, 'user', 'delete', 'Current user cannot delete self.') if user_id.id == 2: current_app.logger.error(f"Could not delete user {user_id.username}. " f"You do not have permission to delete Super Admin.") return Problem.from_crud_resource(HTTPStatus.FORBIDDEN, 'user', 'delete', 'A user cannot delete Super Admin.') if user_id.id == 1: current_app.logger.error(f"Could not delete user {user_id.username}. " f"You do not have permission to delete WALKOFF's internal user.") return Problem.from_crud_resource(HTTPStatus.FORBIDDEN, 'user', 'delete', "A user cannot delete WALKOFF's internal user.")
def refresh(body=None, token_info=None, user=None): current_user_id = get_jwt_identity() user = User.query.filter(User.id == current_user_id).first() if user is None: revoke_token(get_raw_jwt()) return Problem( HTTPStatus.UNAUTHORIZED, 'Could not grant access token.', 'User {} from refresh JWT identity could not be found.'.format(current_user_id)) if user.active: return {'access_token': create_access_token(identity=current_user_id, fresh=False)}, HTTPStatus.CREATED else: return user_deactivated_problem
def delete_user(user_id): if user_id.id != get_jwt_identity( ) and user_id.username != "internal_user": db.session.delete(user_id) db.session.commit() current_app.logger.info(f"User {user_id.username} deleted") return None, HTTPStatus.NO_CONTENT else: current_app.logger.error( f"Could not delete user {user_id.id}. User is current user.") return Problem.from_crud_resource(HTTPStatus.FORBIDDEN, 'user', 'delete', 'Current user cannot delete self.')
def __func(): # TODO: Remove this once connexion can validate enums with openapi3. if field_name not in [ 'info', 'action_apis', 'condition_apis', 'transform_apis', 'device_apis', 'tags', 'externalDocs' ]: return Problem(HTTPStatus.BAD_REQUEST, 'Could not read app api.', '{} is not a valid field name.'.format(field_name)) api = json.loads(redis_cache.hget("app-apis", app_name)) if api is not None: return format_full_app_api(api, app_name)[field_name], HTTPStatus.OK else: return app_api_dne_problem(app_name)
def update_settings(): config_in = request.get_json() if not _reset_token_durations(access_token_duration=config_in.get('access_token_duration', None), refresh_token_duration=config_in.get('refresh_token_duration', None)): return Problem.from_crud_resource( HTTPStatus.BAD_REQUEST, 'settings', 'update', 'Access token duration must be less than refresh token duration.') for config, config_value in config_in.items(): if hasattr(api_gateway.flask_config.FlaskConfig, config.upper()): setattr(api_gateway.flask_config.FlaskConfig, config.upper(), config_value) elif hasattr(current_app.config, config.upper()): setattr(current_app.config, config.upper(), config_value) current_app.logger.info('Changed settings')
def create_user(): data = request.get_json() username = data['username'] if not User.query.filter_by(username=username).first(): user = add_user(username=username, password=data['password']) if 'roles' in data or 'active' in data: role_update_user_fields(data, user) db.session.commit() current_app.logger.info(f'User added: {user.as_json()}') return user.as_json(), HTTPStatus.CREATED else: current_app.logger.warning( f'Cannot create user {username}. User already exists.') return Problem.from_crud_resource( HTTPStatus.BAD_REQUEST, 'user', 'create', f'User with username {username} already exists')
def __func(): # TODO: Remove this once connexion can validate enums with openapi3. if field_name and field_name not in [ 'info', 'action_apis', 'condition_apis', 'transform_apis', 'device_apis', 'tags', 'external_docs' ]: return Problem(HTTPStatus.BAD_REQUEST, 'Could not read app api.', '{} is not a valid field name.'.format(field_name)) ret = [] for app_name, app_api in redis_cache.hgetall("app-apis").items(): ret.append( format_full_app_api(json.loads(app_api), app_name.decode("utf-8"))) if field_name is not None: default = [] if field_name not in ('info', 'external_docs') else {} ret = [{ 'name': api['name'], field_name: api.get(field_name, default) } for api in ret] return ret, HTTPStatus.OK
def update_user(user_id): data = request.get_json() current_user = get_jwt_identity() if user_id.username == "internal_user": return None, HTTPStatus.FORBIDDEN if user_id.id == current_user: return update_user_fields(data, user_id) else: response = role_update_user_fields(data, user_id, update=True) if isinstance(response, tuple) and response[1] == HTTPStatus.FORBIDDEN: current_app.logger.error( f"User {current_user} does not have permission to update user {user_id.id}" ) return Problem.from_crud_resource( HTTPStatus.FORBIDDEN, 'user', 'update', f"Current user does not have permission to update user {user_id.id}." ) else: return response
def __func(workflow): if not workflow.is_valid: return Problem(HTTPStatus.BAD_REQUEST, 'Cannot execute workflow', 'Workflow is invalid') # Short circuits the multiprocessed executor workflow = current_app.running_context.execution_db.session.query( Workflow).filter_by(id=workflow_id).first() workflow_schema = WorkflowSchema() workflow = workflow_schema.dump(workflow) execution_id = str(uuid.uuid4()) workflow_data = { 'execution_id': execution_id, 'id': workflow["id"], 'name': workflow["name"] } current_app.running_context.results_sender.handle_event( workflow=workflow, sender=workflow_data, event=WalkoffEvent.WorkflowExecutionPending, data=data) message = { "workflow": workflow, "workflow_id": str(workflow_id), "execution_id": execution_id } current_app.running_context.cache.lpush( "workflow-queue", json.dumps(message)) # self.__box.encrypt(message)) current_app.running_context.results_sender.handle_event( workflow=workflow, sender=workflow_data, event=WalkoffEvent.SchedulerJobExecuted, data=data) current_app.logger.info('Executed workflow {0}'.format(workflow_id)) return {'id': execution_id}, HTTPStatus.ACCEPTED
from flask import request, current_app from flask_jwt_extended import (jwt_refresh_token_required, create_access_token, create_refresh_token, get_jwt_identity, get_raw_jwt, jwt_required, decode_token) from api_gateway.server.problem import Problem from http import HTTPStatus from api_gateway.serverdb import User, db from api_gateway.serverdb.tokens import revoke_token token_problem_title = 'Could not grant access token.' invalid_username_password_problem = Problem( HTTPStatus.UNAUTHORIZED, token_problem_title, 'Invalid username or password.') user_deactivated_problem = Problem(HTTPStatus.UNAUTHORIZED, token_problem_title, 'User is deactivated.') def _authenticate_and_grant_tokens(json_in, with_refresh=False): username = json_in.get('username', None) password = json_in.get('password', None) if not (username and password): return invalid_username_password_problem user = User.query.filter_by(username=username).first() if user is None: return invalid_username_password_problem try: password = password.encode('utf-8') except UnicodeEncodeError: return invalid_username_password_problem if not user.active: return user_deactivated_problem if user.verify_password(password):
def scheduled_task_name_already_exists_problem(name, operation): return Problem.from_crud_resource( HTTPStatus.BAD_REQUEST, 'scheduled task', operation, 'Could not {} scheduled task. Scheduled task with name {} already exists.' .format(operation, name))
def invalid_uuid_problem(invalid_uuids): return Problem(HTTPStatus.BAD_REQUEST, 'Invalid scheduled task.', 'Specified UUIDs {} are not valid.'.format(invalid_uuids))
def invalid_uuid_problem(invalid_uuids): return Problem(HTTPStatus.BAD_REQUEST, 'Invalid scheduled task.', 'Specified UUIDs {} are not valid.'.format(invalid_uuids)) def scheduled_task_name_already_exists_problem(name, operation): return Problem.from_crud_resource( HTTPStatus.BAD_REQUEST, 'scheduled task', operation, 'Could not {} scheduled task. Scheduled task with name {} already exists.' .format(operation, name)) invalid_scheduler_args_problem = Problem(HTTPStatus.BAD_REQUEST, 'Invalid scheduled task.', 'Invalid scheduler arguments.') def create_scheduled_task(): @jwt_required @permissions_accepted_for_resources( ResourcePermissions('scheduler', ['create', 'execute'])) def __func(): data = request.get_json() invalid_uuids = validate_uuids(data['workflows']) if invalid_uuids: return invalid_uuid_problem(invalid_uuids) task = ScheduledTask.query.filter_by(name=data['name']).first() if task is None: try:
def handle_generic_server_error(e): current_app.logger.exception('Caught an unhandled error.') return Problem(HTTPStatus.INTERNAL_SERVER_ERROR, 'An error occurred in the server.', e.__class__.__name__)
def handle_database_errors(e): current_app.logger.exception('Caught an unhandled SqlAlchemy exception.') return Problem(HTTPStatus.INTERNAL_SERVER_ERROR, 'A database error occurred.', e.__class__.__name__)
def app_api_dne_problem(app_name): return Problem(HTTPStatus.NOT_FOUND, 'Could not read app api.', 'App {} does not exist.'.format(app_name))