TIBCO ModelOps Instances using External Authentication
This section explains how TIBCO ModelOps JupyterLab extensions work with ModelOps instances that have enabled External-Authentication.
Contents
Overview
TIBCO ModelOps supports the use of external authentication providers (see Security). TIBCO ModelOps JupyterLab extensions can connect to such TIBCO ModelOps instances to deploy and monitor Jupyter Notebook documents and Python script files. The extensions can establish a working connection with these TIBCO ModelOps instances by acquiring tokens (JWTs) from JupyterHub.
Requirements
- JupyterHub 3.0.0 or higher
- OAuthenticator 15.0.0 or higher
- JupyterLab 3.3.0 or higher
- TIBCO ModelOps 1.3.0 or higher
JupyterHub & External Auth Providers
JupyterHub serves Jupyter Notebook servers for multiple users by spawning, managing, and proxying multiple single-user notebook server instances. JupyterHub can use various authenticators and spawners. OAuthenticator provides JupyterHub plug-ins to use OAuth 2.0 providers such as Azure Active Directory and AWS Cognito. OAuthenticator also provides base classes for developing custom authenticator implementations.
Assumptions
For TIBCO ModelOps JupyterLab extensions to use TIBCO ModelOps instances that use external authentication, certain conditions must be satisfied:
- JupyterHub is installed and uses an OAuth 2.0 provider.
- JupyterHub and TIBCO ModelOps use the same OAuth 2.0 provider.
- JSON object containing a valid JSON Web Token (JWT) is
available to the spawner
through an environment variable named
auth_state
. - The JWT could be an access token or an id token. By default, the extensions will look for the “access_token” key.
A different key (to find the token to use) can be specified through an environment variable called
TMO_TOKEN_NAME
.
auth_state: {
"id_token": "a-valid-id-token",
"access_token": "a-valid-access-token"
}
The extensions acquire and use these tokens to work with TIBCO ModelOps instances that use external authentication.
JupyterHub Authentication Configuration
JupyterHub must be configured correctly to make tokens available to the spawner. There might be several ways to achieve this.
- A custom authenticator to include tokens in the authentication state
- An auth state hook function
to ensure the authentication state is available in the Spawner's environment (through a variable named
auth_state
).
The following jupyterhub_config.py template script file contains sample implementations of a custom authenticator and auth-state hook. Replace the placeholder tokens in the configuration-section before using it as a JupyterHub configuration file.
import os
import json
from base64 import b64encode
from jupyterhub.auth import LocalAuthenticator
from oauthenticator.generic import GenericOAuthenticator
# custom authenticator class to get required tokens
class TMOAuthenticator(GenericOAuthenticator):
# override GenericOAuthenticator's _create_auth_state
# method to make sure tokens are present in the
# authentication state
@staticmethod
def _create_auth_state(token_response, user_data_response):
access_token = token_response['access_token']
id_token = token_response.get('id_token', None)
scope = token_response.get('scope', '')
if isinstance(scope, str):
scope = scope.split(' ')
return {
'access_token': access_token,
'id_token': id_token,
'oauth_user': user_data_response,
'scope': scope,
}
class LocalTMOAuthenticator(LocalAuthenticator, TMOAuthenticator):
"""A version that mixes in local system user creation"""
pass
# use custom authenticator class
c.JupyterHub.authenticator_class = TMOAuthenticator
# configuration-section: begin
# ----------------------------
# configure the authenticator to use desired OAuth 2.0 provider
c.TMOAuthenticator.oauth_callback_url = 'a-jupyterhub-callback-url'
c.TMOAuthenticator.client_id = 'a-valid-client-id'
c.TMOAuthenticator.client_secret = 'a-valid-client-secret'
c.TMOAuthenticator.login_service = 'login-service-name'
c.TMOAuthenticator.username_key = 'user-name-key-in-response'
c.TMOAuthenticator.authorize_url = 'a-valid-authorize-url'
c.TMOAuthenticator.token_url = 'a-valid-token-url'
c.TMOAuthenticator.userdata_url = 'a-valid-userdata-url'
c.TMOAuthenticator.scope = ['openid', 'profile']
def custom_auth_state_hook(spawner, auth_state):
spawner.environment = {
'auth_state': json.dumps(auth_state),
# by default the 'access_token' key will be used
# use 'TMO_TOKEN_NAME' to indicate which key to use
# "TMO_TOKEN_NAME": "id_token"
}
# --------------------------
# configuration-section: end
# wire up auth-state hook
c.Spawner.auth_state_hook = custom_auth_state_hook
# ensure auth state is up-to-date
# https://jupyterhub.readthedocs.io/en/stable/api/auth.html
c.Authenticator.refresh_pre_spawn = True
# ensure auth state is encrypted and persisted
# https://jupyterhub.readthedocs.io/en/stable/api/auth.html
c.Authenticator.enable_auth_state = True
# ensure user servers shutdown on logout
# this is to make sure servers with stale
# auth state in their environments are not used
# https://jupyterhub.readthedocs.io/en/stable/reference/urls.html#hub-logout
c.JupyterHub.shutdown_on_logout = True
# ensure JUPYTERHUB_CRYPT_KEY contains an encryption key
if 'JUPYTERHUB_CRYPT_KEY' not in os.environ:
os.environ['JUPYTERHUB_CRYPT_KEY'] = b64encode(os.urandom(32)).decode('utf-8')
For more information on how to start a JupyterHub instance with a specific configuration file, see the JupyterHub Configuration Basics.
Azure AD Configuration Example
Modify the sample jupyterhub_config.py file as shown below to use Azure Active Directory as the OAuth 2.0 provider. For more information on obtaining appropriate values for the following settings, see OAuth 2.0 and OpenID Connect (OIDC) in the Microsoft identity platform.
c.TMOAuthenticator.oauth_callback_url = 'https://jupyterhub.example.com:8765/hub/oauth_callback'
c.TMOAuthenticator.client_id = '<application-client-id-from-azure-ad>'
c.TMOAuthenticator.client_secret = '<application-client-secret-from-azure-ad>'
aad_tenant_id = '<tenant-id-from-azure-ad>'
c.TMOAuthenticator.login_service = "Azure Active Directory"
c.TMOAuthenticator.username_key = "unique_name"
c.TMOAuthenticator.authorize_url = f'https://login.microsoftonline.com/{aad_tenant_id}/oauth2/authorize'
c.TMOAuthenticator.token_url = f'https://login.microsoftonline.com/{aad_tenant_id}/oauth2/token'
c.TMOAuthenticator.userdata_url = 'https://login.microsoftonline.com/common/openid/userinfo'
AWS Cognito Example
To use AWS Cognito as the OAuth 2.0 provider, modify the sample jupyterhub_config.py file as follows. For more information on obtaining appropriate values for the following settings, see Amazon Cognito tutorials and Amazon Cognito API references.
c.TMOAuthenticator.oauth_callback_url = 'https://jupyterhub.example.com:8765/hub/oauth_callback'
c.TMOAuthenticator.client_id = '<application-client-id-from-aws-cognito>'
c.TMOAuthenticator.client_secret = '<application-client-secret-from-aws-cognito>'
c.TMOAuthenticator.login_service = "AWS Cognito"
c.TMOAuthenticator.username_key = "email"
c.TMOAuthenticator.authorize_url = 'https://<app-domain>.auth.<region>.amazoncognito.com/oauth2/authorize'
c.TMOAuthenticator.token_url = 'https://<app-domain>.auth.<region>.amazoncognito.com/oauth2/token'
c.TMOAuthenticator.userdata_url = 'https://<app-domain>.auth.<region>.amazoncognito.com/oauth2/userInfo'
Miscellaneous Notes
-
The OAuth2 Proxy instance used in the public ingress of the TIBCO ModelOps installation should be configured to skip requests that have verified JWT bearer tokens via the –skip-jwt-bearer-tokens flag. TIBCO ModelOps installer sets this flag to
true
. -
For extensions to work with an external-authentication-enabled ModelOps server, the JWT provided should not have expired (see exp claim) and should have a valid audience claim (see aud claim). To examine the value of the
auth_state
environment variable passed via the spawner, open a Terminal in JupyterLab and issue theenv
command. The values of the tokens can then be verified using JWT Debuggers such as jwt.io.