mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-18 07:23:00 +00:00
update service-whoami examples to include OAuth
This commit is contained in:
@@ -8,7 +8,7 @@ Uses `jupyterhub.services.HubAuth` to authenticate requests with the Hub in a [f
|
|||||||
|
|
||||||
jupyterhub --ip=127.0.0.1
|
jupyterhub --ip=127.0.0.1
|
||||||
|
|
||||||
2. Visit http://127.0.0.1:8000/services/whoami
|
2. Visit http://127.0.0.1:8000/services/whoami or http://127.0.0.1:8000/services/whoami-oauth
|
||||||
|
|
||||||
After logging in with your local-system credentials, you should see a JSON dump of your user info:
|
After logging in with your local-system credentials, you should see a JSON dump of your user info:
|
||||||
|
|
||||||
|
@@ -9,5 +9,13 @@ c.JupyterHub.services = [
|
|||||||
'environment': {
|
'environment': {
|
||||||
'FLASK_APP': 'whoami-flask.py',
|
'FLASK_APP': 'whoami-flask.py',
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
'name': 'whoami-oauth',
|
||||||
|
'url': 'http://127.0.0.1:10201',
|
||||||
|
'command': ['flask', 'run', '--port=10201'],
|
||||||
|
'environment': {
|
||||||
|
'FLASK_APP': 'whoami-oauth.py',
|
||||||
|
}
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
@@ -17,7 +17,7 @@ prefix = os.environ.get('JUPYTERHUB_SERVICE_PREFIX', '/')
|
|||||||
|
|
||||||
auth = HubAuth(
|
auth = HubAuth(
|
||||||
api_token=os.environ['JUPYTERHUB_API_TOKEN'],
|
api_token=os.environ['JUPYTERHUB_API_TOKEN'],
|
||||||
cookie_cache_max_age=60,
|
cache_max_age=60,
|
||||||
)
|
)
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
70
examples/service-whoami-flask/whoami-oauth.py
Normal file
70
examples/service-whoami-flask/whoami-oauth.py
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
whoami service authentication with the Hub
|
||||||
|
"""
|
||||||
|
|
||||||
|
from functools import wraps
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
from flask import Flask, redirect, request, Response, make_response
|
||||||
|
|
||||||
|
from jupyterhub.services.auth import HubOAuth
|
||||||
|
|
||||||
|
|
||||||
|
prefix = os.environ.get('JUPYTERHUB_SERVICE_PREFIX', '/')
|
||||||
|
|
||||||
|
auth = HubOAuth(
|
||||||
|
api_token=os.environ['JUPYTERHUB_API_TOKEN'],
|
||||||
|
cache_max_age=60,
|
||||||
|
)
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def authenticated(f):
|
||||||
|
"""Decorator for authenticating with the Hub via OAuth"""
|
||||||
|
@wraps(f)
|
||||||
|
def decorated(*args, **kwargs):
|
||||||
|
token = request.cookies.get(auth.cookie_name)
|
||||||
|
if token:
|
||||||
|
user = auth.user_for_token(token)
|
||||||
|
else:
|
||||||
|
user = None
|
||||||
|
if user:
|
||||||
|
return f(user, *args, **kwargs)
|
||||||
|
else:
|
||||||
|
# redirect to login url on failed auth
|
||||||
|
state = auth.generate_state(next_url=request.path)
|
||||||
|
response = make_response(redirect(auth.login_url + '&state=%s' % state))
|
||||||
|
response.set_cookie(auth.state_cookie_name, state)
|
||||||
|
return response
|
||||||
|
return decorated
|
||||||
|
|
||||||
|
|
||||||
|
@app.route(prefix)
|
||||||
|
@authenticated
|
||||||
|
def whoami(user):
|
||||||
|
return Response(
|
||||||
|
json.dumps(user, indent=1, sort_keys=True),
|
||||||
|
mimetype='application/json',
|
||||||
|
)
|
||||||
|
|
||||||
|
@app.route(prefix + 'oauth_callback')
|
||||||
|
def oauth_callback():
|
||||||
|
code = request.args.get('code', None)
|
||||||
|
if code is None:
|
||||||
|
return 403
|
||||||
|
|
||||||
|
# validate state field
|
||||||
|
arg_state = request.args.get('state', None)
|
||||||
|
cookie_state = request.cookies.get(auth.state_cookie_name)
|
||||||
|
if arg_state != cookie_state:
|
||||||
|
# state doesn't match
|
||||||
|
return 403
|
||||||
|
|
||||||
|
token = auth.token_for_code(code)
|
||||||
|
next_url = auth.get_next_url(cookie_state) or prefix
|
||||||
|
response = make_response(redirect(next_url))
|
||||||
|
response.set_cookie(auth.cookie_name, token)
|
||||||
|
return response
|
@@ -2,13 +2,15 @@
|
|||||||
|
|
||||||
Uses `jupyterhub.services.HubAuthenticated` to authenticate requests with the Hub.
|
Uses `jupyterhub.services.HubAuthenticated` to authenticate requests with the Hub.
|
||||||
|
|
||||||
|
There is an implementation each of cookie-based `HubAuthenticated` and OAuth-based `HubOAuthenticated`.
|
||||||
|
|
||||||
## Run
|
## Run
|
||||||
|
|
||||||
1. Launch JupyterHub and the `whoami service` with
|
1. Launch JupyterHub and the `whoami service` with
|
||||||
|
|
||||||
jupyterhub --ip=127.0.0.1
|
jupyterhub --ip=127.0.0.1
|
||||||
|
|
||||||
2. Visit http://127.0.0.1:8000/services/whoami
|
2. Visit http://127.0.0.1:8000/services/whoami or http://127.0.0.1:8000/services/whoami-oauth
|
||||||
|
|
||||||
After logging in with your local-system credentials, you should see a JSON dump of your user info:
|
After logging in with your local-system credentials, you should see a JSON dump of your user info:
|
||||||
|
|
||||||
|
@@ -6,5 +6,10 @@ c.JupyterHub.services = [
|
|||||||
'name': 'whoami',
|
'name': 'whoami',
|
||||||
'url': 'http://127.0.0.1:10101',
|
'url': 'http://127.0.0.1:10101',
|
||||||
'command': [sys.executable, './whoami.py'],
|
'command': [sys.executable, './whoami.py'],
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
'name': 'whoami-oauth',
|
||||||
|
'url': 'http://127.0.0.1:10102',
|
||||||
|
'command': [sys.executable, './whoami-oauth.py'],
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
@@ -13,10 +13,10 @@ from tornado.ioloop import IOLoop
|
|||||||
from tornado.httpserver import HTTPServer
|
from tornado.httpserver import HTTPServer
|
||||||
from tornado.web import RequestHandler, Application, authenticated
|
from tornado.web import RequestHandler, Application, authenticated
|
||||||
|
|
||||||
from jupyterhub.services.auth import HubAuthenticated
|
from jupyterhub.services.auth import HubOAuthenticated, HubOAuthCallbackHandler
|
||||||
|
from jupyterhub.utils import url_path_join
|
||||||
|
|
||||||
|
class WhoAmIHandler(HubOAuthenticated, RequestHandler):
|
||||||
class WhoAmIHandler(HubAuthenticated, RequestHandler):
|
|
||||||
hub_users = {getuser()} # the users allowed to access this service
|
hub_users = {getuser()} # the users allowed to access this service
|
||||||
|
|
||||||
@authenticated
|
@authenticated
|
||||||
@@ -27,9 +27,10 @@ class WhoAmIHandler(HubAuthenticated, RequestHandler):
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
app = Application([
|
app = Application([
|
||||||
(os.environ['JUPYTERHUB_SERVICE_PREFIX'] + '/?', WhoAmIHandler),
|
(os.environ['JUPYTERHUB_SERVICE_PREFIX'], WhoAmIHandler),
|
||||||
|
(url_path_join(os.environ['JUPYTERHUB_SERVICE_PREFIX'], 'oauth_callback'), HubOAuthCallbackHandler),
|
||||||
(r'.*', WhoAmIHandler),
|
(r'.*', WhoAmIHandler),
|
||||||
])
|
], cookie_secret=os.urandom(32))
|
||||||
|
|
||||||
http_server = HTTPServer(app)
|
http_server = HTTPServer(app)
|
||||||
url = urlparse(os.environ['JUPYTERHUB_SERVICE_URL'])
|
url = urlparse(os.environ['JUPYTERHUB_SERVICE_URL'])
|
@@ -27,7 +27,7 @@ def main():
|
|||||||
app = Application([
|
app = Application([
|
||||||
(os.environ['JUPYTERHUB_SERVICE_PREFIX'] + '/?', WhoAmIHandler),
|
(os.environ['JUPYTERHUB_SERVICE_PREFIX'] + '/?', WhoAmIHandler),
|
||||||
(r'.*', WhoAmIHandler),
|
(r'.*', WhoAmIHandler),
|
||||||
], login_url='/hub/login')
|
])
|
||||||
|
|
||||||
http_server = HTTPServer(app)
|
http_server = HTTPServer(app)
|
||||||
url = urlparse(os.environ['JUPYTERHUB_SERVICE_URL'])
|
url = urlparse(os.environ['JUPYTERHUB_SERVICE_URL'])
|
||||||
|
Reference in New Issue
Block a user