Monday, July 1, 2019

Discourse.org SSO with gitlab.com

A previous post discussed how to set up a Discourse forum to run as a service within JupyterHub. Though this makes the forum appear within the URL space of the JupyterHub server, it still runs as a completely separate service with its own notion of accounts and identities. We're tackling that in this post, describing how to make Discourse use single sign on (SSO) from gitlab.com, which is also how we set up JupyterHub accounts to work.

The previous post went over creating a JupyterHub service configuration for the Discourse service. We now add a second service, for the SSO server. This example is for The Littlest JupyterHub, where we create a snippet in /opt/tljh/config/jupyterhub_config.d/discourse-service.py.

c.JupyterHub.services = [
    {
        'name': 'forum',
        'url': 'http://172.17.0.2:80/',
        'api_token': 'no_token',
    },
    {
        'name': 'discourse-sso',
        'url': 'http://127.0.0.1:10101',
        'command': ['/opt/tljh/user/bin/flask', 'run', '--port=10101'],
        'environment': {'FLASK_APP': '/opt/tljh/hub/bin/discourse-sso.py',
            'GITLAB_CLIENT_ID': '...',
            'GITLAB_CLIENT_SECRET': '...',
            'EXTERNAL_BASE_URL': 'https://jupyterhub.example.com',
            'DISCOURSE_SECRET': '...',
        },
    },
]

Code for the service is at discourse-gitlab-sso. It provides a Python Flask-based service which:

  • Listens for SSO redirects from discourse, which arrive at discourse_sso() and results in redirecting the browser to gitlab.com for an OAuth request.
  • gitlab.com redirects the browser to gitlab_oauth_callback() with the OAuth response. Python code sends several followup requests to get a token and fetch information about the user from GitLab.
  • gitlab_user_to_discourse() maps the information retrieved from gitlab to the format expected by Discourse, and the browser is finally redirected back to Discourse with the SSO information encoded.