mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-12 12:33:02 +00:00
docs review
This commit is contained in:
@@ -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
|
||||||
|
@@ -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(
|
||||||
|
@@ -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):
|
||||||
|
@@ -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.
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user