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:
Min RK
2020-01-17 12:35:33 +01:00
committed by GitHub
5 changed files with 53 additions and 15 deletions

View File

@@ -223,7 +223,7 @@ class OAuthAuthorizeHandler(OAuthHandler, BaseHandler):
return True
@web.authenticated
def get(self):
async def get(self):
"""GET /oauth/authorization
Render oauth confirmation page:
@@ -251,8 +251,14 @@ class OAuthAuthorizeHandler(OAuthHandler, BaseHandler):
return
# Render oauth 'Authorize application...' page
auth_state = await self.current_user.get_auth_state()
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

View File

@@ -1431,8 +1431,13 @@ class UserUrlHandler(BaseHandler):
url_path_join(self.hub.base_url, "spawn", user.escaped_name, server_name),
{"next": self.request.uri},
)
auth_state = await user.get_auth_state()
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)

View File

@@ -68,10 +68,9 @@ class HomeHandler(BaseHandler):
url = url_path_join(self.hub.base_url, 'spawn', user.escaped_name)
auth_state = await user.get_auth_state()
user.spawner.run_auth_state_hook(auth_state)
html = self.render_template(
'home.html',
auth_state=auth_state,
user=user,
url=url,
allow_named_servers=self.allow_named_servers,
@@ -94,10 +93,12 @@ class SpawnHandler(BaseHandler):
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(
'spawn.html',
for_user=for_user,
auth_state=auth_state,
spawner_options_form=spawner_options_form,
error_message=message,
url=self.request.uri,
@@ -149,6 +150,7 @@ class SpawnHandler(BaseHandler):
server_name = ''
spawner = user.spawners[server_name]
# resolve `?next=...`, falling back on the spawn-pending url
# must not be /user/server for named servers,
# 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.
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()
if spawner_options_form:
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
)
self.finish(form)
@@ -240,7 +248,7 @@ class SpawnHandler(BaseHandler):
"Failed to spawn single-user server with form", exc_info=True
)
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)
)
self.finish(form)
@@ -301,6 +309,8 @@ class SpawnPendingHandler(BaseHandler):
# if spawning fails for any reason, point users to /hub/home to retry
self.extra_error_html = self.spawn_home_error
auth_state = await user.get_auth_state()
# First, check for previous failure.
if (
not spawner.active
@@ -320,6 +330,7 @@ class SpawnPendingHandler(BaseHandler):
html = self.render_template(
"not_running.html",
user=user,
auth_state=auth_state,
server_name=server_name,
spawn_url=spawn_url,
failed=True,
@@ -341,7 +352,11 @@ class SpawnPendingHandler(BaseHandler):
else:
page = "spawn_pending.html"
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)
return
@@ -366,6 +381,7 @@ class SpawnPendingHandler(BaseHandler):
html = self.render_template(
"not_running.html",
user=user,
auth_state=auth_state,
server_name=server_name,
spawn_url=spawn_url,
)
@@ -385,7 +401,7 @@ class AdminHandler(BaseHandler):
@web.authenticated
@admin_only
def get(self):
async def get(self):
available = {'name', 'admin', 'running', 'last_activity'}
default_sort = ['admin', 'name']
mapping = {'running': orm.Spawner.server_id}
@@ -434,9 +450,11 @@ class AdminHandler(BaseHandler):
for u in users:
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(
'admin.html',
current_user=self.current_user,
auth_state=auth_state,
admin_access=self.settings.get('admin_access', False),
users=users,
running=running,
@@ -452,7 +470,7 @@ class TokenPageHandler(BaseHandler):
"""Handler for page requesting new API tokens"""
@web.authenticated
def get(self):
async def get(self):
never = datetime(1900, 1, 1)
user = self.current_user
@@ -521,8 +539,12 @@ class TokenPageHandler(BaseHandler):
oauth_clients = sorted(oauth_clients, key=sort_key, reverse=True)
auth_state = await self.current_user.get_auth_state()
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)

View File

@@ -974,11 +974,11 @@ class Spawner(LoggingConfigurable):
except Exception:
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"""
if self.auth_state_hook is not None:
try:
return self.auth_state_hook(self, auth_state)
await maybe_future(self.auth_state_hook(self, auth_state))
except Exception:
self.log.exception("auth_stop_hook failed with exception: %s", self)

View File

@@ -530,12 +530,17 @@ class User:
# trigger pre-spawn hook on authenticator
authenticator = self.authenticator
try:
spawner._start_pending = True
if authenticator:
# pre_spawn_start can thow errors that can lead to a redirect loop
# if left uncaught (see https://github.com/jupyterhub/jupyterhub/issues/2683)
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
self.last_activity = (
spawner.orm_spawner.started