Configure username/password authentication

This guide shows you how to configure username/password authentication for Deephaven.

Username/password is a common authentication method in which each user of an application has their own username and a secret password. The username says who the user is, and the password proves it.

Warning

The example configuration given in this guide is not recommended for use in a production environment. It is only meant to show a basic implementation that can be used as a template. Every user who logs in gets the same SuperUser context. A SuperUser context allows everything the Deephaven APIs allow, so the example handler doesn't limit what any user can do.

Overview

Username/password authentication requires some extra configuration on top of a Docker deployment of Deephaven. A PostgreSQL database that runs in Docker alongside Deephaven stores usernames and passwords. The database stores each password as a bcrypt hash. Bcrypt is a one-way hashing algorithm.

The Dockerfile adds a JAR (Java archive) file to the Deephaven classpath. The classpath is the list of libraries that the Deephaven server loads at startup. That JAR file handles the authentication.

For a basic setup, there are three required files:

  • A SQL file to create a schema and a table of usernames and bcrypt-hashed passwords.
  • A Dockerfile that builds the Deephaven image and adds the required JAR to the Deephaven classpath.
  • A Docker Compose file that defines the PostgreSQL and Deephaven services.

Set up username/password authentication

SQL

Save the following as init-users.sql in the same directory as your Dockerfile and docker-compose.yml. It creates a schema, deephaven_username_password_auth, with a single table (users). The table has a single entry for a user named admin with the password p@ssw0rd.

The rounds column records the bcrypt cost factor of each hash. This example uses 10, which the $2a$10$ prefix of the hash records. The handler doesn't check rounds against the hash, so keep the two equal. See Add more users after startup for the value to use with a new hash.

Dockerfile

The Dockerfile adds the JAR file from the Overview to the Deephaven classpath. The Groovy example uses the server-slim image, which starts a Groovy console.

Note

Make sure that the version in the FROM image tag matches the version of the authentication-provider JAR in the ADD URL. Both use version 42.7 in this example.

docker-compose.yml

Create docker-compose.yml in the same directory as the Dockerfile. The build: . line builds the Deephaven image from that Dockerfile. The file defines two services: postgres and deephaven.

The deephaven service's host port is configurable. The settings after the file explain how to change it.

Warning

The file below turns fsync off, which is not recommended. It also sets the postgres service's admin password to password in plaintext. See How to use secrets in Docker Compose to learn more about security best practices with Docker.

The START_OPTS value sets these Java options:

  • -Xmx4g: The maximum Java Virtual Machine (JVM) heap size.
  • -DAuthHandlers: The authentication handler to use. Here, it is the SQL handler.
  • -Dauthentication.basic.sql.jdbc.connection: The JDBC (Java Database Connectivity) URL of the user database. The handler can't log in without it.
  • -Dauthentication.basic.sql.jdbc.user and -Dauthentication.basic.sql.jdbc.password: The database login that the handler uses to read the users table.

The JDBC URL uses postgres, the Compose service name, because containers reach each other by service name, not localhost.

The deephaven service also defines these settings:

  • ports: Maps the host port named by the DEEPHAVEN_PORT environment variable (default 10000) to port 10000 in the container.
  • volumes: Mounts ./data on the host to /data in the container.

Start Deephaven

Start Deephaven with docker compose up --build. Then open http://localhost:10000/ide and sign in with the username admin and the password p@ssw0rd that the SQL file created. If you set DEEPHAVEN_PORT, replace 10000 in the URL with that host port.

Add more users after startup

Each row in the users table stores a username, a bcrypt hash of the password, and the rounds value. The rounds value is the bcrypt cost factor, as a power of two: a cost of 10 runs 2^10 hashing rounds. Set rounds to the value in the hash's $2a$...$ prefix. The examples in this guide use 10.

This step needs git and a Java Development Kit (JDK) on your machine, not only Docker.

To generate a hash, clone the Deephaven source repository, open a shell at its root, and run the generatePassword Gradle task. Replace newPasswordGoesHere with the password you want to hash:

Keep both layers of quotes. The outer single quotes stop the shell from expanding a $ in the password. The inner double quotes keep a password that contains spaces together as one argument when Gradle parses --args. Without them, the hash doesn't match the password you intended.

By default, the generatePassword task prints a hash that starts with $2a$10$.

PostgreSQL runs init-users.sql only when the container starts with an empty data directory, which happens on its first start. To add users, insert new rows into the running database instead of editing the file.

The Compose file above doesn't define a named volume or bind mount for database data, so PostgreSQL stores its data in a Docker-managed anonymous volume. docker compose down leaves that volume and its rows on disk, but a subsequent docker compose up doesn't automatically reattach it. Add the additional users again in the recreated database.

Open a PostgreSQL command-line shell (psql) with docker compose exec postgres psql -U postgres. Then run an INSERT statement with the hash that the generatePassword task printed and the matching rounds value: