docs review

This commit is contained in:
Min RK
2016-10-26 10:22:54 +02:00
parent 85c040ab8e
commit fd4a04e3f3
4 changed files with 56 additions and 23 deletions

View File

@@ -80,11 +80,13 @@ environment needed to start the process:
The Hub will pass the following environment variables to launch the Service: The Hub will pass the following environment variables to launch the Service:
``` ```
JUPYTERHUB_SERVICE_NAME: the name of the service JUPYTERHUB_SERVICE_NAME: The name of the service
JUPYTERHUB_API_TOKEN: API token assigned to the service JUPYTERHUB_API_TOKEN: API token assigned to the service
JUPYTERHUB_API_URL: URL for the JupyterHub API (default, http://127.0.0.1:8080/hub/api) JUPYTERHUB_API_URL: URL for the JupyterHub API (default, http://127.0.0.1:8080/hub/api)
JUPYTERHUB_BASE_URL: Base URL of the Hub (https://mydomain[:port]/) JUPYTERHUB_BASE_URL: Base URL of the Hub (https://mydomain[:port]/)
JUPYTERHUB_SERVICE_PREFIX: URL path prefix of this service (/services/:service-name/) JUPYTERHUB_SERVICE_PREFIX: URL path prefix of this service (/services/:service-name/)
JUPYTERHUB_SERVICE_URL: Local URL where the service is expected to be listening.
Only for proxied web services.
``` ```
For the previous example, these environment variables would be passed when For the previous example, these environment variables would be passed when
@@ -121,6 +123,8 @@ c.JupyterHub.services = [
] ]
``` ```
In this case, the `url` field will be passed along to the service as `JUPYTERHUB_SERVICE_URL`.
## Writing your own services ## Writing your own services
@@ -128,13 +132,19 @@ When writing your own services, you have a few decisions to make (in addition to
1. Does my service need a public URL? 1. Does my service need a public URL?
2. Do I want JupyterHub to start/stop the service? 2. Do I want JupyterHub to start/stop the service?
3. Does my service need authentication? 3. Does my service need to authenticate users?
When a service is managed by JupyterHub, When a service is managed by JupyterHub,
the Hub will pass the necessary information to the service via environment variables described above. the Hub will pass the necessary information to the service via environment variables described above.
To make your service most flexible, you can use these same environment variables, To make your service most flexible, you can use these same environment variables,
whether your service is managed by the Hub or not. whether your service is managed by the Hub or not.
When a service is managed by JupyterHub,
the Hub will define the environment variables, as described above,
and pass the information as needed to the service.
A flexible service, whether managed by the Hub or not,
can make use of these same environment variables.
When you run a service that has a url, it will be accessible under a `/services/` prefix, such as `https://myhub.horse/services/my-service/`. When you run a service that has a url, it will be accessible under a `/services/` prefix, such as `https://myhub.horse/services/my-service/`.
For your service to route proxied requests properly, it must take `JUPYTERHUB_SERVICE_PREFIX` into account when routing requests. For your service to route proxied requests properly, it must take `JUPYTERHUB_SERVICE_PREFIX` into account when routing requests.
For example, a web service would normally service its root handler at `'/'`, For example, a web service would normally service its root handler at `'/'`,
@@ -144,22 +154,24 @@ but the proxied service would need to serve `JUPYTERHUB_SERVICE_PREFIX + '/'`.
### Authenticating with the Hub ### Authenticating with the Hub
JupyterHub 0.7 introduces some utilities for using the Hub's authentication mechanism to govern access to your service. JupyterHub 0.7 introduces some utilities for using the Hub's authentication mechanism to govern access to your service.
When a user logs into JupyterHub, the Hub sets a cookie (`jupyterhub-services`) that your service can use to authenticate requests. When a user logs into JupyterHub, the Hub sets a cookie (`jupyterhub-services`).
The service can use this cookie to authenticate requests.
JupyterHub ships with a reference implementation of Hub authentication, JupyterHub ships with a reference implementation of Hub authentication that can be used by services.
but you can read on to find details of the process if you plan to implement your own hub-authenticating clients. You may go beyond this reference implementation and create custom hub-authenticating clients and services.
We describe the process below.
The base implementation is the [`HubAuth`][HubAuth] class, The reference, or base, implementation is the [`HubAuth`][HubAuth] class,
which implements the requests to the Hub. which implements the requests to the Hub.
To use HubAuth, you must set the `.api_token`, either when constructing the class, To use HubAuth, you must set the `.api_token`, either programmatically when constructing the class,
or via the `JUPYTERHUB_API_TOKEN` environment variable. or via the `JUPYTERHUB_API_TOKEN` environment variable.
Most of the implementation is in the [`HubAuth.user_for_cookie`][user_for_cookie] method, Most of the logic for authentication implementation is found in the [`HubAuth.user_for_cookie`][user_for_cookie] method,
which makes a request of the Hub, and returns: which makes a request of the Hub, and returns:
- None if no user could be identified - None, if no user could be identified
- a dict of the form: - a dict of the following form:
```python ```python
{ {
@@ -167,14 +179,17 @@ which makes a request of the Hub, and returns:
"groups": ["list", "of", "groups"], "groups": ["list", "of", "groups"],
"admin": False, # or True "admin": False, # or True
} }
```
You are then free to use that user information to take appropriate action. You are then free to use that user information to take appropriate action.
HubAuth also caches the responses from the Hub for a number of seconds, governed by `cookie_cache_max_age` (default: five minutes). HubAuth also caches the Hub responses for a number of seconds,
configurable by the `cookie_cache_max_age`` setting (default: five minutes).
#### Flask Example #### Flask Example
For example, you can use HubAuth to authenticate requests to a flask service: For example, you have a Flask service that returns information about a user.
JupyterHub's HubAuth class can be used to authenticate requests to the Flask service.
See the `service-whoami-flask` example in the JupyterHub repo for more details. See the `service-whoami-flask` example in the JupyterHub repo for more details.
```python ```python
@@ -227,7 +242,7 @@ def whoami(user):
#### Authenticating tornado services with JupyterHub #### Authenticating tornado services with JupyterHub
Since most Jupyter services are written with tornado, Since most Jupyter services are written with tornado,
we include a mixin, [`HubAuthenticated`][HubAuthenticated], we include a mixin class, [`HubAuthenticated`][HubAuthenticated],
for quickly authenticating your own tornado services with JupyterHub. for quickly authenticating your own tornado services with JupyterHub.
Tornado's `@web.authenticated` method calls a Handler's `.get_current_user` method Tornado's `@web.authenticated` method calls a Handler's `.get_current_user` method
@@ -249,25 +264,40 @@ class MyHandler(HubAuthenticated, web.RequestHandler):
The HubAuth will automatically load the desired configuration from the service environment variables. The HubAuth will automatically load the desired configuration from the service environment variables.
If you want to limit user access, you can specify either the `.hub_users` attribute or `.hub_groups`. If you want to limit user access, you can whitelist users through either the `.hub_users` attribute or `.hub_groups`.
These are sets that check against the username and user group list, respectively. These are sets that check against the username and user group list, respectively.
If a user matches neither the user list nor the group list, they will not be allowed access. If a user matches neither the user list nor the group list, they will not be allowed access.
If these are left undefined, then any user will be allowed. If both are left undefined, then any user will be allowed.
#### Implementing your own Authentication with JupyterHub #### Implementing your own Authentication with JupyterHub
If you don't want to use the reference implementation If you don't want to use the reference implementation
(e.g. you find the implementation a poor fit for your flask app), (e.g. you find the implementation a poor fit for your Flask app),
you can implement authentication via the Hub yourself. you can implement authentication via the Hub yourself.
We recommend looking at the [`HubAuth`][HubAuth] implementation for reference, We recommend looking at the [`HubAuth`][HubAuth] class implementation for reference,
but this is the process: and taking note of the following process:
1. retrieve the cookie `jupyterhub-services` from the request. 1. retrieve the cookie `jupyterhub-services` from the request.
2. Make an API request `GET /hub/api/authorizations/cookie/jupyterhub-services/cookie-value`, 2. Make an API request `GET /hub/api/authorizations/cookie/jupyterhub-services/cookie-value`,
where cookie-value is the url-encoded value of the `jupyterhub-services` cookie. where cookie-value is the url-encoded value of the `jupyterhub-services` cookie.
This request must be authenticated with a Hub API token in the `Authorization` header. This request must be authenticated with a Hub API token in the `Authorization` header.
For example For example, with [requests][]:
```python
r = requests.get(
'/'/join((["http://127.0.0.1:8081/hub/api",
"authorizations/cookie/jupyterhub-services",
quote(encrypted_cookie, safe=''),
]),
headers = {
'Authorization' : 'token %s' % api_token,
},
)
r.raise_for_status()
user = r.json()
```
3. On success, the reply will be a JSON model describing the user: 3. On success, the reply will be a JSON model describing the user:
```json ```json
@@ -279,7 +309,7 @@ but this is the process:
``` ```
[requests]: http://docs.python-requests.org
[services_auth]: api/services.auth.html [services_auth]: api/services.auth.html
[HubAuth]: api/services.auth.html#jupyterhub.services.auth.HubAuth [HubAuth]: api/services.auth.html#jupyterhub.services.auth.HubAuth
[HubAuthenticated]: api/services.auth.html#jupyterhub.services.auth.HubAuthenticated [HubAuthenticated]: api/services.auth.html#jupyterhub.services.auth.HubAuthenticated

View File

@@ -12,6 +12,7 @@ from flask import Flask, redirect, request, Response
from jupyterhub.services.auth import HubAuth from jupyterhub.services.auth import HubAuth
prefix = os.environ.get('JUPYTERHUB_SERVICE_PREFIX', '/') prefix = os.environ.get('JUPYTERHUB_SERVICE_PREFIX', '/')
auth = HubAuth( auth = HubAuth(

View File

@@ -1,6 +1,8 @@
"""An example service authenticating with the Hub. """An example service authenticating with the Hub.
This serves `/services/whoami/`, authenticated with the Hub, showing the user their own info. This example service service serves `/services/whoami/`,
authenticated with the Hub,
showing the user their own info.
""" """
from getpass import getuser from getpass import getuser
import json import json
@@ -15,7 +17,7 @@ from jupyterhub.services.auth import HubAuthenticated
class WhoAmIHandler(HubAuthenticated, RequestHandler): class WhoAmIHandler(HubAuthenticated, RequestHandler):
hub_users = {getuser()} # the users allowed to access me hub_users = {getuser()} # the users allowed to access this service
@authenticated @authenticated
def get(self): def get(self):

View File

@@ -227,7 +227,7 @@ class HubAuthenticated(object):
- .hub_auth: A HubAuth instance - .hub_auth: A HubAuth instance
- .hub_users: A set of usernames to allow. - .hub_users: A set of usernames to allow.
If left unspecified or None, username will note be checked. If left unspecified or None, username will not be checked.
- .hub_groups: A set of group names to allow. - .hub_groups: A set of group names to allow.
If left unspecified or None, groups will not be checked. If left unspecified or None, groups will not be checked.