diff --git a/tests/api/test_auth.py b/tests/api/test_auth.py
index ee92ceeb60..c0cb8ef296 100644
--- a/tests/api/test_auth.py
+++ b/tests/api/test_auth.py
@@ -262,9 +262,11 @@ class AuthTestCase(unittest.TestCase):
self.store.add_access_token_to_user = Mock()
token = yield self.hs.handlers.auth_handler.get_access_token_for_user_id(
- USER_ID, "DEVICE"
+ USER_ID, "DEVICE", valid_until_ms=None
+ )
+ self.store.add_access_token_to_user.assert_called_with(
+ USER_ID, token, "DEVICE", None
)
- self.store.add_access_token_to_user.assert_called_with(USER_ID, token, "DEVICE")
def get_user(tok):
if token != tok:
diff --git a/tests/handlers/test_auth.py b/tests/handlers/test_auth.py
index b204a0700d..b03103d96f 100644
--- a/tests/handlers/test_auth.py
+++ b/tests/handlers/test_auth.py
@@ -117,7 +117,9 @@ class AuthTestCase(unittest.TestCase):
def test_mau_limits_disabled(self):
self.hs.config.limit_usage_by_mau = False
# Ensure does not throw exception
- yield self.auth_handler.get_access_token_for_user_id("user_a")
+ yield self.auth_handler.get_access_token_for_user_id(
+ "user_a", device_id=None, valid_until_ms=None
+ )
yield self.auth_handler.validate_short_term_login_token_and_get_user_id(
self._get_macaroon().serialize()
@@ -131,7 +133,9 @@ class AuthTestCase(unittest.TestCase):
)
with self.assertRaises(ResourceLimitError):
- yield self.auth_handler.get_access_token_for_user_id("user_a")
+ yield self.auth_handler.get_access_token_for_user_id(
+ "user_a", device_id=None, valid_until_ms=None
+ )
self.hs.get_datastore().get_monthly_active_count = Mock(
return_value=defer.succeed(self.large_number_of_users)
@@ -150,7 +154,9 @@ class AuthTestCase(unittest.TestCase):
return_value=defer.succeed(self.hs.config.max_mau_value)
)
with self.assertRaises(ResourceLimitError):
- yield self.auth_handler.get_access_token_for_user_id("user_a")
+ yield self.auth_handler.get_access_token_for_user_id(
+ "user_a", device_id=None, valid_until_ms=None
+ )
self.hs.get_datastore().get_monthly_active_count = Mock(
return_value=defer.succeed(self.hs.config.max_mau_value)
@@ -166,7 +172,9 @@ class AuthTestCase(unittest.TestCase):
self.hs.get_datastore().get_monthly_active_count = Mock(
return_value=defer.succeed(self.hs.config.max_mau_value)
)
- yield self.auth_handler.get_access_token_for_user_id("user_a")
+ yield self.auth_handler.get_access_token_for_user_id(
+ "user_a", device_id=None, valid_until_ms=None
+ )
self.hs.get_datastore().user_last_seen_monthly_active = Mock(
return_value=defer.succeed(self.hs.get_clock().time_msec())
)
@@ -185,7 +193,9 @@ class AuthTestCase(unittest.TestCase):
return_value=defer.succeed(self.small_number_of_users)
)
# Ensure does not raise exception
- yield self.auth_handler.get_access_token_for_user_id("user_a")
+ yield self.auth_handler.get_access_token_for_user_id(
+ "user_a", device_id=None, valid_until_ms=None
+ )
self.hs.get_datastore().get_monthly_active_count = Mock(
return_value=defer.succeed(self.small_number_of_users)
diff --git a/tests/handlers/test_register.py b/tests/handlers/test_register.py
index 1b7e1dacee..90d0129374 100644
--- a/tests/handlers/test_register.py
+++ b/tests/handlers/test_register.py
@@ -272,7 +272,10 @@ class RegistrationTestCase(unittest.HomeserverTestCase):
)
else:
yield self.hs.get_auth_handler().delete_access_tokens_for_user(user_id)
- yield self.store.add_access_token_to_user(user_id=user_id, token=token)
+
+ yield self.store.add_access_token_to_user(
+ user_id=user_id, token=token, device_id=None, valid_until_ms=None
+ )
if displayname is not None:
# logger.info("setting user display name: %s -> %s", user_id, displayname)
diff --git a/tests/rest/client/v1/test_login.py b/tests/rest/client/v1/test_login.py
index 0397f91a9e..eae5411325 100644
--- a/tests/rest/client/v1/test_login.py
+++ b/tests/rest/client/v1/test_login.py
@@ -2,10 +2,14 @@ import json
import synapse.rest.admin
from synapse.rest.client.v1 import login
+from synapse.rest.client.v2_alpha import devices
+from synapse.rest.client.v2_alpha.account import WhoamiRestServlet
from tests import unittest
+from tests.unittest import override_config
LOGIN_URL = b"/_matrix/client/r0/login"
+TEST_URL = b"/_matrix/client/r0/account/whoami"
class LoginRestServletTestCase(unittest.HomeserverTestCase):
@@ -13,6 +17,8 @@ class LoginRestServletTestCase(unittest.HomeserverTestCase):
servlets = [
synapse.rest.admin.register_servlets_for_client_rest_resource,
login.register_servlets,
+ devices.register_servlets,
+ lambda hs, http_server: WhoamiRestServlet(hs).register(http_server),
]
def make_homeserver(self, reactor, clock):
@@ -144,3 +150,105 @@ class LoginRestServletTestCase(unittest.HomeserverTestCase):
self.render(request)
self.assertEquals(channel.result["code"], b"403", channel.result)
+
+ @override_config({"session_lifetime": "24h"})
+ def test_soft_logout(self):
+ self.register_user("kermit", "monkey")
+
+ # we shouldn't be able to make requests without an access token
+ request, channel = self.make_request(b"GET", TEST_URL)
+ self.render(request)
+ self.assertEquals(channel.result["code"], b"401", channel.result)
+ self.assertEquals(channel.json_body["errcode"], "M_MISSING_TOKEN")
+
+ # log in as normal
+ params = {
+ "type": "m.login.password",
+ "identifier": {"type": "m.id.user", "user": "kermit"},
+ "password": "monkey",
+ }
+ request, channel = self.make_request(b"POST", LOGIN_URL, params)
+ self.render(request)
+
+ self.assertEquals(channel.code, 200, channel.result)
+ access_token = channel.json_body["access_token"]
+ device_id = channel.json_body["device_id"]
+
+ # we should now be able to make requests with the access token
+ request, channel = self.make_request(
+ b"GET", TEST_URL, access_token=access_token
+ )
+ self.render(request)
+ self.assertEquals(channel.code, 200, channel.result)
+
+ # time passes
+ self.reactor.advance(24 * 3600)
+
+ # ... and we should be soft-logouted
+ request, channel = self.make_request(
+ b"GET", TEST_URL, access_token=access_token
+ )
+ self.render(request)
+ self.assertEquals(channel.code, 401, channel.result)
+ self.assertEquals(channel.json_body["errcode"], "M_UNKNOWN_TOKEN")
+ self.assertEquals(channel.json_body["soft_logout"], True)
+
+ #
+ # test behaviour after deleting the expired device
+ #
+
+ # we now log in as a different device
+ access_token_2 = self.login("kermit", "monkey")
+
+ # more requests with the expired token should still return a soft-logout
+ self.reactor.advance(3600)
+ request, channel = self.make_request(
+ b"GET", TEST_URL, access_token=access_token
+ )
+ self.render(request)
+ self.assertEquals(channel.code, 401, channel.result)
+ self.assertEquals(channel.json_body["errcode"], "M_UNKNOWN_TOKEN")
+ self.assertEquals(channel.json_body["soft_logout"], True)
+
+ # ... but if we delete that device, it will be a proper logout
+ self._delete_device(access_token_2, "kermit", "monkey", device_id)
+
+ request, channel = self.make_request(
+ b"GET", TEST_URL, access_token=access_token
+ )
+ self.render(request)
+ self.assertEquals(channel.code, 401, channel.result)
+ self.assertEquals(channel.json_body["errcode"], "M_UNKNOWN_TOKEN")
+ self.assertEquals(channel.json_body["soft_logout"], False)
+
+ def _delete_device(self, access_token, user_id, password, device_id):
+ """Perform the UI-Auth to delete a device"""
+ request, channel = self.make_request(
+ b"DELETE", "devices/" + device_id, access_token=access_token
+ )
+ self.render(request)
+ self.assertEquals(channel.code, 401, channel.result)
+ # check it's a UI-Auth fail
+ self.assertEqual(
+ set(channel.json_body.keys()),
+ {"flows", "params", "session"},
+ channel.result,
+ )
+
+ auth = {
+ "type": "m.login.password",
+ # https://github.com/matrix-org/synapse/issues/5665
+ # "identifier": {"type": "m.id.user", "user": user_id},
+ "user": user_id,
+ "password": password,
+ "session": channel.json_body["session"],
+ }
+
+ request, channel = self.make_request(
+ b"DELETE",
+ "devices/" + device_id,
+ access_token=access_token,
+ content={"auth": auth},
+ )
+ self.render(request)
+ self.assertEquals(channel.code, 200, channel.result)
diff --git a/tests/storage/test_registration.py b/tests/storage/test_registration.py
index 9365c4622d..0253c4ac05 100644
--- a/tests/storage/test_registration.py
+++ b/tests/storage/test_registration.py
@@ -57,7 +57,7 @@ class RegistrationStoreTestCase(unittest.TestCase):
def test_add_tokens(self):
yield self.store.register_user(self.user_id, self.pwhash)
yield self.store.add_access_token_to_user(
- self.user_id, self.tokens[1], self.device_id
+ self.user_id, self.tokens[1], self.device_id, valid_until_ms=None
)
result = yield self.store.get_user_by_access_token(self.tokens[1])
@@ -72,9 +72,11 @@ class RegistrationStoreTestCase(unittest.TestCase):
def test_user_delete_access_tokens(self):
# add some tokens
yield self.store.register_user(self.user_id, self.pwhash)
- yield self.store.add_access_token_to_user(self.user_id, self.tokens[0])
yield self.store.add_access_token_to_user(
- self.user_id, self.tokens[1], self.device_id
+ self.user_id, self.tokens[0], device_id=None, valid_until_ms=None
+ )
+ yield self.store.add_access_token_to_user(
+ self.user_id, self.tokens[1], self.device_id, valid_until_ms=None
)
# now delete some
|