I am trying to implement Superset using Keycloak for authentication. Following the post here: Using KeyCloak(OpenID Connect) with Apache SuperSet, the login part works fine.
I also have a timeout set on the session (security requirement) using the Superset Docs: https://superset.apache.org/docs/installation/configuring-superset#flask-app-configuration-hook
The part that doesn't work, when a user is logged out, they are not redirected to the login page. It's just a bunch of errors thrown on the screen, and the user can't see anything. Anyone have a hint as to how I get the user redirected to the login page?
Worth noting, the whole thing is behind an nginx reverse proxy.
Here's the full superset_config.py, in case it's helpful...
from flask_appbuilder.security.manager import AUTH_OID
from superset.security import SupersetSecurityManager
from flask_oidc import OpenIDConnect
from flask_appbuilder.security.views import AuthOIDView
from flask_login import login_user
from urllib.parse import quote
from flask_appbuilder.views import ModelView, SimpleFormView, expose
import logging
class AuthOIDCView(AuthOIDView):
@expose('/login/', methods=['GET', 'POST'])
def login(self, flag=True):
sm = self.appbuilder.sm
oidc = sm.oid
@self.appbuilder.sm.oid.require_login
def handle_login():
user = sm.auth_user_oid(oidc.user_getfield('email'))
if user is None:
info = oidc.user_getinfo(['preferred_username', 'given_name', 'family_name', 'email'])
user = sm.add_user(info.get('preferred_username'), info.get('given_name'), info.get('family_name'), info.get('email'), sm.find_role('Gamma'))
login_user(user, remember=False)
return redirect(self.appbuilder.get_url_for_index)
return handle_login()
@expose('/logout/', methods=['GET', 'POST'])
def logout(self):
oidc = self.appbuilder.sm.oid
oidc.logout()
super(AuthOIDCView, self).logout()
redirect_url = request.url_root.strip('/') + self.appbuilder.get_url_for_login
return redirect(oidc.client_secrets.get('issuer') + '/protocol/openid-connect/logout?redirect_uri=' + quote(redirect_url))
class OIDCSecurityManager(SupersetSecurityManager):
authoidview = AuthOIDCView
def __init__(self,appbuilder):
super(OIDCSecurityManager, self).__init__(appbuilder)
if self.auth_type == AUTH_OID:
self.oid = OpenIDConnect(self.appbuilder.get_app)
SQLALCHEMY_DATABASE_URI = 'a sting'
MENU_HIDE_USER_INFO = True
FEATURE_FLAGS = {
"ROW_LEVEL_SECURITY": True,
"DASHBOARD_RBAC": True,
}
ENABLE_PROXY_FIX = True
PROXY_FIX_CONFIG = {"x_for": 1, "x_proto": 0, "x_host": 1, "x_port": 0, "x_prefix": 0}
class ReverseProxied(object):
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
script_name = environ.get('HTTP_X_SCRIPT_NAME', '')
# print(environ)
if script_name:
environ['SCRIPT_NAME'] = script_name
path_info = environ['PATH_INFO']
if path_info.startswith(script_name):
environ['PATH_INFO'] = path_info[len(script_name):]
scheme = environ.get('HTTP_X_SCHEME', '')
print(scheme)
if scheme:
environ['wsgi.url_scheme'] = scheme
return self.app(environ, start_response)
ADDITIONAL_MIDDLEWARE = [ReverseProxied, ]
def role_mapper(role_list):
# not exposing our roles
# Auth Settings
AUTH_TYPE = AUTH_OID
OIDC_CLIENT_SECRETS = '/a/path' #real config contains correct path
OIDC_ID_TOKEN_COOKIE_SECURE = False
OIDC_REQUIRE_VERIFIED_EMAIL = False
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = 'Gamma'
CUSTOM_SECURITY_MANAGER = OIDCSecurityManager
# Webserver Setting
SUPERSET_WEBSERVER_PROTOCOL = "http"
SUPERSET_WEBSERVER_ADDRESS = "127.0.0.1"
SUPERSET_WEBSERVER_PORT = 8088
# Flask Application Builder Settings
SILENCE_FAB = False
FAB_ADD_SECURITY_VIEWS = True
FAB_ADD_SECURITY_PERMISSION_VIEW = True
FAB_ADD_SECURITY_VIEW_MENU_VIEW = True
FAB_ADD_SECURITY_PERMISSION_VIEWS_VIEW = True
# Session Timeout
from flask import session
from flask import Flask
from datetime import timedelta
def make_session_permanent():
session.permanent = True
# Set up max age of session to 1 minute for testing
PERMANENT_SESSION_LIFETIME = timedelta(minutes=1)
def FLASK_APP_MUTATOR(app: Flask) -> None:
app.before_request_funcs.setdefault(None, []).append(make_session_permanent)```