update service-whoami examples to include OAuth

This commit is contained in:
Min RK
2017-08-17 15:53:55 +02:00
parent 5d0d552c26
commit 03bb094b90
8 changed files with 97 additions and 11 deletions

View File

@@ -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:

View File

@@ -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',
} }
},
] ]

View File

@@ -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__)

View 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

View File

@@ -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:

View File

@@ -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'],
},
] ]

View File

@@ -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'])

View File

@@ -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'])