From f377b4ce45630c665861345f1257d3649c47d155 Mon Sep 17 00:00:00 2001 From: Luka Radenovic Date: Wed, 13 Apr 2022 10:27:17 +0200 Subject: [PATCH] Refactor integrations of sso --- app.py | 22 +-- areas/__init__.py | 3 +- areas/apps/__init__.py | 3 +- areas/apps/models.py | 29 ++++ areas/cliapp/__init__.py | 2 - cliapp/__init__.py | 3 + cliapp/cliapp/__init__.py | 1 + {areas => cliapp}/cliapp/cli.py | 110 +++++-------- config.py | 10 +- helpers/__init__.py | 3 +- helpers/{kratos.py => kratos_user.py} | 0 helpers/models.py | 54 ------- web/__init__.py | 10 ++ {areas => web}/login/__init__.py | 0 {areas => web}/login/login.py | 153 +++++++----------- {static => web/static}/.gitkeep | 0 {static => web/static}/base.js | 0 {static => web/static}/css/bootstrap-grid.css | 0 .../static}/css/bootstrap-grid.css.map | 0 .../static}/css/bootstrap-grid.min.css | 0 .../static}/css/bootstrap-grid.min.css.map | 0 .../static}/css/bootstrap-reboot.css | 0 .../static}/css/bootstrap-reboot.css.map | 0 .../static}/css/bootstrap-reboot.min.css | 0 .../static}/css/bootstrap-reboot.min.css.map | 0 {static => web/static}/css/bootstrap.css | 0 {static => web/static}/css/bootstrap.css.map | 0 {static => web/static}/css/bootstrap.min.css | 0 .../static}/css/bootstrap.min.css.map | 0 {static => web/static}/js/bootstrap.bundle.js | 0 .../static}/js/bootstrap.bundle.js.map | 0 .../static}/js/bootstrap.bundle.min.js | 0 .../static}/js/bootstrap.bundle.min.js.map | 0 {static => web/static}/js/bootstrap.js | 0 {static => web/static}/js/bootstrap.js.map | 0 {static => web/static}/js/bootstrap.min.js | 0 .../static}/js/bootstrap.min.js.map | 0 {static => web/static}/js/jquery-3.6.0.min.js | 0 {static => web/static}/js/js.cookie.min.js | 0 {static => web/static}/logo.svg | 0 {static => web/static}/style.css | 0 {templates => web/templates}/base.html | 0 {templates => web/templates}/loggedin.html | 0 {templates => web/templates}/login.html | 0 {templates => web/templates}/recover.html | 0 {templates => web/templates}/settings.html | 0 46 files changed, 154 insertions(+), 249 deletions(-) create mode 100644 areas/apps/models.py delete mode 100644 areas/cliapp/__init__.py create mode 100644 cliapp/__init__.py create mode 100644 cliapp/cliapp/__init__.py rename {areas => cliapp}/cliapp/cli.py (85%) rename helpers/{kratos.py => kratos_user.py} (100%) delete mode 100644 helpers/models.py create mode 100644 web/__init__.py rename {areas => web}/login/__init__.py (100%) rename {areas => web}/login/login.py (76%) rename {static => web/static}/.gitkeep (100%) rename {static => web/static}/base.js (100%) rename {static => web/static}/css/bootstrap-grid.css (100%) rename {static => web/static}/css/bootstrap-grid.css.map (100%) rename {static => web/static}/css/bootstrap-grid.min.css (100%) rename {static => web/static}/css/bootstrap-grid.min.css.map (100%) rename {static => web/static}/css/bootstrap-reboot.css (100%) rename {static => web/static}/css/bootstrap-reboot.css.map (100%) rename {static => web/static}/css/bootstrap-reboot.min.css (100%) rename {static => web/static}/css/bootstrap-reboot.min.css.map (100%) rename {static => web/static}/css/bootstrap.css (100%) rename {static => web/static}/css/bootstrap.css.map (100%) rename {static => web/static}/css/bootstrap.min.css (100%) rename {static => web/static}/css/bootstrap.min.css.map (100%) rename {static => web/static}/js/bootstrap.bundle.js (100%) rename {static => web/static}/js/bootstrap.bundle.js.map (100%) rename {static => web/static}/js/bootstrap.bundle.min.js (100%) rename {static => web/static}/js/bootstrap.bundle.min.js.map (100%) rename {static => web/static}/js/bootstrap.js (100%) rename {static => web/static}/js/bootstrap.js.map (100%) rename {static => web/static}/js/bootstrap.min.js (100%) rename {static => web/static}/js/bootstrap.min.js.map (100%) rename {static => web/static}/js/jquery-3.6.0.min.js (100%) rename {static => web/static}/js/js.cookie.min.js (100%) rename {static => web/static}/logo.svg (100%) rename {static => web/static}/style.css (100%) rename {templates => web/templates}/base.html (100%) rename {templates => web/templates}/loggedin.html (100%) rename {templates => web/templates}/login.html (100%) rename {templates => web/templates}/recover.html (100%) rename {templates => web/templates}/settings.html (100%) diff --git a/app.py b/app.py index 8eccb79..79a4ad2 100644 --- a/app.py +++ b/app.py @@ -4,18 +4,17 @@ from flask_jwt_extended import JWTManager from flask_migrate import Migrate from jsonschema.exceptions import ValidationError from werkzeug.exceptions import BadRequest -from flask_sqlalchemy import SQLAlchemy # These imports are required from areas import api_v1 -from areas import web -from areas import cli +from cliapp import cli +from web import web from areas import users from areas import apps from areas import auth -from areas import login -from areas import cliapp +from cliapp import cliapp +from web import login from database import db @@ -28,26 +27,21 @@ from helpers import ( kratos_error, global_error, hydra_error, - KratosUser, - App, - AppRole ) from config import * import logging -app = Flask(__name__, static_url_path = '/web/static') - -cors = CORS(app) +app = Flask(__name__) app.config["SECRET_KEY"] = SECRET_KEY app.config["SQLALCHEMY_DATABASE_URI"] = SQLALCHEMY_DATABASE_URI +app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = SQLALCHEMY_TRACK_MODIFICATIONS -## from database import db -#db = SQLAlchemy() +cors = CORS(app) +Migrate(app, db) db.init_app(app) -Migrate(app, db) app.logger.setLevel(logging.INFO) diff --git a/areas/__init__.py b/areas/__init__.py index e8d95f3..1ab3870 100644 --- a/areas/__init__.py +++ b/areas/__init__.py @@ -1,8 +1,7 @@ from flask import Blueprint api_v1 = Blueprint("api_v1", __name__, url_prefix="/api/v1") -web = Blueprint("web", __name__, url_prefix="/web") -cli = Blueprint('cli', __name__) + @api_v1.route("/") @api_v1.route("/health") diff --git a/areas/apps/__init__.py b/areas/apps/__init__.py index 2dbf1c6..937a88c 100644 --- a/areas/apps/__init__.py +++ b/areas/apps/__init__.py @@ -1 +1,2 @@ -from .apps import * \ No newline at end of file +from .apps import * +from .models import * diff --git a/areas/apps/models.py b/areas/apps/models.py new file mode 100644 index 0000000..aa6b20e --- /dev/null +++ b/areas/apps/models.py @@ -0,0 +1,29 @@ +from sqlalchemy import ForeignKey, Integer, String +from database import db + + +class App(db.Model): + """ + The App object, interact with the App database object. Data is stored in + the local database. + """ + + id = db.Column(Integer, primary_key=True) + name = db.Column(String(length=64)) + slug = db.Column(String(length=64), unique=True) + + def __repr__(self): + return f"{self.id} <{self.name}>" + + +class AppRole(db.Model): + """ + The AppRole object, stores the roles Users have on Apps + """ + + user_id = db.Column(String(length=64), primary_key=True) + app_id = db.Column(Integer, ForeignKey("app.id"), primary_key=True) + role = db.Column(String(length=64)) + + def __repr__(self): + return f"{self.role} for {self.user_id} on {self.app_id}" diff --git a/areas/cliapp/__init__.py b/areas/cliapp/__init__.py deleted file mode 100644 index 50400fa..0000000 --- a/areas/cliapp/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ - -from .cli import * \ No newline at end of file diff --git a/cliapp/__init__.py b/cliapp/__init__.py new file mode 100644 index 0000000..0d38f21 --- /dev/null +++ b/cliapp/__init__.py @@ -0,0 +1,3 @@ +from flask import Blueprint + +cli = Blueprint("cli", __name__) diff --git a/cliapp/cliapp/__init__.py b/cliapp/cliapp/__init__.py new file mode 100644 index 0000000..a5bd848 --- /dev/null +++ b/cliapp/cliapp/__init__.py @@ -0,0 +1 @@ +from .cli import * diff --git a/areas/cliapp/cli.py b/cliapp/cliapp/cli.py similarity index 85% rename from areas/cliapp/cli.py rename to cliapp/cliapp/cli.py index 32d65e3..b3f1acb 100644 --- a/areas/cliapp/cli.py +++ b/cliapp/cliapp/cli.py @@ -1,4 +1,3 @@ - """Flask application which provides the interface of a login panel. The application interacts with different backend, like the Kratos backend for users, Hydra for OIDC sessions and MariaDB for application and role specifications. @@ -6,44 +5,17 @@ The application provides also several command line options to interact with the user entries in the database(s)""" -# Basic system imports -import logging -import os -import urllib.parse -import urllib.request - import click - -# Hydra, OIDC Identity Provider import hydra_client - -# Kratos, Identity manager import ory_kratos_client -#from exceptions import BackendError - -# Flask -from flask import Flask, abort, redirect, render_template, request +from flask import current_app from flask.cli import AppGroup from ory_kratos_client.api import v0alpha2_api as kratos_api -from areas import cli from config import * -from flask import current_app - -from helpers import ( - BadRequest, - KratosError, - HydraError, - bad_request_error, - validation_error, - kratos_error, - global_error, - hydra_error, - KratosUser, - App, - AppRole -) - +from helpers import KratosUser +from cliapp import cli +from areas.apps import AppRole, App from database import db # APIs @@ -53,26 +25,25 @@ HYDRA = hydra_client.HydraAdmin(HYDRA_ADMIN_URL) # Kratos has an admin and public end-point. We create an API for them # both. The kratos implementation has bugs, which forces us to set # the discard_unknown_keys to True. -tmp = ory_kratos_client.Configuration(host=KRATOS_ADMIN_URL, - discard_unknown_keys= True) +tmp = ory_kratos_client.Configuration(host=KRATOS_ADMIN_URL, discard_unknown_keys=True) KRATOS_ADMIN = kratos_api.V0alpha2Api(ory_kratos_client.ApiClient(tmp)) -tmp = ory_kratos_client.Configuration(host=KRATOS_PUBLIC_URL, - discard_unknown_keys = True) +tmp = ory_kratos_client.Configuration(host=KRATOS_PUBLIC_URL, discard_unknown_keys=True) KRATOS_PUBLIC = kratos_api.V0alpha2Api(ory_kratos_client.ApiClient(tmp)) ############################################################################## # CLI INTERFACE # ############################################################################## # Define Flask CLI command groups and commands -user_cli = AppGroup('user') -app_cli = AppGroup('app') +user_cli = AppGroup("user") +app_cli = AppGroup("app") ## CLI APP COMMANDS -@app_cli.command('create') -@click.argument('slug') -@click.argument('name') + +@app_cli.command("create") +@click.argument("slug") +@click.argument("name") def create_app(slug, name): """Adds an app into the database :param slug: str short name of the app @@ -88,8 +59,7 @@ def create_app(slug, name): db.session.commit() - -@app_cli.command('list') +@app_cli.command("list") def list_app(): """List all apps found in the database""" current_app.logger.info("Listing configured apps") @@ -99,8 +69,10 @@ def list_app(): print(f"App name: {obj.name} \t Slug: {obj.slug}") -@app_cli.command('delete',) -@click.argument('slug') +@app_cli.command( + "delete", +) +@click.argument("slug") def delete_app(slug): """Removes app from database :param slug: str Slug of app to remove @@ -112,7 +84,6 @@ def delete_app(slug): current_app.logger.info("Not found") return - # Deleting will (probably) fail if there are still roles attached. This is a # PoC implementation only. Actually management of apps and roles will be # done by the backend application @@ -190,10 +161,11 @@ def show_user(email): print(f"Created: {user.created_at}") print(f"State: {user.state}") -@user_cli.command('update') -@click.argument('email') -@click.argument('field') -@click.argument('value') + +@user_cli.command("update") +@click.argument("email") +@click.argument("field") +@click.argument("value") def update_user(email, field, value): """Update an user object. It can modify email and name currently :param email: Email address of user to update @@ -206,9 +178,9 @@ def update_user(email, field, value): current_app.logger.error(f"User with email {email} not found.") return - if field == 'name': + if field == "name": user.name = value - elif field == 'email': + elif field == "email": user.email = value else: current_app.logger.error(f"Field not found: {field}") @@ -216,8 +188,8 @@ def update_user(email, field, value): user.save() -@user_cli.command('delete') -@click.argument('email') +@user_cli.command("delete") +@click.argument("email") def delete_user(email): """Delete an user from the database :param email: Email address of user to delete @@ -230,9 +202,8 @@ def delete_user(email): user.delete() - -@user_cli.command('create') -@click.argument('email') +@user_cli.command("create") +@click.argument("email") def create_user(email): """Create a user in the kratos database. The argument must be an unique email address @@ -250,9 +221,10 @@ def create_user(email): user.email = email user.save() -@user_cli.command('setpassword') -@click.argument('email') -@click.argument('password') + +@user_cli.command("setpassword") +@click.argument("email") +@click.argument("password") def setpassword_user(email, password): """Set a password for an account :param email: email address of account to set a password for @@ -277,7 +249,6 @@ def setpassword_user(email, password): current_app.logger.error(f"User with email '{email}' not found") return False - # Get a recovery URL url = kratos_user.get_recovery_link() @@ -296,8 +267,7 @@ def setpassword_user(email, password): return result - -@user_cli.command('list') +@user_cli.command("list") def list_user(): """Show a list of users in the database""" current_app.logger.info("Listing users") @@ -307,8 +277,8 @@ def list_user(): print(obj) -@user_cli.command('recover') -@click.argument('email') +@user_cli.command("recover") +@click.argument("email") def recover_user(email): """Get recovery link for a user, to manual update the user/use :param email: Email address of the user @@ -324,16 +294,8 @@ def recover_user(email): url = kratos_user.get_recovery_link() print(url) - except BackendError as error: + except Exception as error: current_app.logger.error(f"Error while getting reset link: {error}") - - cli.cli.add_command(user_cli) - - - - - - diff --git a/config.py b/config.py index e976f35..efab954 100644 --- a/config.py +++ b/config.py @@ -6,12 +6,12 @@ HYDRA_CLIENT_SECRET = os.environ.get("HYDRA_CLIENT_SECRET") HYDRA_AUTHORIZATION_BASE_URL = os.environ.get("HYDRA_AUTHORIZATION_BASE_URL") TOKEN_URL = os.environ.get("TOKEN_URL") -LOGIN_PANEL_URL = os.environ.get('LOGIN_PANEL_URL') +LOGIN_PANEL_URL = os.environ.get("LOGIN_PANEL_URL") HYDRA_PUBLIC_URL = os.environ.get("HYDRA_PUBLIC_URL") -HYDRA_ADMIN_URL = os.environ.get('HYDRA_ADMIN_URL') -KRATOS_ADMIN_URL = os.environ.get('KRATOS_ADMIN_URL') -KRATOS_PUBLIC_URL = str(os.environ.get('KRATOS_PUBLIC_URL')) + "/" +HYDRA_ADMIN_URL = os.environ.get("HYDRA_ADMIN_URL") +KRATOS_ADMIN_URL = os.environ.get("KRATOS_ADMIN_URL") +KRATOS_PUBLIC_URL = str(os.environ.get("KRATOS_PUBLIC_URL")) + "/" -SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') +SQLALCHEMY_DATABASE_URI = os.environ.get("DATABASE_URL") SQLALCHEMY_TRACK_MODIFICATIONS = False diff --git a/helpers/__init__.py b/helpers/__init__.py index 37e81cc..9302e8e 100644 --- a/helpers/__init__.py +++ b/helpers/__init__.py @@ -1,5 +1,4 @@ from .kratos_api import * from .error_handler import * from .hydra_oauth import * -from .kratos import * -from .models import * +from .kratos_user import * diff --git a/helpers/kratos.py b/helpers/kratos_user.py similarity index 100% rename from helpers/kratos.py rename to helpers/kratos_user.py diff --git a/helpers/models.py b/helpers/models.py deleted file mode 100644 index 9bd0d9e..0000000 --- a/helpers/models.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Implement different models used by Stackspin panel -""" - - -from flask import current_app -from flask_sqlalchemy import SQLAlchemy - -# pylint: disable=cyclic-import -# This is based on the documentation of Flask Alchemy -#from app import db - -# We need this import at some point to hook up roles and users -# from sqlalchemy.orm import relationship -from sqlalchemy import ForeignKey, Integer, String - -from database import db - -# Pylint complains about too-few-public-methods. Methods will be added once -# this is implemented. -# pylint: disable=too-few-public-methods -class App(db.Model): - """ - The App object, interact with the App database object. Data is stored in - the local database. - """ - - - id = db.Column(Integer, primary_key=True) - name = db.Column(String(length=64)) - slug = db.Column(String(length=64), unique=True) - - def __repr__(self): - return f"{self.id} <{self.name}>" - -# Pylint complains about too-few-public-methods. Methods will be added once -# this is implemented. -# pylint: disable=too-few-public-methods -class AppRole(db.Model): - """ - The AppRole object, stores the roles Users have on Apps - """ - - # pylint: disable=no-member - user_id = db.Column(String(length=64), primary_key=True) - # pylint: disable=no-member - app_id = db.Column(Integer, ForeignKey('app.id'), - primary_key=True) - - # pylint: disable=no-member - role = db.Column(String(length=64)) - - def __repr__(self): - return f"{self.role} for {self.user_id} on {self.app_id}" diff --git a/web/__init__.py b/web/__init__.py new file mode 100644 index 0000000..2a2e389 --- /dev/null +++ b/web/__init__.py @@ -0,0 +1,10 @@ +import os +from flask import Blueprint + +web = Blueprint( + "web", + __name__, + url_prefix="/web", + static_folder="static", + template_folder="templates", +) diff --git a/areas/login/__init__.py b/web/login/__init__.py similarity index 100% rename from areas/login/__init__.py rename to web/login/__init__.py diff --git a/areas/login/login.py b/web/login/login.py similarity index 76% rename from areas/login/login.py rename to web/login/login.py index 7912f06..30df69b 100644 --- a/areas/login/login.py +++ b/web/login/login.py @@ -1,54 +1,26 @@ - """Flask application which provides the interface of a login panel. The application interacts with different backend, like the Kratos backend for users, Hydra for OIDC sessions and MariaDB for application and role specifications. The application provides also several command line options to interact with the user entries in the database(s)""" - -# Basic system imports -import logging -import os import urllib.parse import urllib.request - -# Hydra, OIDC Identity Provider import hydra_client - -# Kratos, Identity manager import ory_kratos_client - -# Flask -from flask import Flask, abort, redirect, render_template, request -from flask_migrate import Migrate -from flask_sqlalchemy import SQLAlchemy -#from kratos import KratosUser -from ory_kratos_client.api import v0alpha2_api as kratos_api - -# Import modules for external APIs - -from areas import web -from config import * -from flask import current_app - -from helpers import ( - BadRequest, - KratosError, - HydraError, - bad_request_error, - validation_error, - kratos_error, - global_error, - hydra_error, - KratosUser, - App, - AppRole -) - import ast -# This is a circular import and should be solved differently -#from app import db +from ory_kratos_client.api import v0alpha2_api as kratos_api +from flask import abort, redirect, render_template, request, current_app + from database import db +from helpers import KratosUser +from config import * +from web import web +from areas.apps import AppRole, App + + +# This is a circular import and should be solved differently +# from app import db # APIs # Create HYDRA & KRATOS API interfaces @@ -57,19 +29,18 @@ HYDRA = hydra_client.HydraAdmin(HYDRA_ADMIN_URL) # Kratos has an admin and public end-point. We create an API for them # both. The kratos implementation has bugs, which forces us to set # the discard_unknown_keys to True. -tmp = ory_kratos_client.Configuration(host=KRATOS_ADMIN_URL, - discard_unknown_keys= True) +tmp = ory_kratos_client.Configuration(host=KRATOS_ADMIN_URL, discard_unknown_keys=True) KRATOS_ADMIN = kratos_api.V0alpha2Api(ory_kratos_client.ApiClient(tmp)) -tmp = ory_kratos_client.Configuration(host=KRATOS_PUBLIC_URL, - discard_unknown_keys = True) +tmp = ory_kratos_client.Configuration(host=KRATOS_PUBLIC_URL, discard_unknown_keys=True) KRATOS_PUBLIC = kratos_api.V0alpha2Api(ory_kratos_client.ApiClient(tmp)) ############################################################################## # WEB ROUTES # ############################################################################## -@web.route('/recovery', methods=['GET', 'POST']) + +@web.route("/recovery", methods=["GET", "POST"]) def recovery(): """Start recovery flow If no active flow, redirect to kratos to create a flow, otherwise render the @@ -82,13 +53,10 @@ def recovery(): if not flow: return redirect(KRATOS_PUBLIC_URL + "self-service/recovery/browser") - return render_template( - 'recover.html', - api_url = KRATOS_PUBLIC_URL - ) + return render_template("recover.html", api_url=KRATOS_PUBLIC_URL) -@web.route('/settings', methods=['GET', 'POST']) +@web.route("/settings", methods=["GET", "POST"]) def settings(): """Start settings flow If no active flow, redirect to kratos to create a flow, otherwise render the @@ -101,13 +69,10 @@ def settings(): if not flow: return redirect(KRATOS_PUBLIC_URL + "self-service/settings/browser") - return render_template( - 'settings.html', - api_url = KRATOS_PUBLIC_URL - ) + return render_template("settings.html", api_url=KRATOS_PUBLIC_URL) -@web.route('/login', methods=['GET', 'POST']) +@web.route("/login", methods=["GET", "POST"]) def login(): """Start login flow If already logged in, shows the loggedin template. Otherwise creates a login @@ -121,10 +86,7 @@ def login(): identity = get_auth() if identity: - return render_template( - 'loggedin.html', - api_url = KRATOS_PUBLIC_URL, - id = id) + return render_template("loggedin.html", api_url=KRATOS_PUBLIC_URL, id=id) flow = request.args.get("flow") @@ -132,13 +94,10 @@ def login(): if not flow: return redirect(KRATOS_PUBLIC_URL + "self-service/login/browser") - return render_template( - 'login.html', - api_url = KRATOS_PUBLIC_URL - ) + return render_template("login.html", api_url=KRATOS_PUBLIC_URL) -@web.route('/auth', methods=['GET', 'POST']) +@web.route("/auth", methods=["GET", "POST"]) def auth(): """Authorize an user for an application If an application authenticated against the IdP (Idenitity Provider), if @@ -156,20 +115,18 @@ def auth(): # Retrieve the challenge id from the request. Depending on the method it is # saved in the form (POST) or in a GET variable. If this variable is not set # we can not continue. - if request.method == 'GET': + if request.method == "GET": challenge = request.args.get("login_challenge") - if request.method == 'POST': + if request.method == "POST": challenge = request.args.post("login_challenge") if not challenge: current_app.logger.error("No challenge given. Error in request") abort(400, description="Challenge required when requesting authorization") - # Check if we are logged in: identity = get_auth() - # If the user is not logged in yet, we redirect to the login page # but before we do that, we set the "flow_state" cookie to auth. # so the UI knows it has to redirect after a successful login. @@ -183,35 +140,38 @@ def auth(): current_app.logger.info("auth_url: " + url) response = redirect(LOGIN_PANEL_URL + "/login") - response.set_cookie('flow_state', 'auth') - response.set_cookie('auth_url', url) + response.set_cookie("flow_state", "auth") + response.set_cookie("auth_url", url) return response - - current_app.logger.info("User is logged in. We can authorize the user") try: login_request = HYDRA.login_request(challenge) except hydra_client.exceptions.NotFound: - current_app.logger.error(f"Not Found. Login request not found. challenge={challenge}") + current_app.logger.error( + f"Not Found. Login request not found. challenge={challenge}" + ) abort(404, description="Login request not found. Please try again.") except hydra_client.exceptions.HTTPError: - current_app.logger.error(f"Conflict. Login request has been used already. challenge={challenge}") + current_app.logger.error( + f"Conflict. Login request has been used already. challenge={challenge}" + ) abort(503, description="Login request already used. Please try again.") # Authorize the user # False positive: pylint: disable=no-member redirect_to = login_request.accept( - identity.id, - remember=True, - # Remember session for 7d - remember_for=60*60*24*7) + identity.id, + remember=True, + # Remember session for 7d + remember_for=60 * 60 * 24 * 7, + ) return redirect(redirect_to) -@web.route('/consent', methods=['GET', 'POST']) +@web.route("/consent", methods=["GET", "POST"]) def consent(): """Get consent For now, it just allows every user. Eventually this function should check @@ -223,7 +183,9 @@ def consent(): challenge = request.args.get("consent_challenge") if not challenge: - abort(403, description="Consent request required. Do not call this page directly") + abort( + 403, description="Consent request required. Do not call this page directly" + ) try: consent_request = HYDRA.consent_request(challenge) except hydra_client.exceptions.NotFound: @@ -242,14 +204,16 @@ def consent(): if isinstance(consent_client, str): consent_client = ast.literal_eval(consent_client) - app_id = consent_client.get('client_id') + app_id = consent_client.get("client_id") # False positive: pylint: disable=no-member kratos_id = consent_request.subject current_app.logger.error(f"Info: Found kratos_id {kratos_id}") current_app.logger.error(f"Info: Found app_id {app_id}") except Exception as error: - current_app.logger.error(f"Error: Unable to extract information from consent request") + current_app.logger.error( + f"Error: Unable to extract information from consent request" + ) current_app.logger.error(f"Error: {error}") current_app.logger.error(f"Client: {consent_request.client}") current_app.logger.error(f"Subject: {consent_request.subject}") @@ -288,15 +252,16 @@ def consent(): current_app.logger.info(f"{kratos_id} was granted access to {app_id}") # False positive: pylint: disable=no-member - return redirect(consent_request.accept( - grant_scope=consent_request.requested_scope, - grant_access_token_audience=consent_request.requested_access_token_audience, - session=claims, - )) + return redirect( + consent_request.accept( + grant_scope=consent_request.requested_scope, + grant_access_token_audience=consent_request.requested_access_token_audience, + session=claims, + ) + ) - -@web.route('/status', methods=['GET', 'POST']) +@web.route("/status", methods=["GET", "POST"]) def status(): """Get status of current session Show if there is an user is logged in. If not shows: not-auth @@ -309,7 +274,6 @@ def status(): return "not-auth" - def get_auth(): """Checks if user is logged in Queries the cookies. If an authentication cookie is found, it @@ -319,7 +283,7 @@ def get_auth(): """ try: - cookie = request.cookies.get('ory_kratos_session') + cookie = request.cookies.get("ory_kratos_session") cookie = "ory_kratos_session=" + cookie except TypeError: current_app.logger.info("User not logged in or cookie corrupted") @@ -327,15 +291,14 @@ def get_auth(): # Given a cookie, check if it is valid and get the profile try: - api_response = KRATOS_PUBLIC.to_session( - cookie=cookie) + api_response = KRATOS_PUBLIC.to_session(cookie=cookie) # Get all traits from ID return api_response.identity except ory_kratos_client.ApiException as error: - current_app.logger.error(f"Exception when calling V0alpha2Api->to_session(): {error}\n") + current_app.logger.error( + f"Exception when calling V0alpha2Api->to_session(): {error}\n" + ) return False - - diff --git a/static/.gitkeep b/web/static/.gitkeep similarity index 100% rename from static/.gitkeep rename to web/static/.gitkeep diff --git a/static/base.js b/web/static/base.js similarity index 100% rename from static/base.js rename to web/static/base.js diff --git a/static/css/bootstrap-grid.css b/web/static/css/bootstrap-grid.css similarity index 100% rename from static/css/bootstrap-grid.css rename to web/static/css/bootstrap-grid.css diff --git a/static/css/bootstrap-grid.css.map b/web/static/css/bootstrap-grid.css.map similarity index 100% rename from static/css/bootstrap-grid.css.map rename to web/static/css/bootstrap-grid.css.map diff --git a/static/css/bootstrap-grid.min.css b/web/static/css/bootstrap-grid.min.css similarity index 100% rename from static/css/bootstrap-grid.min.css rename to web/static/css/bootstrap-grid.min.css diff --git a/static/css/bootstrap-grid.min.css.map b/web/static/css/bootstrap-grid.min.css.map similarity index 100% rename from static/css/bootstrap-grid.min.css.map rename to web/static/css/bootstrap-grid.min.css.map diff --git a/static/css/bootstrap-reboot.css b/web/static/css/bootstrap-reboot.css similarity index 100% rename from static/css/bootstrap-reboot.css rename to web/static/css/bootstrap-reboot.css diff --git a/static/css/bootstrap-reboot.css.map b/web/static/css/bootstrap-reboot.css.map similarity index 100% rename from static/css/bootstrap-reboot.css.map rename to web/static/css/bootstrap-reboot.css.map diff --git a/static/css/bootstrap-reboot.min.css b/web/static/css/bootstrap-reboot.min.css similarity index 100% rename from static/css/bootstrap-reboot.min.css rename to web/static/css/bootstrap-reboot.min.css diff --git a/static/css/bootstrap-reboot.min.css.map b/web/static/css/bootstrap-reboot.min.css.map similarity index 100% rename from static/css/bootstrap-reboot.min.css.map rename to web/static/css/bootstrap-reboot.min.css.map diff --git a/static/css/bootstrap.css b/web/static/css/bootstrap.css similarity index 100% rename from static/css/bootstrap.css rename to web/static/css/bootstrap.css diff --git a/static/css/bootstrap.css.map b/web/static/css/bootstrap.css.map similarity index 100% rename from static/css/bootstrap.css.map rename to web/static/css/bootstrap.css.map diff --git a/static/css/bootstrap.min.css b/web/static/css/bootstrap.min.css similarity index 100% rename from static/css/bootstrap.min.css rename to web/static/css/bootstrap.min.css diff --git a/static/css/bootstrap.min.css.map b/web/static/css/bootstrap.min.css.map similarity index 100% rename from static/css/bootstrap.min.css.map rename to web/static/css/bootstrap.min.css.map diff --git a/static/js/bootstrap.bundle.js b/web/static/js/bootstrap.bundle.js similarity index 100% rename from static/js/bootstrap.bundle.js rename to web/static/js/bootstrap.bundle.js diff --git a/static/js/bootstrap.bundle.js.map b/web/static/js/bootstrap.bundle.js.map similarity index 100% rename from static/js/bootstrap.bundle.js.map rename to web/static/js/bootstrap.bundle.js.map diff --git a/static/js/bootstrap.bundle.min.js b/web/static/js/bootstrap.bundle.min.js similarity index 100% rename from static/js/bootstrap.bundle.min.js rename to web/static/js/bootstrap.bundle.min.js diff --git a/static/js/bootstrap.bundle.min.js.map b/web/static/js/bootstrap.bundle.min.js.map similarity index 100% rename from static/js/bootstrap.bundle.min.js.map rename to web/static/js/bootstrap.bundle.min.js.map diff --git a/static/js/bootstrap.js b/web/static/js/bootstrap.js similarity index 100% rename from static/js/bootstrap.js rename to web/static/js/bootstrap.js diff --git a/static/js/bootstrap.js.map b/web/static/js/bootstrap.js.map similarity index 100% rename from static/js/bootstrap.js.map rename to web/static/js/bootstrap.js.map diff --git a/static/js/bootstrap.min.js b/web/static/js/bootstrap.min.js similarity index 100% rename from static/js/bootstrap.min.js rename to web/static/js/bootstrap.min.js diff --git a/static/js/bootstrap.min.js.map b/web/static/js/bootstrap.min.js.map similarity index 100% rename from static/js/bootstrap.min.js.map rename to web/static/js/bootstrap.min.js.map diff --git a/static/js/jquery-3.6.0.min.js b/web/static/js/jquery-3.6.0.min.js similarity index 100% rename from static/js/jquery-3.6.0.min.js rename to web/static/js/jquery-3.6.0.min.js diff --git a/static/js/js.cookie.min.js b/web/static/js/js.cookie.min.js similarity index 100% rename from static/js/js.cookie.min.js rename to web/static/js/js.cookie.min.js diff --git a/static/logo.svg b/web/static/logo.svg similarity index 100% rename from static/logo.svg rename to web/static/logo.svg diff --git a/static/style.css b/web/static/style.css similarity index 100% rename from static/style.css rename to web/static/style.css diff --git a/templates/base.html b/web/templates/base.html similarity index 100% rename from templates/base.html rename to web/templates/base.html diff --git a/templates/loggedin.html b/web/templates/loggedin.html similarity index 100% rename from templates/loggedin.html rename to web/templates/loggedin.html diff --git a/templates/login.html b/web/templates/login.html similarity index 100% rename from templates/login.html rename to web/templates/login.html diff --git a/templates/recover.html b/web/templates/recover.html similarity index 100% rename from templates/recover.html rename to web/templates/recover.html diff --git a/templates/settings.html b/web/templates/settings.html similarity index 100% rename from templates/settings.html rename to web/templates/settings.html