refine service auth docs

favor HubOAuth, as that should really be the default for most services

- Remove some outdated 'new in' text
- Remove docs for some deprecated features (hub_users, hub_groups)
- more detail on what's required
This commit is contained in:
Min RK
2021-11-30 10:48:53 +01:00
parent 7d44a0ffc8
commit db3b2d8961
2 changed files with 79 additions and 27 deletions

View File

@@ -103,6 +103,8 @@ parameters, which describe the environment needed to start the Service 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:
(service-env)=
```bash ```bash
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
@@ -184,18 +186,38 @@ extra slash you might get unexpected behavior. For example if your service has a
## Hub Authentication and Services ## Hub Authentication and Services
JupyterHub 0.7 introduces some utilities for using the Hub's authentication JupyterHub provides some utilities for using the Hub's authentication
mechanism to govern access to your service. When a user logs into JupyterHub, mechanism to govern access to your service.
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 that Requests to all JupyterHub services are made with OAuth tokens.
These can either be requests with a token in the `Authorization` header,
or url parameter `?token=...`,
or browser requests which must complete the OAuth authorization code flow,
which results in a token that should be persisted for future requests
(persistence is up to the service,
but an encrypted cookie confined to the service path is appropriate,
and provided by default).
:::{versionchanged} 2.0
The shared `jupyterhub-services` cookie is removed.
OAuth must be used to authenticate browser requests with services.
:::
JupyterHub includes a reference implementation of Hub authentication that
can be used by services. You may go beyond this reference implementation and can be used by services. You may go beyond this reference implementation and
create custom hub-authenticating clients and services. We describe the process create custom hub-authenticating clients and services. We describe the process
below. below.
The reference, or 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 API requests to the Hub that resolve a token to a User model.
There are two levels of authentication with the Hub:
- [`HubAuth`][hubauth] - the most basic authentication,
for services that should only accept API requests authorized with a token.
- [`HubOAuth`][huboauth] - For services that should use oauth to authenticate with the Hub.
This should be used for any service that serves pages that should be visited with a browser.
To use HubAuth, you must set the `.api_token`, either programmatically 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.
@@ -238,18 +260,17 @@ for more details.
### 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 class, [`HubAuthenticated`][hubauthenticated], we include a mixin class, [`HubOAuthenticated`][huboauthenticated],
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` Tornado's {py:func}`~.tornado.web.authenticated` decorator calls a Handler's {py:meth}`~.tornado.web.RequestHandler.get_current_user`
method to identify the user. Mixing in `HubAuthenticated` defines method to identify the user. Mixing in {class}`.HubAuthenticated` defines
`get_current_user` to use HubAuth. If you want to configure the HubAuth {meth}`~.HubAuthenticated.get_current_user` to use HubAuth. If you want to configure the HubAuth
instance beyond the default, you'll want to define an `initialize` method, instance beyond the default, you'll want to define an {py:meth}`~.tornado.web.RequestHandler.initialize` method,
such as: such as:
```python ```python
class MyHandler(HubAuthenticated, web.RequestHandler): class MyHandler(HubOAuthenticated, web.RequestHandler):
hub_users = {'inara', 'mal'}
def initialize(self, hub_auth): def initialize(self, hub_auth):
self.hub_auth = hub_auth self.hub_auth = hub_auth
@@ -259,14 +280,21 @@ class MyHandler(HubAuthenticated, web.RequestHandler):
... ...
``` ```
The HubAuth will automatically load the desired configuration from the Service The HubAuth class will automatically load the desired configuration from the Service
environment variables. [environment variables](service-env).
If you want to limit user access, you can specify allowed users through either the :::{versionchanged} 2.0
`.hub_users` attribute or `.hub_groups`. These are sets that check against the
username and user group list, respectively. If a user matches neither the user Access scopes are used to govern access to services.
list nor the group list, they will not be allowed access. If both are left Prior to 2.0,
undefined, then any user will be allowed. sets of users and groups could be used to grant access
by defining `.hub_groups` or `.hub_users` on the authenticated handler.
These are ignored if the 2.0 `.hub_scopes` is defined.
:::
:::{seealso}
{meth}`.HubAuth.check_scopes`
:::
### Implementing your own Authentication with JupyterHub ### Implementing your own Authentication with JupyterHub
@@ -316,7 +344,7 @@ and taking note of the following process:
```python ```python
{ {
"name": "inara", "name": "inara",
# groups may be omitted, depending on permissions # groups may be omitted, depending on permissions
"groups": ["serenity", "guild"], "groups": ["serenity", "guild"],
# scopes is new in JupyterHub 2.0 # scopes is new in JupyterHub 2.0
"scopes": [ "scopes": [
@@ -342,9 +370,11 @@ section on securing the notebook viewer.
[requests]: http://docs.python-requests.org/en/master/ [requests]: http://docs.python-requests.org/en/master/
[services_auth]: ../api/services.auth.html [services_auth]: ../api/services.auth.html
[hubauth]: ../api/services.auth.html#jupyterhub.services.auth.HubAuth
[huboauth]: ../api/services.auth.html#jupyterhub.services.auth.HubOAuth [huboauth]: ../api/services.auth.html#jupyterhub.services.auth.HubOAuth
[hubauth.user_for_token]: ../api/services.auth.html#jupyterhub.services.auth.HubAuth.user_for_token [hubauth.user_for_token]: ../api/services.auth.html#jupyterhub.services.auth.HubAuth.user_for_token
[hubauthenticated]: ../api/services.auth.html#jupyterhub.services.auth.HubAuthenticated [hubauthenticated]: ../api/services.auth.html#jupyterhub.services.auth.HubAuthenticated
[huboauthenticated]: ../api/services.auth.html#jupyterhub.services.auth.HubOAuthenticated
[nbviewer example]: https://github.com/jupyter/nbviewer#securing-the-notebook-viewer [nbviewer example]: https://github.com/jupyter/nbviewer#securing-the-notebook-viewer
[fastapi example]: https://github.com/jupyterhub/jupyterhub/tree/HEAD/examples/service-fastapi [fastapi example]: https://github.com/jupyterhub/jupyterhub/tree/HEAD/examples/service-fastapi
[fastapi]: https://fastapi.tiangolo.com [fastapi]: https://fastapi.tiangolo.com

View File

@@ -3,10 +3,24 @@
Tokens are sent to the Hub for verification. Tokens are sent to the Hub for verification.
The Hub replies with a JSON model describing the authenticated user. The Hub replies with a JSON model describing the authenticated user.
``HubAuth`` can be used in any application, even outside tornado. This contains two levels of authentication:
``HubAuthenticated`` is a mixin class for tornado handlers that should - :class:`HubOAuth` - Use OAuth 2 to authenticate browsers with the Hub.
authenticate with the Hub. This should be used for any service that should respond to browser requests
(i.e. most services).
- :class:`HubAuth` - token-only authentication, for a service that only need to handle token-authenticated API requests
The ``Auth`` classes (:class:`HubAuth`, :class:`HubOAuth`)
can be used in any application, even outside tornado.
They contain reference implementations of talking to the Hub API
to resolve a token to a user.
The ``Authenticated`` classes (:class:`HubAuthenticated`, :class:`HubOAuthenticated`)
are mixins for tornado handlers that should authenticate with the Hub.
If you are using OAuth, you will also need to register an oauth callback handler to complete the oauth process.
A tornado implementation is provided in :class:`HubOAuthCallbackHandler`.
""" """
import base64 import base64
@@ -212,6 +226,7 @@ class HubAuth(SingletonConfigurable):
help="""The base API URL of the Hub. help="""The base API URL of the Hub.
Typically `http://hub-ip:hub-port/hub/api` Typically `http://hub-ip:hub-port/hub/api`
Default: $JUPYTERHUB_API_URL
""", """,
).tag(config=True) ).tag(config=True)
@@ -227,7 +242,10 @@ class HubAuth(SingletonConfigurable):
os.getenv('JUPYTERHUB_API_TOKEN', ''), os.getenv('JUPYTERHUB_API_TOKEN', ''),
help="""API key for accessing Hub API. help="""API key for accessing Hub API.
Generate with `jupyterhub token [username]` or add to JupyterHub.services config. Default: $JUPYTERHUB_API_TOKEN
Loaded from services configuration in jupyterhub_config.
Will be auto-generated for hub-managed services.
""", """,
).tag(config=True) ).tag(config=True)
@@ -236,6 +254,7 @@ class HubAuth(SingletonConfigurable):
help="""The URL prefix for the Hub itself. help="""The URL prefix for the Hub itself.
Typically /hub/ Typically /hub/
Default: $JUPYTERHUB_BASE_URL
""", """,
).tag(config=True) ).tag(config=True)
@@ -854,8 +873,6 @@ class HubAuthenticated:
Examples:: Examples::
class MyHandler(HubAuthenticated, web.RequestHandler): class MyHandler(HubAuthenticated, web.RequestHandler):
hub_users = {'inara', 'mal'}
def initialize(self, hub_auth): def initialize(self, hub_auth):
self.hub_auth = hub_auth self.hub_auth = hub_auth
@@ -865,6 +882,7 @@ class HubAuthenticated:
""" """
# deprecated, pre-2.0 allow sets
hub_services = None # set of allowed services hub_services = None # set of allowed services
hub_users = None # set of allowed users hub_users = None # set of allowed users
hub_groups = None # set of allowed groups hub_groups = None # set of allowed groups
@@ -960,6 +978,10 @@ class HubAuthenticated:
raise UserNotAllowed(model) raise UserNotAllowed(model)
# proceed with the pre-2.0 way if hub_scopes is not set # proceed with the pre-2.0 way if hub_scopes is not set
warnings.warn(
"hub_scopes ($JUPYTERHUB not set, proceeding with pre-2.0 authentication",
DeprecationWarning,
)
if self.allow_admin and model.get('admin', False): if self.allow_admin and model.get('admin', False):
app_log.debug("Allowing Hub admin %s", name) app_log.debug("Allowing Hub admin %s", name)