Notify auth providers on logout

Provide a hook by which auth providers can be notified of logouts.
This commit is contained in:
Richard van der Hoff 2017-11-01 15:42:38 +00:00
parent 846a94fbc9
commit bc8a5c0330
3 changed files with 42 additions and 7 deletions

View File

@ -82,3 +82,13 @@ Password auth provider classes may optionally provide the following methods.
The method should return a Twisted ``Deferred`` object, which resolves to The method should return a Twisted ``Deferred`` object, which resolves to
``True`` if authentication is successful, and ``False`` if not. ``True`` if authentication is successful, and ``False`` if not.
``someprovider.on_logged_out``\(*user_id*, *device_id*, *access_token*)
This method, if implemented, is called when a user logs out. It is passed
the qualified user ID, the ID of the deactivated device (if any: access
tokens are occasionally created without an associated device ID), and the
(now deactivated) access token.
It may return a Twisted ``Deferred`` object; the logout request will wait
for the deferred to complete but the result is ignored.

View File

@ -682,6 +682,7 @@ class AuthHandler(BaseHandler):
yield self.store.user_delete_threepids(user_id) yield self.store.user_delete_threepids(user_id)
yield self.store.user_set_password_hash(user_id, None) yield self.store.user_set_password_hash(user_id, None)
@defer.inlineCallbacks
def delete_access_token(self, access_token): def delete_access_token(self, access_token):
"""Invalidate a single access token """Invalidate a single access token
@ -691,8 +692,19 @@ class AuthHandler(BaseHandler):
Returns: Returns:
Deferred Deferred
""" """
return self.store.delete_access_token(access_token) user_info = yield self.auth.get_user_by_access_token(access_token)
yield self.store.delete_access_token(access_token)
# see if any of our auth providers want to know about this
for provider in self.password_providers:
if hasattr(provider, "on_logged_out"):
yield provider.on_logged_out(
user_id=str(user_info["user"]),
device_id=user_info["device_id"],
access_token=access_token,
)
@defer.inlineCallbacks
def delete_access_tokens_for_user(self, user_id, except_token_id=None, def delete_access_tokens_for_user(self, user_id, except_token_id=None,
device_id=None): device_id=None):
"""Invalidate access tokens belonging to a user """Invalidate access tokens belonging to a user
@ -707,10 +719,20 @@ class AuthHandler(BaseHandler):
Returns: Returns:
Deferred Deferred
""" """
return self.store.user_delete_access_tokens( tokens_and_devices = yield self.store.user_delete_access_tokens(
user_id, except_token_id=except_token_id, device_id=device_id, user_id, except_token_id=except_token_id, device_id=device_id,
) )
# see if any of our auth providers want to know about this
for provider in self.password_providers:
if hasattr(provider, "on_logged_out"):
for token, device_id in tokens_and_devices:
yield provider.on_logged_out(
user_id=user_id,
device_id=device_id,
access_token=token,
)
@defer.inlineCallbacks @defer.inlineCallbacks
def add_threepid(self, user_id, medium, address, validated_at): def add_threepid(self, user_id, medium, address, validated_at):
# 'Canonicalise' email addresses down to lower case. # 'Canonicalise' email addresses down to lower case.

View File

@ -255,7 +255,8 @@ class RegistrationStore(background_updates.BackgroundUpdateStore):
If None, tokens associated with any device (or no device) will If None, tokens associated with any device (or no device) will
be deleted be deleted
Returns: Returns:
defer.Deferred: defer.Deferred[list[str, str|None]]: a list of the deleted tokens
and device IDs
""" """
def f(txn): def f(txn):
keyvalues = { keyvalues = {
@ -272,14 +273,14 @@ class RegistrationStore(background_updates.BackgroundUpdateStore):
values.append(except_token_id) values.append(except_token_id)
txn.execute( txn.execute(
"SELECT token FROM access_tokens WHERE %s" % where_clause, "SELECT token, device_id FROM access_tokens WHERE %s" % where_clause,
values values
) )
rows = self.cursor_to_dict(txn) tokens_and_devices = [(r[0], r[1]) for r in txn]
for row in rows: for token, _ in tokens_and_devices:
self._invalidate_cache_and_stream( self._invalidate_cache_and_stream(
txn, self.get_user_by_access_token, (row["token"],) txn, self.get_user_by_access_token, (token,)
) )
txn.execute( txn.execute(
@ -287,6 +288,8 @@ class RegistrationStore(background_updates.BackgroundUpdateStore):
values values
) )
return tokens_and_devices
yield self.runInteraction( yield self.runInteraction(
"user_delete_access_tokens", f, "user_delete_access_tokens", f,
) )