summary refs log tree commit diff
diff options
context:
space:
mode:
authorRichard van der Hoff <richard@matrix.org>2017-11-01 15:42:38 +0000
committerRichard van der Hoff <richard@matrix.org>2017-11-01 16:51:51 +0000
commitbc8a5c033097f719d6b2971660ad833ab8cb3838 (patch)
treea04182e6c7ed25ce0f2362a6fd6e7427973fbd03
parentMerge pull request #2620 from matrix-org/rav/auth_non_password (diff)
downloadsynapse-bc8a5c033097f719d6b2971660ad833ab8cb3838.tar.xz
Notify auth providers on logout
Provide a hook by which auth providers can be notified of logouts.
-rw-r--r--docs/password_auth_providers.rst10
-rw-r--r--synapse/handlers/auth.py26
-rw-r--r--synapse/storage/registration.py13
3 files changed, 42 insertions, 7 deletions
diff --git a/docs/password_auth_providers.rst b/docs/password_auth_providers.rst
index 2dbebcd72c..98019cea01 100644
--- a/docs/password_auth_providers.rst
+++ b/docs/password_auth_providers.rst
@@ -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
     ``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.
diff --git a/synapse/handlers/auth.py b/synapse/handlers/auth.py
index 9799461d26..cc667b6d8b 100644
--- a/synapse/handlers/auth.py
+++ b/synapse/handlers/auth.py
@@ -682,6 +682,7 @@ class AuthHandler(BaseHandler):
         yield self.store.user_delete_threepids(user_id)
         yield self.store.user_set_password_hash(user_id, None)
 
+    @defer.inlineCallbacks
     def delete_access_token(self, access_token):
         """Invalidate a single access token
 
@@ -691,8 +692,19 @@ class AuthHandler(BaseHandler):
         Returns:
             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,
                                       device_id=None):
         """Invalidate access tokens belonging to a user
@@ -707,10 +719,20 @@ class AuthHandler(BaseHandler):
         Returns:
             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,
         )
 
+        # 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
     def add_threepid(self, user_id, medium, address, validated_at):
         # 'Canonicalise' email addresses down to lower case.
diff --git a/synapse/storage/registration.py b/synapse/storage/registration.py
index 65ddefda92..9c4f61da76 100644
--- a/synapse/storage/registration.py
+++ b/synapse/storage/registration.py
@@ -255,7 +255,8 @@ class RegistrationStore(background_updates.BackgroundUpdateStore):
                 If None, tokens associated with any device (or no device) will
                 be deleted
         Returns:
-            defer.Deferred:
+            defer.Deferred[list[str, str|None]]: a list of the deleted tokens
+                and device IDs
         """
         def f(txn):
             keyvalues = {
@@ -272,14 +273,14 @@ class RegistrationStore(background_updates.BackgroundUpdateStore):
                 values.append(except_token_id)
 
             txn.execute(
-                "SELECT token FROM access_tokens WHERE %s" % where_clause,
+                "SELECT token, device_id FROM access_tokens WHERE %s" % where_clause,
                 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(
-                    txn, self.get_user_by_access_token, (row["token"],)
+                    txn, self.get_user_by_access_token, (token,)
                 )
 
             txn.execute(
@@ -287,6 +288,8 @@ class RegistrationStore(background_updates.BackgroundUpdateStore):
                 values
             )
 
+            return tokens_and_devices
+
         yield self.runInteraction(
             "user_delete_access_tokens", f,
         )