def token_grant(admin_access_token, id_, email): """Grant a token to the selected user.""" try: admin = User.query.filter_by(id_=ADMIN_USER_ID).one_or_none() if admin_access_token != admin.access_token: raise ValueError("Admin access token invalid.") user = _get_user_by_criteria(id_, email) error_msg = None if not user: error_msg = f"User {id_ or email} does not exist." elif user.access_token: error_msg = ( f"User {user.id_} ({user.email}) has already an active access token." ) if error_msg: click.secho(f"ERROR: {error_msg}", fg="red") sys.exit(1) if user.access_token_status in [UserTokenStatus.revoked.name, None]: click.confirm( f"User {user.id_} ({user.email}) access token status" f" is {user.access_token_status}, do you want to" " proceed?", abort=True, ) user_granted_token = secrets.token_urlsafe(16) user.access_token = user_granted_token Session.commit() log_msg = (f"Token for user {user.id_} ({user.email}) granted.\n" f"\nToken: {user_granted_token}") click.secho(log_msg, fg="green") admin.log_action(AuditLogAction.grant_token, {"reana_admin": log_msg}) # send notification to user by email email_subject = "REANA access token granted" email_body = JinjaEnv.render_template( "emails/token_granted.txt", user_full_name=user.full_name, reana_hostname=REANA_HOSTNAME, ui_config=REANAConfig.load("ui"), sender_email=ADMIN_EMAIL, ) send_email(user.email, email_subject, email_body) except click.exceptions.Abort: click.echo("Grant token aborted.") except REANAEmailNotificationError as e: click.secho( "Something went wrong while sending email:\n{}".format(e), fg="red", err=True, ) except Exception as e: click.secho( "Something went wrong while granting token:\n{}".format(e), fg="red", err=True, )
def token_revoke(admin_access_token, id_, email): """Revoke selected user's token.""" try: admin = User.query.filter_by(id_=ADMIN_USER_ID).one_or_none() if admin_access_token != admin.access_token: raise ValueError("Admin access token invalid.") user = _get_user_by_criteria(id_, email) error_msg = None if not user: error_msg = f"User {id_ or email} does not exist." elif not user.access_token: error_msg = (f"User {user.id_} ({user.email}) does not have an" " active access token.") if error_msg: click.secho(f"ERROR: {error_msg}", fg="red") sys.exit(1) revoked_token = user.access_token user.active_token.status = UserTokenStatus.revoked Session.commit() log_msg = (f"User token {revoked_token} ({user.email}) was" " successfully revoked.") click.secho(log_msg, fg="green") admin.log_action(AuditLogAction.revoke_token, {"reana_admin": log_msg}) # send notification to user by email email_subject = "REANA access token revoked" email_body = JinjaEnv.render_template( "emails/token_revoked.txt", user_full_name=user.full_name, reana_hostname=REANA_HOSTNAME, ui_config=REANAConfig.load("ui"), sender_email=ADMIN_EMAIL, ) send_email(user.email, email_subject, email_body) except REANAEmailNotificationError as e: click.secho( "Something went wrong while sending email:\n{}".format(e), fg="red", err=True, ) except Exception as e: click.secho( "Something went wrong while revoking token:\n{}".format(e), fg="red", err=True, )
def request_token(user): r"""Endpoint to request user access token. --- put: summary: Requests a new access token for the authenticated user. description: >- This resource allows the user to create an empty REANA access token and mark it as requested. operationId: request_token produces: - application/json parameters: - name: access_token in: query description: API access_token of user. required: false type: string responses: 200: description: >- User information correspoding to the session cookie sent in the request. schema: type: object properties: reana_token: type: object properties: status: type: string requested_at: type: string examples: application/json: { "reana_token": { "status": "requested", "requested_at": "Mon, 25 May 2020 10:45:15 GMT" } } 401: description: >- Error message indicating that the uses is not authenticated. schema: type: object properties: error: type: string examples: application/json: { "error": "User not logged in" } 403: description: >- Request failed. User token not valid. examples: application/json: { "message": "Token is not valid." } 500: description: >- Request failed. Internal server error. examples: application/json: { "message": "Internal server error." } """ try: user.request_access_token() user.log_action(AuditLogAction.request_token) email_subject = f"[{REANA_HOSTNAME}] Token request ({user.email})" fields = [ "id_", "email", "full_name", "username", "access_token", "access_token_status", ] user_data = "\n".join([f"{f}: {getattr(user, f, None)}" for f in fields]) email_body = JinjaEnv.render_template( "emails/token_request.txt", user_data=user_data, user_email=user.email, reana_hostname=REANA_HOSTNAME, ) try: send_email(ADMIN_EMAIL, email_subject, email_body) except REANAEmailNotificationError: logging.error(traceback.format_exc()) return ( jsonify( { "reana_token": { "status": user.access_token_status, "requested_at": user.latest_access_token.created, } } ), 200, ) except HTTPError as e: logging.error(traceback.format_exc()) return jsonify(e.response.json()), e.response.status_code except ValueError as e: logging.error(traceback.format_exc()) return jsonify({"message": str(e)}), 403 except Exception as e: logging.error(traceback.format_exc()) return jsonify({"message": str(e)}), 500