When using Standalone authentication, Gateway supports authentication of a single user account. This might not be enough for your needs. To manage multiple user accounts while using a Standalone authentication, you can set up a separate user database and write custom authentication functions for Gateway to use.
Custom authentication functions replace the default authentication for Gateway Standalone authentication deployments. These functions should access the authentication system and database that you want your Standalone Gateway installation to use. The custom authentication functions must be inside a Python module script that is contained within the Built-In workspace. This means that the functions will be available only if Gateway is built into a Docker image with the custom authentication code before it is installed and deployed.
The example below uses the standard Gateway MongoDB workflow to authenticate users with the MongoDB client, allowing for authentication of multiple user credentials.
To set up authentication scripts that connect to a MongoDB database:
Create a MongoDB database to hold the user account authentication details.
For more details, see Creating the MongoDB database and collection.
Create a local directory for your Standalone authentication project.
In the same directory, create a file named
config.pywith the following code, replacing each setting as appropriate:MONGO_HOST = '10.244.141.44' # Replace with your MongoDB host URI MONGO_PORT = 27017 # Replace with your MongoDB port number MONGO_DBNAME = 'gateway' # Replace with your MongoDB Database name MONGO_USERNAME = 'go' # Replace with your MongoDB username MONGO_PASSWORD_PATH = 'customizations/.mongosecret' # Replace with your MongoDB password file locationMONGO_PASSWORD_PATHmust be a relative path from the workspace root folder. It cannot be an absolute path.The
.mongosecretfile referenced byMONGO_PASSWORD_PATHmust be encrypted. This encryption must use the Secret key that is specified in the Gateway Certificates settings. (ClickSettings at the bottom of the navigator on the left, expand Configurations, then click General configuration. Click Certificates to scroll to the Certificates section.)
Tip: You can use Gateway's Encrypt password page to encrypt the password file. Make sure the secret key you're using to encrypt the file is the same one specified in the Certificates settings.Make sure that you store the encrypted
.mongosecretfile in thecustomizationssubfolder under the local directory that you specified earlier.
Within the same directory, create a custom authentication script named
gw_custom_authentication.py.Add the following code to the
gw_custom_authentication.pyscript:import base64 import json from bluecat.util import get_portal_mongo_db def generate_token(username, password): """ Generates a simple token """ user_data = { 'username': username, 'password': password } # Convert the dictionary to a JSON string json_data = json.dumps(user_data) # Encode the JSON string to bytes and then to base64 encoded_data = base64.b64encode(json_data.encode()).decode() return encoded_data def decode_token(token): """ Decodes the token and returns the username and password """ # Decode the base64 encoded data back to JSON string json_data = base64.b64decode(token).decode() # Convert the JSON string back to a dictionary user_data = json.loads(json_data) return user_data def retrieve_user_information(username: str, password: str) -> dict: """ Validate the custom user credentials. :return: A dictionary contain the information of the custom user. """ client = get_portal_mongo_db() users_collection = client.db.users username_identifier = {'username': username, 'password': password} user = users_collection.find_one(username_identifier) if user : token = generate_token(user.get('username'), user.get('password')) return { "username": user.get('username'), "token": token, "group": user.get('group') } return {} def retrieve_user_information_via_token(token: str) -> dict: """ Validate the custom user token. :return: A dictionary contain the information of the custom user. """ user = decode_token(token) client = get_portal_mongo_db() users_collection = client.db.users username_identifier = {'username': user.get('username'), 'password': user.get('password')} user = users_collection.find_one(username_identifier) if user: return { "username": user.get('username'), "token": token, "group": user.get('group') } return {}This script implements the required
retrieve_user_information()andretrieve_user_information_via_token()functions. These functions validate the user's credentials by either username/password or from a session token.Important: This code assumes that the MongoDB database implements theuserscollection withusername,password, andgroupas strings. If your schema differs, change the code as needed to fetch and compare the indicated values.As described in Authentication function script format, if the credentials or token are valid, these functions will return the user's details in the following format:
{ "username": <User name>, "token": <Token>, "group": <Gateway group>, }To create a new Docker image with your custom authentication scripts:
In the same directory where your custom authentication script is located, first create the following Dockerfile script (with the file name
Dockerfile):FROM quay.io/bluecat/gateway:v25.3.0 USER root COPY ./gw_custom_authentication.py /builtin/customizations/ COPY ./.mongosecret /builtin/customizations/ COPY ./config.py /builtin/ # Ensure the content is available if the container is run with a custom User ID. RUN chgrp -R 0 /builtin && chmod -R g=u /builtin USER flaskWhen executed, this file first copies required files to the
builtinbuiltin/customizationsfolder in the built-in workspace. Then, it makes sure the folder is available to containers run with a custom User ID.To execute the Dockerfile you just created, run the following command from the same directory as the Dockerfile script you just created:
docker build . -t <Custom project:Version>Where:
<Custom projectis the a custom name for your project, with no spaces.<Versionis a version number for your project, with no spaces. This can be useful during development to track different versions of your authentication scripts.
Running this command creates a docker image named
<Custom project:Version>.
Run the container with this newly-created image. Use the same docker command you normally would, replacing the final
--nameparameter with<Custom project:Version>. For example:docker run -d \ -p 80:8000 \ -p 443:44300 \ -v <Path to mapped workspace directory>:/bluecat_gateway/ \ -v <Path to mapped logs directory>:/logs/ \ -e AUTHENTICATION=Standalone \ -e STANDALONE_USERNAME=<Standalone account user name> -e STANDALONE_PASSWORD=<Standalone account password> \ --name bluecat_gateway <Custom project:Version>Note: If you are mounting a custom workspace with aconfig.pyfile with the MongoDB configuration in it, the configuration in the custom workspace will have a higher precedence than the MongoDB configuration in the built-in workspace.You can now log in to Gateway as a user with your custom credentials, validated by MongoDB.
Setting up MongoDB without using the Gateway MongoDB workflow
The example above assumes you are configuring your MongoDB client through the
Gateway UI. If desired, you can also create the MongoDB
client from the gw_custom_authentication.py script itself, using
the Flask-PyMongo package that comes installed with Gateway.
To do so, add the following to gw_custom_authentication.py:
from flask_pymongo import PyMongo
from flask import current_app
def get_mongo_client():
return PyMongo(current_app, "mongodb://<User name>:<Password>@<Host>:<Port>/<Database>")
Creating the MongoDB database and collection
The following steps describe how to create a MongoDB database and collection, and insert data into the new collection. You can use this to test the example authentication scripts.
Connect to the MongoDB deployment. To do so, run the following command on the machine to which MongoDB is deployed:
mongoshNote: The default MongoDB port is 27017. To use a different port, run the following command instead:mongosh "mongodb://localhost:<Port number>"Tip: For other ways to connect to a MongoDB deployment, see Connect to a Deployment.Create a new MongoDB database. To do so, run the following command in the MongoDB shell:
use <Database name>This command creates a new database and switches to that database.
Create a new collection in the database and add data for the list of users. To do so, run the following command:
db.users.insertOne({username: "mongoExampleUser", password: "mongoExampleUser", group: "all"})This command creates a new collection called
usersand adds a sample user namedmongoExampleUser. This collection will store a list of user details includingusername,passwordandgroup.Create a new user in the new database for BlueCat Gateway to use when connecting to the MongoDB database.
BlueCat Gateway needs a username and password to connect to a MongoDB instance. These details must match those used in the config.py file used to set BlueCat Gateway's MongoDB configuration.
To create this user, run the following command in the MongoDB shell:
db.createUser ({ user: "<Username>", pwd: "<Password>", roles: [ { role: "readWrite", db: "<Database name>" } ] })Replace
<Database name>with the name of the MongoDB database that you specified earlier.To confirm that the user was created successfully, run the following command:
show usersYou now have a MongoDB database that BlueCat Gateway can log into, using the username and password specified in Step 3 as
<Username>and<Password>. This username and password should be used when setting up theconfig.pyfile during main authentication script setup, with the password file encrypted.