user-provided tokens are added in exactly one place,
so switch default handling of tokens to generated=True
and explicitly distrust user tokens.
Add JupyterHub.trust_user_provided_tokens flag so that users can avoid the extra hashing
if they know they are providing good keys.
fail with informative error if version mismatches
Since we weren't always tagging before,
we have to handle no tag being present:
- database empty (use latest because we are about to create everything anew)
- if 'spawners' is present, assume 0.8.dev
- if 'services' is present, assume 0.7.x
- else: assume base revision when we started tracking this stuff
privy is used for encryption
- db only has blob column, no knowledge of encryption
- add CryptKeeper for handling encryption
- use privy for encryption, so we have fewer choices to make
- storing/loading encrypted auth_state runs in a ThreadPool
- MultFernet allows key rotation via `AUTH_STATE_KEY=secret2;secret1;secret0`
- Failure to decrypt results in cleared state
- Attempting to set auth_state without encryption is a hard failure
- Absent encryption, auth_state will always be None
OAuth access tokens can only be used to identify users, not perform actions on their behalf, which API tokens do.
Implementing OAuth scopes would allow us to achieve this limitation without separating the two items, but that would be a much bigger change, including having an OAuth "Would you like to grant permissions..." confirmation page.
- OAuth access tokens *are* APITokens.
oauth_access_tokens table only stores extra oauth metadata.
- only store hashed client_secret in database,
using HashedCompare to allow comparison.
We already added running users, but we didn't handle removing users from the proxy
if the user's server was stopped (e.g. while the Hub was restarting).
service_tokens supersedes api_tokens,
since they now map to a new services collection,
rather than regular Hub usernames.
Services in the ORM have:
- API tokens
- servers (multiple, can be 0)
- pid (0 if not managed)
This is the first small part of easing the pain of services,
which is generating the API tokens,
and used to require initializing the JupyterHub database.
- Otherwise does not work with MySQL
- Change JSONDict to be TEXT (Unbounded) rather than VARCHAR.
This makes most sense, since you can't index these anyway.
- The 'ip' field in Server is set to 255, since that is the
max allowed length of DNS entries.
- Most of the rest of the Unicodes have approximately high
values that most people should not mostly run into
(famous last words).
check_routes checks for missing routes for running users.
This is meant for when the proxy has been relaunched outside the Hub.
If spawners are slow to start, it's possible for check_routes to fire in the middle of spawning,
triggering addition of the user's server (which has no defined location yet) to the proxy before it's up.
If the spawning fails, the route will remain indefinitely (because it never should have been added in the first place), and the user will see 503 until their server is launched manually again.
Checking `spawn_pending` in user.running prevents this.