June 29, 2023

Enhancing Security and User Experience: Customizing Login in Apache Superset with Token

Source Article on Medium: https://medium.com/@mert1943992/enhancing-security-and-user-experience-customizing-login-in-apache-superset-with-token-204b95386b8a

What is Superset?

Apache Superset is an open-source business intelligence (BI) platform that allows users to easily explore and visualize data, build dashboards, and create interactive reports.

With Superset, users can connect to various data sources, such as relational databases, NoSQL databases, cloud storage solutions, and more, to analyze and visualize data. It supports various visualization types, including bar charts, line charts, scatter plots, histograms, maps, and more. Users can also create custom charts using Python or SQL.

Superset also includes data exploration, SQL query generation, and data slicing and dicing. It has a user-friendly interface that allows users to quickly drag and drop data to create interactive dashboards and reports.

Superset is highly customizable and can be extended through custom plugins and integrations. It also supports integration with popular authentication providers and supports role-based access control for data and dashboard sharing.

Customize Config

To customize the configuration of Apache Superset, you can modify its configuration files to tailor the behavior and appearance of the application. By adding the volume to run the command you can customize the config file. In the superset_config.py, the below definitions are added to override login methods.

# other configs
from custom_security import CustomSecurityManager
CUSTOM_SECURITY_MANAGER = CustomSecurityManager
# other configs

Example Project

To better understand, an example project is explained. For redirect assuming that the token is generated from another project. The token should write into a database. An example table can have columns like below.

The main project should insert a token before redirecting the user to the Apache superset. The consumed column should be false in the insertion to prevent second use.

Custom Security

Apache Superset supports integration with external authentication and authorization providers. Users can customize the authentication and authorization logic to meet their specific requirements. For creating a custom login custom_security.py file was created. In the example, the Oracle database is used.

from flask import redirect, g, flash, request
from flask_appbuilder.security.views import UserDBModelView, AuthDBView
from superset.security import SupersetSecurityManager
from flask_appbuilder.security.views import expose
from flask_appbuilder.security.manager import BaseSecurityManager
from flask_login import login_user, logout_user
from datetime import datetime
import cx_Oracle

class SupersetAuth:
    def __init__(self, id, token, username, consumed, creationDate, expirationDate, consumedDate, userId):
        self.id = id
        self.token = token
        self.username = username
        self.consumed = consumed
        self.creationDate = creationDate
        self.expirationDate = expirationDate
        self.consumedDate = consumedDate
        self.userId = userId


class CustomAuthDBView(AuthDBView):
    login_template = 'appbuilder/general/security/login_db.html'

    @expose('/login/', methods=['GET', 'POST'])
    def login(self):
        authsuccess = False
        usernameFromPath = ''
        token = ''
        redirect_url = self.appbuilder.get_url_for_index

        if request.args.get('redirect') is not None:
            redirect_url = request.args.get('redirect')
        if request.args.get('username') is not None:
            usernameFromPath = request.args.get('username')
            user = self.appbuilder.sm.find_user(username=usernameFromPath)
        if request.args.get('token') is not None:
            token = request.args.get('token')

        if usernameFromPath != '':
            try:
                connection = cx_Oracle.connect('username', 'password', 'host:port/schema', encoding="UTF-8")
                connection.autocommit = True
                cursor = connection.cursor()
                cursor.execute('select * from superset_auth where token=:tokenToDb', tokenToDb=token)
                fromDb = cursor.fetchone()
                if fromDb:
                    supersetAuth = SupersetAuth(*fromDb)
                    today = datetime.today()
                    if supersetAuth.consumed == 1:
                        flash('InvalidToken', 'warning')
                        return super().login()
                    if supersetAuth.expirationDate > today and supersetAuth.username == usernameFromPath:
                        statement = "update superset_auth set consumed=:consumed, consumed_time=:consumedTime where id=:id"
                        cursor.execute(statement, {'consumed': True, 'consumedTime': today, 'id': supersetAuth.id})
                        authsuccess = True
            except cx_Oracle.Error as error:
                print(error)
            finally:
                if connection:
                    cursor.close()
                    connection.close()

        if g.user is not None and g.user.is_authenticated and not authsuccess:
            return redirect(redirect_url)

        if authsuccess:
            login_user(user, remember=False)
            return redirect(redirect_url)
        else:
            flash('Auto Login Failed', 'warning')
            return super().login()


class CustomSecurityManager(SupersetSecurityManager):
    authdbview = CustomAuthDBView

    def __init__(self, appbuilder):
        super().__init__(appbuilder)

Installation of Superset

Assuming that custom_security.py and superset_config.py are located in /DATA/etc/superset in your machine.

docker run - detach -v DATA/etc/superset:/etc/superset –name superset -p 8088:8088 amancevice/superset

This command creates a Docker container named “superset” and maps the container’s port 8088 to the host machine’s port 8088, which is the default port used by Superset. You can use a different port number if needed.

To start superset enter the container and run the below commands on bash.

docker exec -it superset /bin/bash
superset fab create-admin --username admin --firstname admin --lastname admin --email [email protected] --password Admin1234!
superset db upgrade
superset load_examples
superset init

Your superset will be ready to use in a little while.

Usage of Custom Login

After the token is generated, url should be like this.
http://host:port/login?username=username&token=tokenSuperset will automatically log the user into the system and inform the database that the token has been used.
You can also log in to the system with a Username and Password.

Conclusion

Superset is an advanced data visualization tool and is preferred by many people and institutions because it is free. When integrating the superset into existing UI projects, it may be necessary to customize the login methods. In the example we gave in this article, we have seen how to log in to the system automatically using Tokens. By changing the rewritten config file, it can be provided to serve different scenarios.