Add AD authentication to your Dash app

A very simple way to integrate Dash with LDAP using Flask

Erik Petrovski
Towards Data Science

--

It’s a locked dashboard!
Photo by Dane Deaner on Unsplash

In most organizations, login credentials are managed by a directory service like Active Directory. If you manage to integrate Dash with your organization’s directory service then users can simply log in to your Dash app with their existing credentials. A common way of doing this is by way of LDAP (an open protocol for speaking with directory services like Active Directory) and Flask (a lightweight web application framework). In this post, I’ll demonstrate how to integrate LDAP and FLASK with Dash in Python in — as far as I know — the simplest way possible.

Prerequisites

Before getting into any code, you need to have LDAP already up and running. This is a major step that’s out of the scope of this article which only focuses on the Python side of things. If you need AD integration however, I’m assuming that you work in a pretty large organization with its own IT-department and hopefully that department is (1) not you and (2) willing to help!

Assuming LDAP is up and running, go ahead and clone the example code from GitHub by running:

git clone https://github.com/epetrovski/dash_ldap

We also need a few libraries to build a Dash app and make it work with LDAP — four in total. If you already use Pipenv, just run the following in a terminal inside the cloned dash_ldap directory to get a full working virtual environment with dependencies installed:

pipenv sync

If you don’t want to mess with Pipenv, just install the dependencies you need with:

pip install dash flask flask-simpleldap gunicorn

Walkthrough of app.py

All the code you need is in app.py. Let’s go through it line by line.

The first trick is to make Dash run inside a Flask app that serves your Dash app to the outside world. This is done by passing a Flask object to the Dash app’s server argument at initialization like so:

app = Dash(__name__, server=Flask(__name__))

We then define a Dash app for purpose of example. This app is just a simple placeholder but don’t worry, when you build your own app with advanced callbacks etc., it won’t require any changes to the LDAP integration setup.

app.layout = html.P('Hello world!')

You’ll now need to configure Flask for LDAP by updating Flask’s configuration dictionary. The details below is just a placeholder as your credentials will depend on your company’s LDAP setup — again, ask IT!

app.server.config.update({
'LDAP_BASE_DN': 'OU=users,dc=example,dc=org',
'LDAP_USERNAME': 'CN=user,OU=Users,DC=example,DC=org',
'LDAP_PASSWORD': os.getenv('LDAP_PASSWORD')})

You may have noticed that I’ve taken the liberty and added the LDAP_PASSWORD with an os.getenv(). I’m assuming that you would never store a password in code but use something like an environment variable instead.

Very importantly, now we need to protect all of Dash’s view functions that have been registered with Flask with an authentication requirement by wrapping them with LDAP(app.server).basic_auth_required():

for view_func in app.server.view_functions:
app.server.view_functions[view_func] = LDAP(app.server).basic_auth_required(app.server.view_functions[view_func])

Finally, we may want a way to run the Flask app quickly for testing purposes. Usually we would use app.run() but since the app is served on a Flask server, we use app.run_server():

if __name__ == '__main__':
app.run_server()

Test it out

You can confirm that the AD integration is working by running:

python3 app.py

Now navigate to http://127.0.0.1:8000 and you should see a login prompt. Punch in your credentials and you should see the ‘Hello world!’ frontpage.

Now that you’re pleased with having everything running smoothly, please remember that a crucial part to making this all work is the flask-simpleldap package. It’s one of those great Python packages that just works and solves a very unglamorous but crucial IT need.

Run in production

If you’re running your Dash app in production, you should be running the app on a production grade http server like gunicorn. You already have this installed, so just run:

gunicorn app:server

This works because in app.py, I’ve defined:

server = app.server

There you go, a login protected Dash app that integrates with a directory service and is fit for production!

--

--