import os from datetime import datetime from urllib.parse import urlencode import sentry_sdk from authlib.integrations.base_client import OAuthError from authlib.integrations.flask_client import OAuth from flask import Flask, flash, redirect, request, session from sentry_sdk.integrations.flask import FlaskIntegration from sentry_sdk.utils import BadDsn from src import admin from src.audit import AuditLog from src.db import db sentry_dsn = os.environ.get("SENTRY_DSN") sentry_env = os.environ.get("FLASK_ENV", "development") if sentry_dsn: try: sentry_sdk.init(dsn=sentry_dsn, environment=sentry_env, integrations=[FlaskIntegration()]) except BadDsn: pass app = Flask(__name__) app.secret_key = os.environ.get("SECRET_KEY", "SECRET KEY") app.config.from_object("config") app.config["ADMIN_RAISE_ON_INTEGRITY_ERROR"] = True AuditLog.init_app(app) db.init_app(app) admin.init_app(app) oauth = OAuth(app) auth0 = oauth.register( "auth0", client_id=app.config["AUTH0_CLIENT_ID"], client_secret=app.config["AUTH0_CLIENT_SECRET"], api_base_url=app.config["AUTH0_BASE_URL"], access_token_url=app.config["AUTH0_BASE_URL"] + "/oauth/token", authorize_url=app.config["AUTH0_BASE_URL"] + "/authorize", client_kwargs={"scope": "openid profile email offline_access"}, ) @app.before_request def before_request_func(): expires_at = session.get("token", {}).get("expires_at") if expires_at and expires_at < datetime.timestamp(datetime.now()): refresh_token = session.get("token", {}).get("refresh_token", "") try: token = auth0.fetch_access_token(refresh_token=refresh_token, grant_type="refresh_token") session["token"].update(token) except OAuthError: session.clear() flash("User is blocked", "error") return redirect("/logout") @app.route("/callback") def callback_handling(): if "error" in request.args: session.clear() flash(request.args.get("error_description").capitalize(), "error") return redirect("/logout") session["token"] = auth0.authorize_access_token() resp = auth0.get("userinfo") userinfo = resp.json() permissions = userinfo.get(app.config["AUTH0_USER_PAYLOAD_KEY"], {}).get("permissions", []) session[app.config["USER_ACCESS_KEY"]] = app.config["USER_ACCESS_PERMISSION"] in permissions session[app.config["SUPERUSER_ACCESS_KEY"]] = app.config["SUPERUSER_ACCESS_PERMISSION"] in permissions session[app.config["JWT_PAYLOAD"]] = userinfo session[app.config["PROFILE_KEY"]] = { "user_id": userinfo["sub"], "name": userinfo["name"], "picture": userinfo["picture"], "permissions": permissions, } return redirect("/") @app.route("/login") def login(): session.clear() return auth0.authorize_redirect( redirect_uri=app.config["AUTH0_CALLBACK_URL"], audience=app.config["AUTH0_AUDIENCE"] ) @app.route("/logout") def logout(): _flashes = session.get("_flashes", []) session.clear() for _flash in _flashes: flash(_flash[1], _flash[0]) params = {"returnTo": request.host_url, "client_id": app.config["AUTH0_CLIENT_ID"]} return redirect(auth0.api_base_url + "/v2/logout?" + urlencode(params)) @app.route("/health") def health(): return "Ok" if __name__ == "__main__": app.run(host="0.0.0.0", port=4000) # nosec