clarify docstrings, comments in refresh_user

- refresh_user may return True in the common case, identifying that everything is up-to-date
- return False for "needs login"
- return auth_data dict when an update can be performed without logging in again
This commit is contained in:
Min RK
2018-09-13 10:28:10 +02:00
parent d79a99323e
commit ce9d9fd26d
2 changed files with 46 additions and 21 deletions

View File

@@ -300,21 +300,27 @@ class Authenticator(LoggingConfigurable):
Args: Args:
user (User): the user to refresh user (User): the user to refresh
Returns: Returns:
auth_data (dict or None): auth_data (bool or dict):
The same return value as `.authenticate`. Return **True** if auth data for the user is up-to-date
Any values here will refresh the value and no updates are required.
for the user.
This can include updating `.admin` fields Return **False** if the user's auth data has expired,
or updating `.auth_state`.
Return None if the user's auth data has expired,
and they should be required to login again. and they should be required to login again.
Return a **dict** of auth data if some values should be updated.
This dict should have the same structure as that returned
by :meth:`.authenticate()` when it returns a dict.
Any fields present will refresh the value for the user.
Any fields not present will be left unchanged.
This can include updating `.admin` or `.auth_state` fields.
""" """
return {'name': user.name} return True
async def authenticate(self, handler, data): async def authenticate(self, handler, data):
"""Authenticate a user with login form data """Authenticate a user with login form data
This must be a tornado gen.coroutine. This must be a coroutine.
It must return the username on successful authentication, It must return the username on successful authentication,
and return None on failed authentication. and return None on failed authentication.
@@ -328,12 +334,14 @@ class Authenticator(LoggingConfigurable):
data (dict): The formdata of the login form. data (dict): The formdata of the login form.
The default form has 'username' and 'password' fields. The default form has 'username' and 'password' fields.
Returns: Returns:
user (str or dict or None): The username of the authenticated user, user (str or dict or None):
The username of the authenticated user,
or None if Authentication failed. or None if Authentication failed.
The Authenticator may return a dict instead, which MUST have a The Authenticator may return a dict instead, which MUST have a
key 'name' holding the username, and may have two optional keys key `name` holding the username, and MAY have two optional keys
set - 'auth_state', a dictionary of of auth state that will be set: `auth_state`, a dictionary of of auth state that will be
persisted; and 'admin', the admin setting value for the user. persisted; and `admin`, the admin setting value for the user.
""" """
def pre_spawn_start(self, user, spawner): def pre_spawn_start(self, user, spawner):

View File

@@ -54,8 +54,14 @@ class BaseHandler(RequestHandler):
async def prepare(self): async def prepare(self):
"""Identify the user during the prepare stage of each request """Identify the user during the prepare stage of each request
During requests, the current user may be retrieved via `.prepare()` runs prior to all handler methods,
self.current_user e.g. `.get()`, `.post()`.
Checking here allows `.get_current_user` to be async without requiring
every current user check to be made async.
The current user (None if not logged in) may be accessed
via the `self.current_user` property during the handling of any request.
""" """
try: try:
await self.get_current_user() await self.get_current_user()
@@ -234,7 +240,8 @@ class BaseHandler(RequestHandler):
user (User): the user whose auth info is to be refreshed user (User): the user whose auth info is to be refreshed
force (bool): force a refresh instead of checking last refresh time force (bool): force a refresh instead of checking last refresh time
Returns: Returns:
user (User): the user having been refreshed, or None if user (User): the user having been refreshed,
or None if the user must login again to refresh auth info.
""" """
if not force: # TODO: and it's sufficiently recent if not force: # TODO: and it's sufficiently recent
return user return user
@@ -249,15 +256,25 @@ class BaseHandler(RequestHandler):
self.log.debug("Refreshing auth for %s", user.name) self.log.debug("Refreshing auth for %s", user.name)
auth_info = await self.authenticator.refresh_user(user) auth_info = await self.authenticator.refresh_user(user)
if auth_info is None:
self.log.warning("User %s has stale auth info. Login required to refresh.", user.name) if not auth_info:
self.log.warning(
"User %s has stale auth info. Login is required to refresh.",
user.name,
)
return return
if isinstance(auth_info, str): if auth_info == True:
auth_info = {'name': auth_info} # refresh_user confirmed that it's up-to-date,
# nothing to refresh
return user
# Ensure name field is set. It cannot be updated.
auth_info['name'] = user.name
if 'auth_state' not in auth_info: if 'auth_state' not in auth_info:
# refresh didn't specify auth_state, # refresh didn't specify auth_state,
# so preserve previous value to avoid clearing # so preserve previous value to avoid clearing it
auth_info['auth_state'] = await user.get_auth_state() auth_info['auth_state'] = await user.get_auth_state()
return await self.auth_to_user(auth_info, user) return await self.auth_to_user(auth_info, user)