Refactor integrations of sso

This commit is contained in:
Luka Radenovic 2022-04-13 10:27:17 +02:00
parent ce5a7d05ac
commit f377b4ce45
46 changed files with 154 additions and 249 deletions

22
app.py
View file

@ -4,18 +4,17 @@ from flask_jwt_extended import JWTManager
from flask_migrate import Migrate from flask_migrate import Migrate
from jsonschema.exceptions import ValidationError from jsonschema.exceptions import ValidationError
from werkzeug.exceptions import BadRequest from werkzeug.exceptions import BadRequest
from flask_sqlalchemy import SQLAlchemy
# These imports are required # These imports are required
from areas import api_v1 from areas import api_v1
from areas import web from cliapp import cli
from areas import cli from web import web
from areas import users from areas import users
from areas import apps from areas import apps
from areas import auth from areas import auth
from areas import login from cliapp import cliapp
from areas import cliapp from web import login
from database import db from database import db
@ -28,26 +27,21 @@ from helpers import (
kratos_error, kratos_error,
global_error, global_error,
hydra_error, hydra_error,
KratosUser,
App,
AppRole
) )
from config import * from config import *
import logging import logging
app = Flask(__name__, static_url_path = '/web/static') app = Flask(__name__)
cors = CORS(app)
app.config["SECRET_KEY"] = SECRET_KEY app.config["SECRET_KEY"] = SECRET_KEY
app.config["SQLALCHEMY_DATABASE_URI"] = SQLALCHEMY_DATABASE_URI app.config["SQLALCHEMY_DATABASE_URI"] = SQLALCHEMY_DATABASE_URI
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = SQLALCHEMY_TRACK_MODIFICATIONS
## from database import db cors = CORS(app)
#db = SQLAlchemy() Migrate(app, db)
db.init_app(app) db.init_app(app)
Migrate(app, db)
app.logger.setLevel(logging.INFO) app.logger.setLevel(logging.INFO)

View file

@ -1,8 +1,7 @@
from flask import Blueprint from flask import Blueprint
api_v1 = Blueprint("api_v1", __name__, url_prefix="/api/v1") 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("/")
@api_v1.route("/health") @api_v1.route("/health")

View file

@ -1 +1,2 @@
from .apps import * from .apps import *
from .models import *

29
areas/apps/models.py Normal file
View file

@ -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}"

View file

@ -1,2 +0,0 @@
from .cli import *

3
cliapp/__init__.py Normal file
View file

@ -0,0 +1,3 @@
from flask import Blueprint
cli = Blueprint("cli", __name__)

View file

@ -0,0 +1 @@
from .cli import *

View file

@ -1,4 +1,3 @@
"""Flask application which provides the interface of a login panel. The """Flask application which provides the interface of a login panel. The
application interacts with different backend, like the Kratos backend for users, application interacts with different backend, like the Kratos backend for users,
Hydra for OIDC sessions and MariaDB for application and role specifications. 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)""" the user entries in the database(s)"""
# Basic system imports
import logging
import os
import urllib.parse
import urllib.request
import click import click
# Hydra, OIDC Identity Provider
import hydra_client import hydra_client
# Kratos, Identity manager
import ory_kratos_client import ory_kratos_client
#from exceptions import BackendError from flask import current_app
# Flask
from flask import Flask, abort, redirect, render_template, request
from flask.cli import AppGroup from flask.cli import AppGroup
from ory_kratos_client.api import v0alpha2_api as kratos_api from ory_kratos_client.api import v0alpha2_api as kratos_api
from areas import cli
from config import * from config import *
from flask import current_app from helpers import KratosUser
from cliapp import cli
from helpers import ( from areas.apps import AppRole, App
BadRequest,
KratosError,
HydraError,
bad_request_error,
validation_error,
kratos_error,
global_error,
hydra_error,
KratosUser,
App,
AppRole
)
from database import db from database import db
# APIs # 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 # 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 # both. The kratos implementation has bugs, which forces us to set
# the discard_unknown_keys to True. # the discard_unknown_keys to True.
tmp = ory_kratos_client.Configuration(host=KRATOS_ADMIN_URL, tmp = ory_kratos_client.Configuration(host=KRATOS_ADMIN_URL, discard_unknown_keys=True)
discard_unknown_keys= True)
KRATOS_ADMIN = kratos_api.V0alpha2Api(ory_kratos_client.ApiClient(tmp)) KRATOS_ADMIN = kratos_api.V0alpha2Api(ory_kratos_client.ApiClient(tmp))
tmp = ory_kratos_client.Configuration(host=KRATOS_PUBLIC_URL, tmp = ory_kratos_client.Configuration(host=KRATOS_PUBLIC_URL, discard_unknown_keys=True)
discard_unknown_keys = True)
KRATOS_PUBLIC = kratos_api.V0alpha2Api(ory_kratos_client.ApiClient(tmp)) KRATOS_PUBLIC = kratos_api.V0alpha2Api(ory_kratos_client.ApiClient(tmp))
############################################################################## ##############################################################################
# CLI INTERFACE # # CLI INTERFACE #
############################################################################## ##############################################################################
# Define Flask CLI command groups and commands # Define Flask CLI command groups and commands
user_cli = AppGroup('user') user_cli = AppGroup("user")
app_cli = AppGroup('app') app_cli = AppGroup("app")
## CLI APP COMMANDS ## CLI APP COMMANDS
@app_cli.command('create')
@click.argument('slug') @app_cli.command("create")
@click.argument('name') @click.argument("slug")
@click.argument("name")
def create_app(slug, name): def create_app(slug, name):
"""Adds an app into the database """Adds an app into the database
:param slug: str short name of the app :param slug: str short name of the app
@ -88,8 +59,7 @@ def create_app(slug, name):
db.session.commit() db.session.commit()
@app_cli.command("list")
@app_cli.command('list')
def list_app(): def list_app():
"""List all apps found in the database""" """List all apps found in the database"""
current_app.logger.info("Listing configured apps") current_app.logger.info("Listing configured apps")
@ -99,8 +69,10 @@ def list_app():
print(f"App name: {obj.name} \t Slug: {obj.slug}") print(f"App name: {obj.name} \t Slug: {obj.slug}")
@app_cli.command('delete',) @app_cli.command(
@click.argument('slug') "delete",
)
@click.argument("slug")
def delete_app(slug): def delete_app(slug):
"""Removes app from database """Removes app from database
:param slug: str Slug of app to remove :param slug: str Slug of app to remove
@ -112,7 +84,6 @@ def delete_app(slug):
current_app.logger.info("Not found") current_app.logger.info("Not found")
return return
# Deleting will (probably) fail if there are still roles attached. This is a # Deleting will (probably) fail if there are still roles attached. This is a
# PoC implementation only. Actually management of apps and roles will be # PoC implementation only. Actually management of apps and roles will be
# done by the backend application # done by the backend application
@ -190,10 +161,11 @@ def show_user(email):
print(f"Created: {user.created_at}") print(f"Created: {user.created_at}")
print(f"State: {user.state}") print(f"State: {user.state}")
@user_cli.command('update')
@click.argument('email') @user_cli.command("update")
@click.argument('field') @click.argument("email")
@click.argument('value') @click.argument("field")
@click.argument("value")
def update_user(email, field, value): def update_user(email, field, value):
"""Update an user object. It can modify email and name currently """Update an user object. It can modify email and name currently
:param email: Email address of user to update :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.") current_app.logger.error(f"User with email {email} not found.")
return return
if field == 'name': if field == "name":
user.name = value user.name = value
elif field == 'email': elif field == "email":
user.email = value user.email = value
else: else:
current_app.logger.error(f"Field not found: {field}") current_app.logger.error(f"Field not found: {field}")
@ -216,8 +188,8 @@ def update_user(email, field, value):
user.save() user.save()
@user_cli.command('delete') @user_cli.command("delete")
@click.argument('email') @click.argument("email")
def delete_user(email): def delete_user(email):
"""Delete an user from the database """Delete an user from the database
:param email: Email address of user to delete :param email: Email address of user to delete
@ -230,9 +202,8 @@ def delete_user(email):
user.delete() user.delete()
@user_cli.command("create")
@user_cli.command('create') @click.argument("email")
@click.argument('email')
def create_user(email): def create_user(email):
"""Create a user in the kratos database. The argument must be an unique """Create a user in the kratos database. The argument must be an unique
email address email address
@ -250,9 +221,10 @@ def create_user(email):
user.email = email user.email = email
user.save() user.save()
@user_cli.command('setpassword')
@click.argument('email') @user_cli.command("setpassword")
@click.argument('password') @click.argument("email")
@click.argument("password")
def setpassword_user(email, password): def setpassword_user(email, password):
"""Set a password for an account """Set a password for an account
:param email: email address of account to set a password for :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") current_app.logger.error(f"User with email '{email}' not found")
return False return False
# Get a recovery URL # Get a recovery URL
url = kratos_user.get_recovery_link() url = kratos_user.get_recovery_link()
@ -296,8 +267,7 @@ def setpassword_user(email, password):
return result return result
@user_cli.command("list")
@user_cli.command('list')
def list_user(): def list_user():
"""Show a list of users in the database""" """Show a list of users in the database"""
current_app.logger.info("Listing users") current_app.logger.info("Listing users")
@ -307,8 +277,8 @@ def list_user():
print(obj) print(obj)
@user_cli.command('recover') @user_cli.command("recover")
@click.argument('email') @click.argument("email")
def recover_user(email): def recover_user(email):
"""Get recovery link for a user, to manual update the user/use """Get recovery link for a user, to manual update the user/use
:param email: Email address of the user :param email: Email address of the user
@ -324,16 +294,8 @@ def recover_user(email):
url = kratos_user.get_recovery_link() url = kratos_user.get_recovery_link()
print(url) print(url)
except BackendError as error: except Exception as error:
current_app.logger.error(f"Error while getting reset link: {error}") current_app.logger.error(f"Error while getting reset link: {error}")
cli.cli.add_command(user_cli) cli.cli.add_command(user_cli)

View file

@ -6,12 +6,12 @@ HYDRA_CLIENT_SECRET = os.environ.get("HYDRA_CLIENT_SECRET")
HYDRA_AUTHORIZATION_BASE_URL = os.environ.get("HYDRA_AUTHORIZATION_BASE_URL") HYDRA_AUTHORIZATION_BASE_URL = os.environ.get("HYDRA_AUTHORIZATION_BASE_URL")
TOKEN_URL = os.environ.get("TOKEN_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_PUBLIC_URL = os.environ.get("HYDRA_PUBLIC_URL")
HYDRA_ADMIN_URL = os.environ.get('HYDRA_ADMIN_URL') HYDRA_ADMIN_URL = os.environ.get("HYDRA_ADMIN_URL")
KRATOS_ADMIN_URL = os.environ.get('KRATOS_ADMIN_URL') KRATOS_ADMIN_URL = os.environ.get("KRATOS_ADMIN_URL")
KRATOS_PUBLIC_URL = str(os.environ.get('KRATOS_PUBLIC_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 SQLALCHEMY_TRACK_MODIFICATIONS = False

View file

@ -1,5 +1,4 @@
from .kratos_api import * from .kratos_api import *
from .error_handler import * from .error_handler import *
from .hydra_oauth import * from .hydra_oauth import *
from .kratos import * from .kratos_user import *
from .models import *

View file

@ -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}"

10
web/__init__.py Normal file
View file

@ -0,0 +1,10 @@
import os
from flask import Blueprint
web = Blueprint(
"web",
__name__,
url_prefix="/web",
static_folder="static",
template_folder="templates",
)

View file

@ -1,54 +1,26 @@
"""Flask application which provides the interface of a login panel. The """Flask application which provides the interface of a login panel. The
application interacts with different backend, like the Kratos backend for users, application interacts with different backend, like the Kratos backend for users,
Hydra for OIDC sessions and MariaDB for application and role specifications. Hydra for OIDC sessions and MariaDB for application and role specifications.
The application provides also several command line options to interact with The application provides also several command line options to interact with
the user entries in the database(s)""" the user entries in the database(s)"""
# Basic system imports
import logging
import os
import urllib.parse import urllib.parse
import urllib.request import urllib.request
# Hydra, OIDC Identity Provider
import hydra_client import hydra_client
# Kratos, Identity manager
import ory_kratos_client 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 import ast
# This is a circular import and should be solved differently from ory_kratos_client.api import v0alpha2_api as kratos_api
#from app import db from flask import abort, redirect, render_template, request, current_app
from database import db 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 # APIs
# Create HYDRA & KRATOS API interfaces # 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 # 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 # both. The kratos implementation has bugs, which forces us to set
# the discard_unknown_keys to True. # the discard_unknown_keys to True.
tmp = ory_kratos_client.Configuration(host=KRATOS_ADMIN_URL, tmp = ory_kratos_client.Configuration(host=KRATOS_ADMIN_URL, discard_unknown_keys=True)
discard_unknown_keys= True)
KRATOS_ADMIN = kratos_api.V0alpha2Api(ory_kratos_client.ApiClient(tmp)) KRATOS_ADMIN = kratos_api.V0alpha2Api(ory_kratos_client.ApiClient(tmp))
tmp = ory_kratos_client.Configuration(host=KRATOS_PUBLIC_URL, tmp = ory_kratos_client.Configuration(host=KRATOS_PUBLIC_URL, discard_unknown_keys=True)
discard_unknown_keys = True)
KRATOS_PUBLIC = kratos_api.V0alpha2Api(ory_kratos_client.ApiClient(tmp)) KRATOS_PUBLIC = kratos_api.V0alpha2Api(ory_kratos_client.ApiClient(tmp))
############################################################################## ##############################################################################
# WEB ROUTES # # WEB ROUTES #
############################################################################## ##############################################################################
@web.route('/recovery', methods=['GET', 'POST'])
@web.route("/recovery", methods=["GET", "POST"])
def recovery(): def recovery():
"""Start recovery flow """Start recovery flow
If no active flow, redirect to kratos to create a flow, otherwise render the If no active flow, redirect to kratos to create a flow, otherwise render the
@ -82,13 +53,10 @@ def recovery():
if not flow: if not flow:
return redirect(KRATOS_PUBLIC_URL + "self-service/recovery/browser") return redirect(KRATOS_PUBLIC_URL + "self-service/recovery/browser")
return render_template( return render_template("recover.html", api_url=KRATOS_PUBLIC_URL)
'recover.html',
api_url = KRATOS_PUBLIC_URL
)
@web.route('/settings', methods=['GET', 'POST']) @web.route("/settings", methods=["GET", "POST"])
def settings(): def settings():
"""Start settings flow """Start settings flow
If no active flow, redirect to kratos to create a flow, otherwise render the If no active flow, redirect to kratos to create a flow, otherwise render the
@ -101,13 +69,10 @@ def settings():
if not flow: if not flow:
return redirect(KRATOS_PUBLIC_URL + "self-service/settings/browser") return redirect(KRATOS_PUBLIC_URL + "self-service/settings/browser")
return render_template( return render_template("settings.html", api_url=KRATOS_PUBLIC_URL)
'settings.html',
api_url = KRATOS_PUBLIC_URL
)
@web.route('/login', methods=['GET', 'POST']) @web.route("/login", methods=["GET", "POST"])
def login(): def login():
"""Start login flow """Start login flow
If already logged in, shows the loggedin template. Otherwise creates a login If already logged in, shows the loggedin template. Otherwise creates a login
@ -121,10 +86,7 @@ def login():
identity = get_auth() identity = get_auth()
if identity: if identity:
return render_template( return render_template("loggedin.html", api_url=KRATOS_PUBLIC_URL, id=id)
'loggedin.html',
api_url = KRATOS_PUBLIC_URL,
id = id)
flow = request.args.get("flow") flow = request.args.get("flow")
@ -132,13 +94,10 @@ def login():
if not flow: if not flow:
return redirect(KRATOS_PUBLIC_URL + "self-service/login/browser") return redirect(KRATOS_PUBLIC_URL + "self-service/login/browser")
return render_template( return render_template("login.html", api_url=KRATOS_PUBLIC_URL)
'login.html',
api_url = KRATOS_PUBLIC_URL
)
@web.route('/auth', methods=['GET', 'POST']) @web.route("/auth", methods=["GET", "POST"])
def auth(): def auth():
"""Authorize an user for an application """Authorize an user for an application
If an application authenticated against the IdP (Idenitity Provider), if 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 # 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 # saved in the form (POST) or in a GET variable. If this variable is not set
# we can not continue. # we can not continue.
if request.method == 'GET': if request.method == "GET":
challenge = request.args.get("login_challenge") challenge = request.args.get("login_challenge")
if request.method == 'POST': if request.method == "POST":
challenge = request.args.post("login_challenge") challenge = request.args.post("login_challenge")
if not challenge: if not challenge:
current_app.logger.error("No challenge given. Error in request") current_app.logger.error("No challenge given. Error in request")
abort(400, description="Challenge required when requesting authorization") abort(400, description="Challenge required when requesting authorization")
# Check if we are logged in: # Check if we are logged in:
identity = get_auth() identity = get_auth()
# If the user is not logged in yet, we redirect to the login page # 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. # 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. # 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) current_app.logger.info("auth_url: " + url)
response = redirect(LOGIN_PANEL_URL + "/login") response = redirect(LOGIN_PANEL_URL + "/login")
response.set_cookie('flow_state', 'auth') response.set_cookie("flow_state", "auth")
response.set_cookie('auth_url', url) response.set_cookie("auth_url", url)
return response return response
current_app.logger.info("User is logged in. We can authorize the user") current_app.logger.info("User is logged in. We can authorize the user")
try: try:
login_request = HYDRA.login_request(challenge) login_request = HYDRA.login_request(challenge)
except hydra_client.exceptions.NotFound: 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.") abort(404, description="Login request not found. Please try again.")
except hydra_client.exceptions.HTTPError: 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.") abort(503, description="Login request already used. Please try again.")
# Authorize the user # Authorize the user
# False positive: pylint: disable=no-member # False positive: pylint: disable=no-member
redirect_to = login_request.accept( redirect_to = login_request.accept(
identity.id, identity.id,
remember=True, remember=True,
# Remember session for 7d # Remember session for 7d
remember_for=60*60*24*7) remember_for=60 * 60 * 24 * 7,
)
return redirect(redirect_to) return redirect(redirect_to)
@web.route('/consent', methods=['GET', 'POST']) @web.route("/consent", methods=["GET", "POST"])
def consent(): def consent():
"""Get consent """Get consent
For now, it just allows every user. Eventually this function should check For now, it just allows every user. Eventually this function should check
@ -223,7 +183,9 @@ def consent():
challenge = request.args.get("consent_challenge") challenge = request.args.get("consent_challenge")
if not 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: try:
consent_request = HYDRA.consent_request(challenge) consent_request = HYDRA.consent_request(challenge)
except hydra_client.exceptions.NotFound: except hydra_client.exceptions.NotFound:
@ -242,14 +204,16 @@ def consent():
if isinstance(consent_client, str): if isinstance(consent_client, str):
consent_client = ast.literal_eval(consent_client) 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 # False positive: pylint: disable=no-member
kratos_id = consent_request.subject kratos_id = consent_request.subject
current_app.logger.error(f"Info: Found kratos_id {kratos_id}") current_app.logger.error(f"Info: Found kratos_id {kratos_id}")
current_app.logger.error(f"Info: Found app_id {app_id}") current_app.logger.error(f"Info: Found app_id {app_id}")
except Exception as error: 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"Error: {error}")
current_app.logger.error(f"Client: {consent_request.client}") current_app.logger.error(f"Client: {consent_request.client}")
current_app.logger.error(f"Subject: {consent_request.subject}") 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}") current_app.logger.info(f"{kratos_id} was granted access to {app_id}")
# False positive: pylint: disable=no-member # False positive: pylint: disable=no-member
return redirect(consent_request.accept( return redirect(
grant_scope=consent_request.requested_scope, consent_request.accept(
grant_access_token_audience=consent_request.requested_access_token_audience, grant_scope=consent_request.requested_scope,
session=claims, 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(): def status():
"""Get status of current session """Get status of current session
Show if there is an user is logged in. If not shows: not-auth Show if there is an user is logged in. If not shows: not-auth
@ -309,7 +274,6 @@ def status():
return "not-auth" return "not-auth"
def get_auth(): def get_auth():
"""Checks if user is logged in """Checks if user is logged in
Queries the cookies. If an authentication cookie is found, it Queries the cookies. If an authentication cookie is found, it
@ -319,7 +283,7 @@ def get_auth():
""" """
try: try:
cookie = request.cookies.get('ory_kratos_session') cookie = request.cookies.get("ory_kratos_session")
cookie = "ory_kratos_session=" + cookie cookie = "ory_kratos_session=" + cookie
except TypeError: except TypeError:
current_app.logger.info("User not logged in or cookie corrupted") 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 # Given a cookie, check if it is valid and get the profile
try: try:
api_response = KRATOS_PUBLIC.to_session( api_response = KRATOS_PUBLIC.to_session(cookie=cookie)
cookie=cookie)
# Get all traits from ID # Get all traits from ID
return api_response.identity return api_response.identity
except ory_kratos_client.ApiException as error: 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 return False

View file

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB