mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-07 18:14:10 +00:00
add external oauth example
This commit is contained in:
74
examples/external-oauth/README.md
Normal file
74
examples/external-oauth/README.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# Using JupyterHub as an OAuth provider
|
||||
|
||||
JupyterHub 0.9 introduces
|
||||
Uses `jupyterhub.services.HubAuthenticated` to authenticate requests with the Hub.
|
||||
|
||||
There is an implementation each of cookie-based `HubAuthenticated` and OAuth-based `HubOAuthenticated`.
|
||||
|
||||
## Run
|
||||
|
||||
1. generate an API token:
|
||||
|
||||
export JUPYTERHUB_API_TOKEN=`openssl rand -hex 32`
|
||||
|
||||
2. launch the whoami service:
|
||||
|
||||
bash launch-service.sh &
|
||||
|
||||
3. Launch JupyterHub:
|
||||
|
||||
4. Visit http://127.0.0.1:5555/
|
||||
|
||||
After logging in with your local-system credentials, you should see a JSON dump of your user info:
|
||||
|
||||
```json
|
||||
{
|
||||
"admin": false,
|
||||
"last_activity": "2016-05-27T14:05:18.016372",
|
||||
"name": "queequeg",
|
||||
"pending": null,
|
||||
"server": "/user/queequeg"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
The essential pieces for using JupyterHub as an OAuth provider are:
|
||||
|
||||
1. registering your service with jupyterhub:
|
||||
|
||||
```python
|
||||
c.JupyterHub.services = [
|
||||
{
|
||||
# the name of your service
|
||||
# should be simple and unique.
|
||||
# mostly used to identify your service in logging
|
||||
"name": "my-service",
|
||||
# the oauth client id of your service
|
||||
# must be unique but isn't private
|
||||
# can be randomly generated or hand-written
|
||||
"oauth_client_id": "abc123",
|
||||
# the API token and client secret of the service
|
||||
# should be generated securely,
|
||||
# e.g. via `openssl rand -hex 32`
|
||||
"api_token": "abc123...",
|
||||
# the redirect target for jupyterhub to send users
|
||||
# after successful authentication
|
||||
"oauth_redirect_uri": "https://service-host/oauth_callback"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
2. Telling your service how to authenticate with JupyterHub.
|
||||
|
||||
The relevant OAuth URLs for working with JupyterHub are:
|
||||
|
||||
1. the client_id, used in oauth requests
|
||||
2. the api token registered with jupyterhub is the client_secret for oauth requests
|
||||
3. oauth url of the Hub, which is "/hub/api/oauth2/authorize", e.g. `https://myhub.horse/hub/api/oauth2/authorize`
|
||||
4. a redirect handler to receive the authenticated response
|
||||
(at `oauth_redirect_uri` registered in jupyterhub config)
|
||||
5. the token URL for completing the oauth process is "/hub/api/oauth2/token",
|
||||
e.g. `https://myhub.horse/hub/api/oauth2/token`.
|
||||
The reply is JSON and the token is in the field `access_token`.
|
||||
6. Users can be identified by oauth token by making a request to `/hub/api/user`
|
||||
with the new token in the `Authorization` header.
|
17
examples/external-oauth/jupyterhub_config.py
Normal file
17
examples/external-oauth/jupyterhub_config.py
Normal file
@@ -0,0 +1,17 @@
|
||||
import os
|
||||
|
||||
# get the oauth client's API token.
|
||||
# this could come from anywhere
|
||||
api_token = os.getenv("JUPYTERHUB_API_TOKEN")
|
||||
if not api_token:
|
||||
raise ValueError("Make sure to `export JUPYTERHUB_API_TOKEN=$(openssl rand -hex 32)`")
|
||||
|
||||
# tell JupyterHub to register the service as an external oauth client
|
||||
c.JupyterHub.services = [
|
||||
{
|
||||
'name': 'external-oauth',
|
||||
'oauth_client_id': "whoami-oauth-client-test",
|
||||
'api_token': api_token,
|
||||
'oauth_redirect_uri': 'http://127.0.0.1:5555/oauth_callback',
|
||||
},
|
||||
]
|
20
examples/external-oauth/launch-service.sh
Normal file
20
examples/external-oauth/launch-service.sh
Normal file
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# the service needs to know:
|
||||
# 1. API token
|
||||
if [[ -z "${JUPYTERHUB_API_TOKEN}" ]]; then
|
||||
echo 'set API token with export JUPYTERHUB_API_TOKEN=$(openssl rand -hex 32)'
|
||||
fi
|
||||
|
||||
# 2. oauth client ID
|
||||
export JUPYTERHUB_CLIENT_ID="whoami-oauth-client-test"
|
||||
# 3. what URL to run on
|
||||
export JUPYTERHUB_SERVICE_PREFIX='/'
|
||||
export JUPYTERHUB_SERVICE_URL='http://127.0.0.1:5555'
|
||||
export JUPYTERHUB_OAUTH_CALLBACK_URL="$JUPYTERHUB_SERVICE_URL/oauth_callback"
|
||||
# 4. where the Hub is
|
||||
export JUPYTERHUB_HOST='http://127.0.0.1:8000'
|
||||
|
||||
# launch the service
|
||||
exec python3 whoami-oauth.py
|
46
examples/external-oauth/whoami-oauth.py
Normal file
46
examples/external-oauth/whoami-oauth.py
Normal file
@@ -0,0 +1,46 @@
|
||||
"""An example service authenticating with the Hub.
|
||||
|
||||
This example service serves `/services/whoami/`,
|
||||
authenticated with the Hub,
|
||||
showing the user their own info.
|
||||
"""
|
||||
from getpass import getuser
|
||||
import json
|
||||
import os
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from tornado.ioloop import IOLoop
|
||||
from tornado import log
|
||||
from tornado.httpserver import HTTPServer
|
||||
from tornado.web import RequestHandler, Application, authenticated
|
||||
|
||||
from jupyterhub.services.auth import HubOAuthenticated, HubOAuthCallbackHandler
|
||||
from jupyterhub.utils import url_path_join
|
||||
|
||||
class WhoAmIHandler(HubOAuthenticated, RequestHandler):
|
||||
hub_users = {getuser()} # the users allowed to access this service
|
||||
|
||||
@authenticated
|
||||
def get(self):
|
||||
user_model = self.get_current_user()
|
||||
self.set_header('content-type', 'application/json')
|
||||
self.write(json.dumps(user_model, indent=1, sort_keys=True))
|
||||
|
||||
def main():
|
||||
log.enable_pretty_logging()
|
||||
app = Application([
|
||||
(os.environ['JUPYTERHUB_SERVICE_PREFIX'], WhoAmIHandler),
|
||||
(url_path_join(os.environ['JUPYTERHUB_SERVICE_PREFIX'], 'oauth_callback'), HubOAuthCallbackHandler),
|
||||
(r'.*', WhoAmIHandler),
|
||||
], cookie_secret=os.urandom(32))
|
||||
|
||||
http_server = HTTPServer(app)
|
||||
url = urlparse(os.environ['JUPYTERHUB_SERVICE_URL'])
|
||||
log.app_log.info("Running whoami service on %s", os.environ['JUPYTERHUB_SERVICE_URL'])
|
||||
|
||||
http_server.listen(url.port, url.hostname)
|
||||
|
||||
IOLoop.current().start()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
BIN
examples/external-oauth/whoami.png
Normal file
BIN
examples/external-oauth/whoami.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
Reference in New Issue
Block a user