diff --git a/config.example.py b/config.example.py index e539040e..956ba963 100644 --- a/config.example.py +++ b/config.example.py @@ -9,6 +9,12 @@ class Config(): TESTING = False # SSO auth enabled SSO_AUTH = False + # Authentication is done outside the app, use HTTP header to get the user uuid. + # If SSO_AUTH is set to True, this option is ignored and SSO auth is used. + HEADER_AUTH = True + # Name of HTTP header containing the UUID of authenticated user. + # Only used when HEADER_AUTH is set to True + AUTH_HEADER_NAME = 'X-Authenticated-User' # SSO LOGOUT LOGOUT_URL = "https://flowspec.example.com/Shibboleth.sso/Logout" # SQL Alchemy config diff --git a/flowapp/__init__.py b/flowapp/__init__.py index a29297a7..83433e06 100644 --- a/flowapp/__init__.py +++ b/flowapp/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import babel -from flask import Flask, redirect, render_template, session, url_for +from flask import Flask, redirect, render_template, session, url_for, request from flask_sso import SSO from flask_sqlalchemy import SQLAlchemy from flask_wtf.csrf import CSRFProtect @@ -72,21 +72,9 @@ def login(user_info): else: user = db.session.query(models.User).filter_by(uuid=uuid).first() try: - session["user_uuid"] = user.uuid - session["user_email"] = user.uuid - session["user_name"] = user.name - session["user_id"] = user.id - session["user_roles"] = [role.name for role in user.role.all()] - session["user_orgs"] = ", ".join( - org.name for org in user.organization.all() - ) - session["user_role_ids"] = [role.id for role in user.role.all()] - session["user_org_ids"] = [org.id for org in user.organization.all()] - roles = [i > 1 for i in session["user_role_ids"]] - session["can_edit"] = True if all(roles) and roles else [] + _register_user_to_session(uuid) except AttributeError: - return redirect("/") - + pass return redirect("/") @app.route("/logout") @@ -96,6 +84,19 @@ def logout(): session.clear() return redirect(app.config.get("LOGOUT_URL")) + @app.route("/ext-login") + def ext_login(): + header_name = app.config.get("AUTH_HEADER_NAME", 'X-Authenticated-User') + if header_name not in request.headers: + return render_template("errors/401.j2") + uuid = request.headers.get(header_name) + if uuid: + try: + _register_user_to_session(uuid) + except AttributeError: + return render_template("errors/401.j2") + return redirect("/") + @app.route("/") @auth_required def index(): @@ -177,4 +178,20 @@ def format_datetime(value): return babel.dates.format_datetime(value, format) + def _register_user_to_session(uuid: str): + user = db.session.query(models.User).filter_by(uuid=uuid).first() + session["user_uuid"] = user.uuid + session["user_email"] = user.uuid + session["user_name"] = user.name + session["user_id"] = user.id + session["user_roles"] = [role.name for role in user.role.all()] + session["user_orgs"] = ", ".join( + org.name for org in user.organization.all() + ) + session["user_role_ids"] = [role.id for role in user.role.all()] + session["user_org_ids"] = [org.id for org in user.organization.all()] + roles = [i > 1 for i in session["user_role_ids"]] + session["can_edit"] = True if all(roles) and roles else [] + return app + diff --git a/flowapp/auth.py b/flowapp/auth.py index b4925d99..c4d942ff 100644 --- a/flowapp/auth.py +++ b/flowapp/auth.py @@ -14,7 +14,10 @@ def auth_required(f): @wraps(f) def decorated(*args, **kwargs): if not check_auth(get_user()): - return redirect("/login") + if current_app.config.get("SSO_AUTH"): + return redirect("/login") + elif current_app.config.get("HEADER_AUTH", False): + return redirect("/ext-login") return f(*args, **kwargs) return decorated @@ -99,6 +102,12 @@ def check_auth(uuid): if uuid: exist = db.session.query(User).filter_by(uuid=uuid).first() return exist + elif current_app.config.get("HEADER_AUTH", False): + # External auth (for example apache) + header_name = current_app.config.get("AUTH_HEADER_NAME", 'X-Authenticated-User') + if header_name not in request.headers or not session.get("user_uuid"): + return False + return db.session.query(User).filter_by(uuid=request.headers.get(header_name)) else: # Localhost login / no check session["user_email"] = current_app.config["LOCAL_USER_UUID"] diff --git a/flowapp/templates/errors/401.j2 b/flowapp/templates/errors/401.j2 new file mode 100755 index 00000000..6fea372d --- /dev/null +++ b/flowapp/templates/errors/401.j2 @@ -0,0 +1,7 @@ +{% extends 'layouts/default.j2' %} +{% block content %} +

Could not log you in.

+

401: Unauthorized

+

Please log out and try logging in again.

+

Log out

+{% endblock %} \ No newline at end of file