mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-13 13:03:01 +00:00
update docs for allow_all, allow_existing_users
This commit is contained in:
@@ -37,14 +37,14 @@ A [generic implementation](https://github.com/jupyterhub/oauthenticator/blob/mas
|
|||||||
## The Dummy Authenticator
|
## The Dummy Authenticator
|
||||||
|
|
||||||
When testing, it may be helpful to use the
|
When testing, it may be helpful to use the
|
||||||
{class}`jupyterhub.auth.DummyAuthenticator`. This allows for any username and
|
{class}`~.jupyterhub.auth.DummyAuthenticator`. This allows for any username and
|
||||||
password unless if a global password has been set. Once set, any username will
|
password unless a global password has been set. Once set, any username will
|
||||||
still be accepted but the correct password will need to be provided.
|
still be accepted but the correct password will need to be provided.
|
||||||
|
|
||||||
## Additional Authenticators
|
## Additional Authenticators
|
||||||
|
|
||||||
A partial list of other authenticators is available on the
|
Additional authenticators can be found on GitHub
|
||||||
[JupyterHub wiki](https://github.com/jupyterhub/jupyterhub/wiki/Authenticators).
|
by searching for [topic:jupyterhub topic:authenticator](https://github.com/search?q=topic%3Ajupyterhub%20topic%3Aauthenticator&type=repositories).
|
||||||
|
|
||||||
## Technical Overview of Authentication
|
## Technical Overview of Authentication
|
||||||
|
|
||||||
@@ -54,9 +54,9 @@ The base authenticator uses simple username and password authentication.
|
|||||||
|
|
||||||
The base Authenticator has one central method:
|
The base Authenticator has one central method:
|
||||||
|
|
||||||
#### Authenticator.authenticate method
|
#### Authenticator.authenticate
|
||||||
|
|
||||||
Authenticator.authenticate(handler, data)
|
{meth}`.Authenticator.authenticate`
|
||||||
|
|
||||||
This method is passed the Tornado `RequestHandler` and the `POST data`
|
This method is passed the Tornado `RequestHandler` and the `POST data`
|
||||||
from JupyterHub's login form. Unless the login form has been customized,
|
from JupyterHub's login form. Unless the login form has been customized,
|
||||||
@@ -81,7 +81,7 @@ Writing an Authenticator that looks up passwords in a dictionary
|
|||||||
requires only overriding this one method:
|
requires only overriding this one method:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from IPython.utils.traitlets import Dict
|
from traitlets import Dict
|
||||||
from jupyterhub.auth import Authenticator
|
from jupyterhub.auth import Authenticator
|
||||||
|
|
||||||
class DictionaryAuthenticator(Authenticator):
|
class DictionaryAuthenticator(Authenticator):
|
||||||
@@ -136,7 +136,7 @@ To only allow usernames that start with 'w':
|
|||||||
c.Authenticator.username_pattern = r'w.*'
|
c.Authenticator.username_pattern = r'w.*'
|
||||||
```
|
```
|
||||||
|
|
||||||
### How to write a custom authenticator
|
## How to write a custom authenticator
|
||||||
|
|
||||||
You can use custom Authenticator subclasses to enable authentication
|
You can use custom Authenticator subclasses to enable authentication
|
||||||
via other mechanisms. One such example is using [GitHub OAuth][].
|
via other mechanisms. One such example is using [GitHub OAuth][].
|
||||||
@@ -148,11 +148,6 @@ and {meth}`.Authenticator.post_spawn_stop`, are hooks that can be used to do
|
|||||||
auth-related startup (e.g. opening PAM sessions) and cleanup
|
auth-related startup (e.g. opening PAM sessions) and cleanup
|
||||||
(e.g. closing PAM sessions).
|
(e.g. closing PAM sessions).
|
||||||
|
|
||||||
See a list of custom Authenticators [on the wiki](https://github.com/jupyterhub/jupyterhub/wiki/Authenticators).
|
|
||||||
|
|
||||||
If you are interested in writing a custom authenticator, you can read
|
|
||||||
[this tutorial](http://jupyterhub-tutorial.readthedocs.io/en/latest/authenticators.html).
|
|
||||||
|
|
||||||
### Registering custom Authenticators via entry points
|
### Registering custom Authenticators via entry points
|
||||||
|
|
||||||
As of JupyterHub 1.0, custom authenticators can register themselves via
|
As of JupyterHub 1.0, custom authenticators can register themselves via
|
||||||
@@ -188,6 +183,104 @@ Additionally, configurable attributes for your authenticator will
|
|||||||
appear in jupyterhub help output and auto-generated configuration files
|
appear in jupyterhub help output and auto-generated configuration files
|
||||||
via `jupyterhub --generate-config`.
|
via `jupyterhub --generate-config`.
|
||||||
|
|
||||||
|
(authenticator-allow)=
|
||||||
|
|
||||||
|
### Allowing access
|
||||||
|
|
||||||
|
When dealing with logging in, there are generally two _separate_ steps:
|
||||||
|
|
||||||
|
authentication
|
||||||
|
: identifying who is logged in, and
|
||||||
|
|
||||||
|
authorization
|
||||||
|
: deciding whether an authenticated user is logged in
|
||||||
|
|
||||||
|
{meth}`Authenticator.authenticate` is responsible for authenticating users.
|
||||||
|
It is perfectly fine in the simplest cases for `Authenticator.authenticate` to be responsible for authentication _and_ authorization,
|
||||||
|
in which case `authenticate` may return `None` if the user is not authorized.
|
||||||
|
|
||||||
|
However, Authenticators also have have two methods {meth}`~.Authenticator.check_allowed` and {meth}`~.Authenticator.check_blocked_users`, which are called after successful authentication to further check if the user is allowed.
|
||||||
|
|
||||||
|
If `check_blocked_users()` returns False, authorization stops and the user is not allowed.
|
||||||
|
|
||||||
|
If `check_allowed()` returns True, authorization proceeds.
|
||||||
|
|
||||||
|
:::{versionadded} 5.0
|
||||||
|
{attr}`Authenticator.allow_all` and {attr}`Authenticator.allow_existing_users` are new in JupyterHub 5.0.
|
||||||
|
|
||||||
|
By default, `allow_all` is True when `allowed_users` is empty,
|
||||||
|
and `allow_existing_users` is True when `allowed_users` is not empty.
|
||||||
|
This is to ensure backward-compatibility, but subclasses are free to pick more restrictive defaults.
|
||||||
|
:::
|
||||||
|
|
||||||
|
### Overriding `check_allowed`
|
||||||
|
|
||||||
|
The base implementation of {meth}`~.Authenticator.check_allowed` checks:
|
||||||
|
|
||||||
|
- if `allow_all` is True, return True
|
||||||
|
- if username is in the `allowed_users` set, return True
|
||||||
|
- else return False
|
||||||
|
|
||||||
|
If a custom Authenticator defines additional sources of `allow` configuration,
|
||||||
|
such as membership in a group or other information,
|
||||||
|
it should override `check_allowed` to account for this.
|
||||||
|
`allow_` configuration should generally be _additive_,
|
||||||
|
i.e. if permission is granted by _any_ allow configuration,
|
||||||
|
a user should be authorized.
|
||||||
|
|
||||||
|
:::{note}
|
||||||
|
For backward-compatibility, it is the responsibility of `Authenticator.check_allowed()` to check `.allow_all`.
|
||||||
|
This is to avoid the backward-compatible default values from granting permissions unexpectedly.
|
||||||
|
:::
|
||||||
|
|
||||||
|
If an Authenticator defines additional `allow` configuration, it must at least:
|
||||||
|
|
||||||
|
1. override `check_allowed`, and
|
||||||
|
2. override the default for `allow_all`
|
||||||
|
|
||||||
|
The default for `allow_all` in a custom authenticator should be one of `False` or a dynamic default matching something like `if not any allow configuration specified`.
|
||||||
|
False is recommended for authenticators which source much larger pools of users than are _typically_ allowed to access a Hub (e.g. generic OAuth providers like Google, GitHub, etc.).
|
||||||
|
|
||||||
|
For example, here is how `PAMAuthenticator` extends the base class to add `allowed_groups`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from traitlets import default
|
||||||
|
|
||||||
|
@default("allow_all")
|
||||||
|
def _allow_all_default(self):
|
||||||
|
if self.allowed_users or self.allowed_groups:
|
||||||
|
# if any allow config is specified, default to False
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def check_allowed(self, username, authentication=None):
|
||||||
|
if self.allow_all:
|
||||||
|
return True
|
||||||
|
if self.check_allowed_groups(username, authentication):
|
||||||
|
return True
|
||||||
|
return super().check_allowed(username, authentication)
|
||||||
|
```
|
||||||
|
|
||||||
|
Important points to note:
|
||||||
|
|
||||||
|
- overriding the default for `allow_all` is required to avoid `allow_all` being True when `allowed_groups` is specified, but `allowed_users` is not.
|
||||||
|
- `allow_all` must be checked inside `check_allowed`
|
||||||
|
- `allowed_groups` strictly expands who is authorized,
|
||||||
|
it does not apply restrictions `allowed_users`.
|
||||||
|
This is recommended for all `allow_` configuration added by Authenticators.
|
||||||
|
|
||||||
|
#### Custom error messages
|
||||||
|
|
||||||
|
Any of these authentication and authorization methods may
|
||||||
|
|
||||||
|
```python
|
||||||
|
from tornado import web
|
||||||
|
|
||||||
|
raise web.HTTPError(403, "informative message")
|
||||||
|
```
|
||||||
|
|
||||||
|
if you want to show a more informative login failure message rather than the generic one.
|
||||||
|
|
||||||
(authenticator-auth-state)=
|
(authenticator-auth-state)=
|
||||||
|
|
||||||
### Authentication state
|
### Authentication state
|
||||||
|
@@ -13,15 +13,25 @@ You can restrict which users are allowed to login with a set,
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
c.Authenticator.allowed_users = {'mal', 'zoe', 'inara', 'kaylee'}
|
c.Authenticator.allowed_users = {'mal', 'zoe', 'inara', 'kaylee'}
|
||||||
|
c.Authenticator.allow_all = False
|
||||||
|
c.Authenticator.allow_existing_users = False
|
||||||
```
|
```
|
||||||
|
|
||||||
Users in the `allowed_users` set are added to the Hub database when the Hub is
|
Users in the `allowed_users` set are added to the Hub database when the Hub is started.
|
||||||
started.
|
|
||||||
|
|
||||||
```{warning}
|
```{warning}
|
||||||
If this configuration value is not set, then **all authenticated users will be allowed into your hub**.
|
If `allowed_users` is not specified, then by default **all authenticated users will be allowed into your hub**,
|
||||||
|
i.e. `allow_all` defaults to True if neither `allowed_users` nor `allow_all` are set.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
:::{versionadded} 5.0
|
||||||
|
{attr}`Authenticator.allow_all` and {attr}`Authenticator.allow_existing_users` are new in JupyterHub 5.0.
|
||||||
|
|
||||||
|
By default, `allow_all` is True when `allowed_users` is empty,
|
||||||
|
and `allow_existing_users` is True when `allowed_users` is not empty.
|
||||||
|
This is to ensure backward-compatibility.
|
||||||
|
:::
|
||||||
|
|
||||||
## One Time Passwords ( request_otp )
|
## One Time Passwords ( request_otp )
|
||||||
|
|
||||||
By setting `request_otp` to true, the login screen will show and additional password input field
|
By setting `request_otp` to true, the login screen will show and additional password input field
|
||||||
@@ -42,7 +52,7 @@ c.Authenticator.otp_prompt = 'Google Authenticator:'
|
|||||||
```{note}
|
```{note}
|
||||||
As of JupyterHub 2.0, the full permissions of `admin_users`
|
As of JupyterHub 2.0, the full permissions of `admin_users`
|
||||||
should not be required.
|
should not be required.
|
||||||
Instead, you can assign [roles](define-role-target) to users or groups
|
Instead, it is best to assign [roles](define-role-target) to users or groups
|
||||||
with only the scopes they require.
|
with only the scopes they require.
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -68,26 +78,49 @@ group. For example, we can let any user in the `wheel` group be an admin:
|
|||||||
c.PAMAuthenticator.admin_groups = {'wheel'}
|
c.PAMAuthenticator.admin_groups = {'wheel'}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Give admin access to other users' notebook servers (`admin_access`)
|
## Give some users access to other users' notebook servers
|
||||||
|
|
||||||
Since the default `JupyterHub.admin_access` setting is `False`, the admins
|
The `access:servers` scope can be granted to users to give them permission to visit other users' servers.
|
||||||
do not have permission to log in to the single user notebook servers
|
For example, to give members of the `teachers` group access to the servers of members of the `students` group:
|
||||||
owned by _other users_. If `JupyterHub.admin_access` is set to `True`,
|
|
||||||
then admins have permission to log in _as other users_ on their
|
```python
|
||||||
respective machines for debugging. **As a courtesy, you should make
|
c.JupyterHub.load_roles = [
|
||||||
sure your users know if admin_access is enabled.**
|
{
|
||||||
|
"name": "teachers",
|
||||||
|
"scopes": [
|
||||||
|
"admin-ui",
|
||||||
|
"list:users",
|
||||||
|
"access:servers!group=students",
|
||||||
|
],
|
||||||
|
"groups": ["teachers"],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
By default, only the deprecated `admin` role has global `access` permissions.
|
||||||
|
**As a courtesy, you should make sure your users know if admin access is enabled.**
|
||||||
|
|
||||||
## Add or remove users from the Hub
|
## Add or remove users from the Hub
|
||||||
|
|
||||||
Users can be added to and removed from the Hub via the admin
|
Users can be added to and removed from the Hub via the admin
|
||||||
panel or the REST API. When a user is **added**, the user will be
|
panel or the REST API.
|
||||||
automatically added to the `allowed_users` set and database. Restarting the Hub
|
|
||||||
will not require manually updating the `allowed_users` set in your config file,
|
To enable this behavior, set:
|
||||||
|
|
||||||
|
```python
|
||||||
|
c.Authenticator.allow_existing_users = True
|
||||||
|
```
|
||||||
|
|
||||||
|
When a user is **added**, the user will be
|
||||||
|
automatically added to the `allowed_users` set and database.
|
||||||
|
If `allow_existing_users` is True, restarting the Hub will not require manually updating the `allowed_users` set in your config file,
|
||||||
as the users will be loaded from the database.
|
as the users will be loaded from the database.
|
||||||
|
If `allow_existing_users` is False, users not granted access by configuration such as `allowed_users` will not be permitted to login,
|
||||||
|
even if they are present in the database.
|
||||||
|
|
||||||
After starting the Hub once, it is not sufficient to **remove** a user
|
After starting the Hub once, it is not sufficient to **remove** a user
|
||||||
from the allowed users set in your config file. You must also remove the user
|
from the allowed users set in your config file. You must also remove the user
|
||||||
from the Hub's database, either by deleting the user from JupyterHub's
|
from the Hub's database, either by deleting the user via JupyterHub's
|
||||||
admin page, or you can clear the `jupyterhub.sqlite` database and start
|
admin page, or you can clear the `jupyterhub.sqlite` database and start
|
||||||
fresh.
|
fresh.
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user