consideRatio / discourse-sso-oidc-bridge

Discourse SSO OIDC Bridge - A Python PyPI package
Apache License 2.0
4 stars 4 forks source link

Discourse SSO OIDC Bridge - A Python PyPI package and a Docker image

Latest PyPI version GitHub Workflow Status - Test DockerHub build status

This Python package contains a Flask application that when deployed can be used as and endpoint for Discourse when setting up it's SSO. It will then be able to wrap a OIDC provider and avoid various limitations of not being setup as a Discourse SSO provider.

The Flask application can be deployed using a Docker image that is also within this repo and published to docker hub as consideratio/discourse-sso-oidc-bridge.

This repo was made standing on the shoulders giants who made most of the initial work. Thank you @fmarco76 and @stevenmirabito for the valuable work you have made!

I also did some Dockerfile refinements thanks to @greut's excellent Medium article.

Installation

Note that this only installs a Python package containing a Flask application, you must use gunicorn or another WSGI compatible webserver to host it and setup TLS etc.

pip install --upgrade discourse-sso-oidc-bridge-consideratio

To startup a the Flask app within a prebuilt Docker image, do the following.

docker run --rm -p 8080:8080 consideratio/discourse-sso-oidc-bridge

To actually use it, you should make it deployed in a way that it is accessible for discourse and its users, so it can redirect arriving users who wants to login to it. To do this, visit the discourse settings and search for sso.

NOTE: When you do this setup, you want to check and fill in enable sso, sso url, and sso secret. What you write in your sso secret should be repeated in your bridge configuration.

Bridge Configuration

These are common configuration options, but you can find some more exotic ones within default.py.

To configure these, you have two options.

Config / ENV name Description
DEBUG Very useful while setting this up as you get lots of additional logs, but also sensitive information. Defaults to False.
SECRET_KEY A secret for Flask, just generate one with openssl rand -hex 32.
OIDC_ISSUER An URL to the OIDC issuer. To verify you get this right you can try appending /.well-known/openid-configuration to it and see if you get various JSON details rather than a 404.
OIDC_CLIENT_ID A preregistered client_id on your OIDC issuer.
OIDC_CLIENT_SECRET The provided secret for the the preregistered OIDC_CLIENT_ID.
OIDC_SCOPE Comma or space seperated OIDC scopes, defaults to "openid profile".
OIDC_REDIRECT_URI The URL you register with your identity provider, should include https:// and end with /redirect_uri.
OIDC_EXTRA_AUTH_REQUEST_PARAMS Valid JSON object in a string containing key/values for additional parameters to be sent along with the initial request to the OIDC provider, defaults to "{}".
DISCOURSE_URL The URL of your Discourse deployment, example "https://discourse.example.com".
DISCOURSE_SECRET_KEY A shared secret between the bridge and Discourse, generate one with openssl rand -hex 32.
USERINFO_SSO_MAP Valid JSON object in a string mapping OIDC userinfo attribute names to to Discourse SSO attribute names.
DEFAULT_SSO_ATTRIBUTES Valid JSON object in a string mapping Discourse SSO attributes to default values. By default sub is mapped to external_id and preferred_username to username.
CONFIG_LOCATION The path to a Python file to be loaded as config where OIDC_ISSUER etc. could be set.

OIDC Provider Configuration

You must have a client_id and client_secret from your OIDC issuer. The issuer must also accept redirecting back to <PREFERRED_URL_SCHEME>://<bridge_url>/redirect_uri, which for example could be https://discourse-sso.example.com/redirect_uri.

Development Notes

To make changes and test them

  1. Clone the repo

  2. Install dependencies

    pip install -r dev-requirements.txt -r requirements.txt
  3. Install package locally

    pip install -e .
  4. Run tests

    pytest

Build and upload a PyPI release

  1. Run tests and tag a commit.

    # Make sure you dev requirements are up to date
    pip install -r dev-requirements.txt
    
    # Freeze requirements.in to requirements.txt
    pip-compile
    
    # Run tests
    pytest
    
    # Verify that the Dockerfile can build and start
    docker build --tag discourse-sso-oidc-bridge:local . && docker run --rm discourse-sso-oidc-bridge:local
    
    # Tag for the PyPI release automation
    git tag -a $TAG -m "Release $TAG"
    
    # Update changelog manually
    git add .
    git commit -m "Update ChangeLog"
  2. Push git commits and tags to trigger CD of Docker image and PyPI packaging through a GitHub workflow.

    git push --follow-tags
  3. Verify CD of Docker image and PyPI package.

    Visit DockerHub to verify the build succeeds.

    Visit GitHub Actions to verify the release build succeeds.

    Visit PyPI and release has been published.

Deployment notes

I have deployed this using a simpler not published Helm chart. I'm happy to open source this as well for a complete solution. But to avoid overworking something that few has interest for it in I'd appreciate if you showed interest in this by emailing me or opening an issue or similar.