Reputation: 1808
I've been trying to authenticate with my Login Rest API instead of Other types. How to achieve this? Is REMOTE_USER authentication is the right way to do it? If so, can I get a sample code or documentation on this?
Read the docs here but couldn't understand much since I'm new to flask-appbuilder and python.
Upvotes: 4
Views: 6658
Reputation: 668
I will also add a full code based on the @rags answer if someone finds this useful :
from flask_appbuilder.security.manager import AUTH_REMOTE_USER
from superset.security import SupersetSecurityManager
from flask_appbuilder.security.views import AuthRemoteUserView
from trino.auth import CertificateAuthentication
from flask_login import login_user
from flask_appbuilder import expose
from flask import g, request
from flask import redirect
class RemoteUserMiddleware(object):
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
user = environ.pop('HTTP_USER', None)
environ['REMOTE_USER'] = user
return self.app(environ, start_response)
ADDITIONAL_MIDDLEWARE = [RemoteUserMiddleware, ]
class CustomRemoteUserView(AuthRemoteUserView):
login_template = ""
@expose("/login/")
def login(self):
username = request.environ.get("REMOTE_USER")
user_profile = request.environ.get('HTTP_USER_DETAILS')
profile_data = json.loads(user_profile)
if g.user is not None and g.user.is_authenticated:
return redirect(self.appbuilder.get_url_for_index)
security_manager = self.appbuilder.sm
user = security_manager.find_user(username=username)
if user is not None:
login_user(user)
return redirect(self.appbuilder.get_url_for_index)
app = self.appbuilder.get_app
user = security_manager.add_user(
username=username,
first_name=profile_data.get('firstName', 'UserName'),
last_name=profile_data.get('lastName', 'UserName'),
email=profile_data.get('email', username + '@notfound.com'),
role=security_manager.find_role(app.config['AUTH_ROLE_PUBLIC']),
)
login_user(user)
return redirect(self.appbuilder.get_url_for_index)
class CustomSecurityManager(SupersetSecurityManager):
authremoteuserview = CustomRemoteUserView
AUTH_TYPE = AUTH_REMOTE_USER
AUTH_USER_REGISTRATION = True
CUSTOM_SECURITY_MANAGER = CustomSecurityManager
AUTH_ROLE_PUBLIC = 'Gamma'
Upvotes: 0
Reputation: 534
For simple cases, add the below snippet to superset_config.py
as mentioned here:
class RemoteUserMiddleware(object):
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
user = environ.pop('HTTP_X_PROXY_REMOTE_USER', None)
environ['REMOTE_USER'] = user
return self.app(environ, start_response)
ADDITIONAL_MIDDLEWARE = [RemoteUserMiddleware, ]
AUTH_TYPE = AUTH_REMOTE_USER
AUTH_USER_REGISTRATION = True
and configure the reverse proxy to add the username (or email) to a header named X-PROXY-REMOTE-USER
(without the HTTP
). Enabling AUTH_USER_REGISTRATION
is important so that the account gets created automatically if it doesn't exist.
This will call the AuthRemoteUserView view, which in turn calls auth_user_remote_user to find and create a user if it doesn't exist.
If you want to customize this to add email, usernames, and possibly do rbac based on groups, you can extend the above view like so:
class CustomRemoteUserView(AuthRemoteUserView):
[...]
class CustomSecurityManager(SupersetSecurityManager):
authremoteuserview = CustomRemoteUserView
CUSTOM_SECURITY_MANAGER = CustomSecurityManager
Upvotes: 4
Reputation: 1061
Just for next ones arriving here.
Followed instructions here: https://superset.incubator.apache.org/installation.html#middleware
But not working: TOO MANY REDIRECTS.
Flask App-Builder code here: https://github.com/dpgaspar/Flask-AppBuilder/blob/167c13ec6dda6e7d8286e590233cd603a7d13928/flask_appbuilder/security/views.py#L728
Finally made my own custom remote login (Draft version below).
# Apache superset REMOTE_USER authentication
# https://superset.incubator.apache.org/installation.html#middleware
from flask_appbuilder.security.manager import AUTH_REMOTE_USER
# Define AUTH_TYPE
# AUTH_TYPE = AUTH_REMOTE_USER
# Allow users to auto register and be assigned to Remote role
# AUTH_USER_REGISTRATION = True
# AUTH_USER_REGISTRATION_ROLE = "Remote"
# For testing without a proxy just calling http://localhost:9000/superset/welcome?logme=user1
from flask import request, g
from flask_login import login_user, logout_user
import logging
# Middleware to extract user from header HTTP_X_PROXY_REMOTE_USER
# and place it at REMOTE_USER
class RemoteUserLogin(object):
def __init__(self, app):
self.app = app
def log_user(self, environ):
from superset import security_manager as sm
username = self.get_username(environ)
logging.info("REMOTE_USER Checking logged user")
if hasattr(g, "user") and \
hasattr(g.user, "username"):
if g.user.username == username:
logging.info("REMOTE_USER user already logged")
return g.user
else:
logout_user()
user = sm.find_user(username=username)
logging.info("REMOTE_USER Look up user: %s", user)
if user:
logging.info("REMOTE_USER Login_user: %s", user)
login_user(user)
return user
def get_username(self, environ):
user = environ.pop('HTTP_X_PROXY_REMOTE_USER', None)
if not user and self.app.debug:
# Dev hack
user = environ.get("werkzeug.request").args.get("logme")
if user:
logging.error("Logging user from request. Remove me ASAP!!!: %s", user)
environ['REMOTE_USER'] = user
return user
def before_request(self):
user = self.log_user(request.environ)
if not user:
raise Exception("Invalid login or user not found")
from superset.app import SupersetAppInitializer
def app_init(app):
logging.info("Resgistering RemoteUserLogin")
app.before_request(RemoteUserLogin(app).before_request)
return SupersetAppInitializer(app)
APP_INITIALIZER = app_init
Upvotes: 3