mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-12 12:33:02 +00:00
Merge pull request #2881 from minrk/auth-state-earlier
trigger auth_state_hook prior to options form, add auth_state to template namespace
This commit is contained in:
@@ -223,7 +223,7 @@ class OAuthAuthorizeHandler(OAuthHandler, BaseHandler):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
@web.authenticated
|
@web.authenticated
|
||||||
def get(self):
|
async def get(self):
|
||||||
"""GET /oauth/authorization
|
"""GET /oauth/authorization
|
||||||
|
|
||||||
Render oauth confirmation page:
|
Render oauth confirmation page:
|
||||||
@@ -251,8 +251,14 @@ class OAuthAuthorizeHandler(OAuthHandler, BaseHandler):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Render oauth 'Authorize application...' page
|
# Render oauth 'Authorize application...' page
|
||||||
|
auth_state = await self.current_user.get_auth_state()
|
||||||
self.write(
|
self.write(
|
||||||
self.render_template("oauth.html", scopes=scopes, oauth_client=client)
|
self.render_template(
|
||||||
|
"oauth.html",
|
||||||
|
auth_state=auth_state,
|
||||||
|
scopes=scopes,
|
||||||
|
oauth_client=client,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Errors that should be shown to the user on the provider website
|
# Errors that should be shown to the user on the provider website
|
||||||
|
@@ -1431,8 +1431,13 @@ class UserUrlHandler(BaseHandler):
|
|||||||
url_path_join(self.hub.base_url, "spawn", user.escaped_name, server_name),
|
url_path_join(self.hub.base_url, "spawn", user.escaped_name, server_name),
|
||||||
{"next": self.request.uri},
|
{"next": self.request.uri},
|
||||||
)
|
)
|
||||||
|
auth_state = await user.get_auth_state()
|
||||||
html = self.render_template(
|
html = self.render_template(
|
||||||
"not_running.html", user=user, server_name=server_name, spawn_url=spawn_url
|
"not_running.html",
|
||||||
|
user=user,
|
||||||
|
server_name=server_name,
|
||||||
|
spawn_url=spawn_url,
|
||||||
|
auth_state=auth_state,
|
||||||
)
|
)
|
||||||
self.finish(html)
|
self.finish(html)
|
||||||
|
|
||||||
|
@@ -68,10 +68,9 @@ class HomeHandler(BaseHandler):
|
|||||||
url = url_path_join(self.hub.base_url, 'spawn', user.escaped_name)
|
url = url_path_join(self.hub.base_url, 'spawn', user.escaped_name)
|
||||||
|
|
||||||
auth_state = await user.get_auth_state()
|
auth_state = await user.get_auth_state()
|
||||||
user.spawner.run_auth_state_hook(auth_state)
|
|
||||||
|
|
||||||
html = self.render_template(
|
html = self.render_template(
|
||||||
'home.html',
|
'home.html',
|
||||||
|
auth_state=auth_state,
|
||||||
user=user,
|
user=user,
|
||||||
url=url,
|
url=url,
|
||||||
allow_named_servers=self.allow_named_servers,
|
allow_named_servers=self.allow_named_servers,
|
||||||
@@ -94,10 +93,12 @@ class SpawnHandler(BaseHandler):
|
|||||||
|
|
||||||
default_url = None
|
default_url = None
|
||||||
|
|
||||||
def _render_form(self, for_user, spawner_options_form, message=''):
|
async def _render_form(self, for_user, spawner_options_form, message=''):
|
||||||
|
auth_state = await for_user.get_auth_state()
|
||||||
return self.render_template(
|
return self.render_template(
|
||||||
'spawn.html',
|
'spawn.html',
|
||||||
for_user=for_user,
|
for_user=for_user,
|
||||||
|
auth_state=auth_state,
|
||||||
spawner_options_form=spawner_options_form,
|
spawner_options_form=spawner_options_form,
|
||||||
error_message=message,
|
error_message=message,
|
||||||
url=self.request.uri,
|
url=self.request.uri,
|
||||||
@@ -149,6 +150,7 @@ class SpawnHandler(BaseHandler):
|
|||||||
server_name = ''
|
server_name = ''
|
||||||
|
|
||||||
spawner = user.spawners[server_name]
|
spawner = user.spawners[server_name]
|
||||||
|
|
||||||
# resolve `?next=...`, falling back on the spawn-pending url
|
# resolve `?next=...`, falling back on the spawn-pending url
|
||||||
# must not be /user/server for named servers,
|
# must not be /user/server for named servers,
|
||||||
# which may get handled by the default server if they aren't ready yet
|
# which may get handled by the default server if they aren't ready yet
|
||||||
@@ -175,10 +177,16 @@ class SpawnHandler(BaseHandler):
|
|||||||
|
|
||||||
# Add handler to spawner here so you can access query params in form rendering.
|
# Add handler to spawner here so you can access query params in form rendering.
|
||||||
spawner.handler = self
|
spawner.handler = self
|
||||||
|
|
||||||
|
# auth_state may be an input to options form,
|
||||||
|
# so resolve the auth state hook here
|
||||||
|
auth_state = await user.get_auth_state()
|
||||||
|
await spawner.run_auth_state_hook(auth_state)
|
||||||
|
|
||||||
spawner_options_form = await spawner.get_options_form()
|
spawner_options_form = await spawner.get_options_form()
|
||||||
if spawner_options_form:
|
if spawner_options_form:
|
||||||
self.log.debug("Serving options form for %s", spawner._log_name)
|
self.log.debug("Serving options form for %s", spawner._log_name)
|
||||||
form = self._render_form(
|
form = await self._render_form(
|
||||||
for_user=user, spawner_options_form=spawner_options_form
|
for_user=user, spawner_options_form=spawner_options_form
|
||||||
)
|
)
|
||||||
self.finish(form)
|
self.finish(form)
|
||||||
@@ -240,7 +248,7 @@ class SpawnHandler(BaseHandler):
|
|||||||
"Failed to spawn single-user server with form", exc_info=True
|
"Failed to spawn single-user server with form", exc_info=True
|
||||||
)
|
)
|
||||||
spawner_options_form = await user.spawner.get_options_form()
|
spawner_options_form = await user.spawner.get_options_form()
|
||||||
form = self._render_form(
|
form = await self._render_form(
|
||||||
for_user=user, spawner_options_form=spawner_options_form, message=str(e)
|
for_user=user, spawner_options_form=spawner_options_form, message=str(e)
|
||||||
)
|
)
|
||||||
self.finish(form)
|
self.finish(form)
|
||||||
@@ -301,6 +309,8 @@ class SpawnPendingHandler(BaseHandler):
|
|||||||
# if spawning fails for any reason, point users to /hub/home to retry
|
# if spawning fails for any reason, point users to /hub/home to retry
|
||||||
self.extra_error_html = self.spawn_home_error
|
self.extra_error_html = self.spawn_home_error
|
||||||
|
|
||||||
|
auth_state = await user.get_auth_state()
|
||||||
|
|
||||||
# First, check for previous failure.
|
# First, check for previous failure.
|
||||||
if (
|
if (
|
||||||
not spawner.active
|
not spawner.active
|
||||||
@@ -320,6 +330,7 @@ class SpawnPendingHandler(BaseHandler):
|
|||||||
html = self.render_template(
|
html = self.render_template(
|
||||||
"not_running.html",
|
"not_running.html",
|
||||||
user=user,
|
user=user,
|
||||||
|
auth_state=auth_state,
|
||||||
server_name=server_name,
|
server_name=server_name,
|
||||||
spawn_url=spawn_url,
|
spawn_url=spawn_url,
|
||||||
failed=True,
|
failed=True,
|
||||||
@@ -341,7 +352,11 @@ class SpawnPendingHandler(BaseHandler):
|
|||||||
else:
|
else:
|
||||||
page = "spawn_pending.html"
|
page = "spawn_pending.html"
|
||||||
html = self.render_template(
|
html = self.render_template(
|
||||||
page, user=user, spawner=spawner, progress_url=spawner._progress_url
|
page,
|
||||||
|
user=user,
|
||||||
|
spawner=spawner,
|
||||||
|
progress_url=spawner._progress_url,
|
||||||
|
auth_state=auth_state,
|
||||||
)
|
)
|
||||||
self.finish(html)
|
self.finish(html)
|
||||||
return
|
return
|
||||||
@@ -366,6 +381,7 @@ class SpawnPendingHandler(BaseHandler):
|
|||||||
html = self.render_template(
|
html = self.render_template(
|
||||||
"not_running.html",
|
"not_running.html",
|
||||||
user=user,
|
user=user,
|
||||||
|
auth_state=auth_state,
|
||||||
server_name=server_name,
|
server_name=server_name,
|
||||||
spawn_url=spawn_url,
|
spawn_url=spawn_url,
|
||||||
)
|
)
|
||||||
@@ -385,7 +401,7 @@ class AdminHandler(BaseHandler):
|
|||||||
|
|
||||||
@web.authenticated
|
@web.authenticated
|
||||||
@admin_only
|
@admin_only
|
||||||
def get(self):
|
async def get(self):
|
||||||
available = {'name', 'admin', 'running', 'last_activity'}
|
available = {'name', 'admin', 'running', 'last_activity'}
|
||||||
default_sort = ['admin', 'name']
|
default_sort = ['admin', 'name']
|
||||||
mapping = {'running': orm.Spawner.server_id}
|
mapping = {'running': orm.Spawner.server_id}
|
||||||
@@ -434,9 +450,11 @@ class AdminHandler(BaseHandler):
|
|||||||
for u in users:
|
for u in users:
|
||||||
running.extend(s for s in u.spawners.values() if s.active)
|
running.extend(s for s in u.spawners.values() if s.active)
|
||||||
|
|
||||||
|
auth_state = await self.current_user.get_auth_state()
|
||||||
html = self.render_template(
|
html = self.render_template(
|
||||||
'admin.html',
|
'admin.html',
|
||||||
current_user=self.current_user,
|
current_user=self.current_user,
|
||||||
|
auth_state=auth_state,
|
||||||
admin_access=self.settings.get('admin_access', False),
|
admin_access=self.settings.get('admin_access', False),
|
||||||
users=users,
|
users=users,
|
||||||
running=running,
|
running=running,
|
||||||
@@ -452,7 +470,7 @@ class TokenPageHandler(BaseHandler):
|
|||||||
"""Handler for page requesting new API tokens"""
|
"""Handler for page requesting new API tokens"""
|
||||||
|
|
||||||
@web.authenticated
|
@web.authenticated
|
||||||
def get(self):
|
async def get(self):
|
||||||
never = datetime(1900, 1, 1)
|
never = datetime(1900, 1, 1)
|
||||||
|
|
||||||
user = self.current_user
|
user = self.current_user
|
||||||
@@ -521,8 +539,12 @@ class TokenPageHandler(BaseHandler):
|
|||||||
|
|
||||||
oauth_clients = sorted(oauth_clients, key=sort_key, reverse=True)
|
oauth_clients = sorted(oauth_clients, key=sort_key, reverse=True)
|
||||||
|
|
||||||
|
auth_state = await self.current_user.get_auth_state()
|
||||||
html = self.render_template(
|
html = self.render_template(
|
||||||
'token.html', api_tokens=api_tokens, oauth_clients=oauth_clients
|
'token.html',
|
||||||
|
api_tokens=api_tokens,
|
||||||
|
oauth_clients=oauth_clients,
|
||||||
|
auth_state=auth_state,
|
||||||
)
|
)
|
||||||
self.finish(html)
|
self.finish(html)
|
||||||
|
|
||||||
|
@@ -974,11 +974,11 @@ class Spawner(LoggingConfigurable):
|
|||||||
except Exception:
|
except Exception:
|
||||||
self.log.exception("post_stop_hook failed with exception: %s", self)
|
self.log.exception("post_stop_hook failed with exception: %s", self)
|
||||||
|
|
||||||
def run_auth_state_hook(self, auth_state):
|
async def run_auth_state_hook(self, auth_state):
|
||||||
"""Run the auth_state_hook if defined"""
|
"""Run the auth_state_hook if defined"""
|
||||||
if self.auth_state_hook is not None:
|
if self.auth_state_hook is not None:
|
||||||
try:
|
try:
|
||||||
return self.auth_state_hook(self, auth_state)
|
await maybe_future(self.auth_state_hook(self, auth_state))
|
||||||
except Exception:
|
except Exception:
|
||||||
self.log.exception("auth_stop_hook failed with exception: %s", self)
|
self.log.exception("auth_stop_hook failed with exception: %s", self)
|
||||||
|
|
||||||
|
@@ -530,12 +530,17 @@ class User:
|
|||||||
# trigger pre-spawn hook on authenticator
|
# trigger pre-spawn hook on authenticator
|
||||||
authenticator = self.authenticator
|
authenticator = self.authenticator
|
||||||
try:
|
try:
|
||||||
|
spawner._start_pending = True
|
||||||
|
|
||||||
if authenticator:
|
if authenticator:
|
||||||
# pre_spawn_start can thow errors that can lead to a redirect loop
|
# pre_spawn_start can thow errors that can lead to a redirect loop
|
||||||
# if left uncaught (see https://github.com/jupyterhub/jupyterhub/issues/2683)
|
# if left uncaught (see https://github.com/jupyterhub/jupyterhub/issues/2683)
|
||||||
await maybe_future(authenticator.pre_spawn_start(self, spawner))
|
await maybe_future(authenticator.pre_spawn_start(self, spawner))
|
||||||
|
|
||||||
spawner._start_pending = True
|
# trigger auth_state hook
|
||||||
|
auth_state = await self.get_auth_state()
|
||||||
|
await spawner.run_auth_state_hook(auth_state)
|
||||||
|
|
||||||
# update spawner start time, and activity for both spawner and user
|
# update spawner start time, and activity for both spawner and user
|
||||||
self.last_activity = (
|
self.last_activity = (
|
||||||
spawner.orm_spawner.started
|
spawner.orm_spawner.started
|
||||||
|
Reference in New Issue
Block a user