diff options
Diffstat (limited to 'tests/rest/client/test_auth.py')
-rw-r--r-- | tests/rest/client/test_auth.py | 265 |
1 files changed, 18 insertions, 247 deletions
diff --git a/tests/rest/client/test_auth.py b/tests/rest/client/test_auth.py index 72bbc87b4a..8552671431 100644 --- a/tests/rest/client/test_auth.py +++ b/tests/rest/client/test_auth.py @@ -12,7 +12,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from http import HTTPStatus from typing import Optional, Union from twisted.internet.defer import succeed @@ -514,39 +513,12 @@ class RefreshAuthTests(unittest.HomeserverTestCase): self.user_pass = "pass" self.user = self.register_user("test", self.user_pass) - def use_refresh_token(self, refresh_token: str) -> FakeChannel: - """ - Helper that makes a request to use a refresh token. - """ - return self.make_request( - "POST", - "/_matrix/client/v1/refresh", - {"refresh_token": refresh_token}, - ) - - def is_access_token_valid(self, access_token) -> bool: - """ - Checks whether an access token is valid, returning whether it is or not. - """ - code = self.make_request( - "GET", "/_matrix/client/v3/account/whoami", access_token=access_token - ).code - - # Either 200 or 401 is what we get back; anything else is a bug. - assert code in {HTTPStatus.OK, HTTPStatus.UNAUTHORIZED} - - return code == HTTPStatus.OK - def test_login_issue_refresh_token(self): """ A login response should include a refresh_token only if asked. """ # Test login - body = { - "type": "m.login.password", - "user": "test", - "password": self.user_pass, - } + body = {"type": "m.login.password", "user": "test", "password": self.user_pass} login_without_refresh = self.make_request( "POST", "/_matrix/client/r0/login", body @@ -556,8 +528,8 @@ class RefreshAuthTests(unittest.HomeserverTestCase): login_with_refresh = self.make_request( "POST", - "/_matrix/client/r0/login", - {"refresh_token": True, **body}, + "/_matrix/client/r0/login?org.matrix.msc2918.refresh_token=true", + body, ) self.assertEqual(login_with_refresh.code, 200, login_with_refresh.result) self.assertIn("refresh_token", login_with_refresh.json_body) @@ -583,12 +555,11 @@ class RefreshAuthTests(unittest.HomeserverTestCase): register_with_refresh = self.make_request( "POST", - "/_matrix/client/r0/register", + "/_matrix/client/r0/register?org.matrix.msc2918.refresh_token=true", { "username": "test3", "password": self.user_pass, "auth": {"type": LoginType.DUMMY}, - "refresh_token": True, }, ) self.assertEqual(register_with_refresh.code, 200, register_with_refresh.result) @@ -599,22 +570,17 @@ class RefreshAuthTests(unittest.HomeserverTestCase): """ A refresh token can be used to issue a new access token. """ - body = { - "type": "m.login.password", - "user": "test", - "password": self.user_pass, - "refresh_token": True, - } + body = {"type": "m.login.password", "user": "test", "password": self.user_pass} login_response = self.make_request( "POST", - "/_matrix/client/r0/login", + "/_matrix/client/r0/login?org.matrix.msc2918.refresh_token=true", body, ) self.assertEqual(login_response.code, 200, login_response.result) refresh_response = self.make_request( "POST", - "/_matrix/client/v1/refresh", + "/_matrix/client/unstable/org.matrix.msc2918.refresh_token/refresh", {"refresh_token": login_response.json_body["refresh_token"]}, ) self.assertEqual(refresh_response.code, 200, refresh_response.result) @@ -633,19 +599,14 @@ class RefreshAuthTests(unittest.HomeserverTestCase): ) @override_config({"refreshable_access_token_lifetime": "1m"}) - def test_refreshable_access_token_expiration(self): + def test_refresh_token_expiration(self): """ The access token should have some time as specified in the config. """ - body = { - "type": "m.login.password", - "user": "test", - "password": self.user_pass, - "refresh_token": True, - } + body = {"type": "m.login.password", "user": "test", "password": self.user_pass} login_response = self.make_request( "POST", - "/_matrix/client/r0/login", + "/_matrix/client/r0/login?org.matrix.msc2918.refresh_token=true", body, ) self.assertEqual(login_response.code, 200, login_response.result) @@ -655,198 +616,13 @@ class RefreshAuthTests(unittest.HomeserverTestCase): refresh_response = self.make_request( "POST", - "/_matrix/client/v1/refresh", + "/_matrix/client/unstable/org.matrix.msc2918.refresh_token/refresh", {"refresh_token": login_response.json_body["refresh_token"]}, ) self.assertEqual(refresh_response.code, 200, refresh_response.result) self.assertApproximates( refresh_response.json_body["expires_in_ms"], 60 * 1000, 100 ) - access_token = refresh_response.json_body["access_token"] - - # Advance 59 seconds in the future (just shy of 1 minute, the time of expiry) - self.reactor.advance(59.0) - # Check that our token is valid - self.assertEqual( - self.make_request( - "GET", "/_matrix/client/v3/account/whoami", access_token=access_token - ).code, - HTTPStatus.OK, - ) - - # Advance 2 more seconds (just past the time of expiry) - self.reactor.advance(2.0) - # Check that our token is invalid - self.assertEqual( - self.make_request( - "GET", "/_matrix/client/v3/account/whoami", access_token=access_token - ).code, - HTTPStatus.UNAUTHORIZED, - ) - - @override_config( - { - "refreshable_access_token_lifetime": "1m", - "nonrefreshable_access_token_lifetime": "10m", - } - ) - def test_different_expiry_for_refreshable_and_nonrefreshable_access_tokens(self): - """ - Tests that the expiry times for refreshable and non-refreshable access - tokens can be different. - """ - body = { - "type": "m.login.password", - "user": "test", - "password": self.user_pass, - } - login_response1 = self.make_request( - "POST", - "/_matrix/client/r0/login", - {"refresh_token": True, **body}, - ) - self.assertEqual(login_response1.code, 200, login_response1.result) - self.assertApproximates( - login_response1.json_body["expires_in_ms"], 60 * 1000, 100 - ) - refreshable_access_token = login_response1.json_body["access_token"] - - login_response2 = self.make_request( - "POST", - "/_matrix/client/r0/login", - body, - ) - self.assertEqual(login_response2.code, 200, login_response2.result) - nonrefreshable_access_token = login_response2.json_body["access_token"] - - # Advance 59 seconds in the future (just shy of 1 minute, the time of expiry) - self.reactor.advance(59.0) - - # Both tokens should still be valid. - self.assertTrue(self.is_access_token_valid(refreshable_access_token)) - self.assertTrue(self.is_access_token_valid(nonrefreshable_access_token)) - - # Advance to 61 s (just past 1 minute, the time of expiry) - self.reactor.advance(2.0) - - # Only the non-refreshable token is still valid. - self.assertFalse(self.is_access_token_valid(refreshable_access_token)) - self.assertTrue(self.is_access_token_valid(nonrefreshable_access_token)) - - # Advance to 599 s (just shy of 10 minutes, the time of expiry) - self.reactor.advance(599.0 - 61.0) - - # It's still the case that only the non-refreshable token is still valid. - self.assertFalse(self.is_access_token_valid(refreshable_access_token)) - self.assertTrue(self.is_access_token_valid(nonrefreshable_access_token)) - - # Advance to 601 s (just past 10 minutes, the time of expiry) - self.reactor.advance(2.0) - - # Now neither token is valid. - self.assertFalse(self.is_access_token_valid(refreshable_access_token)) - self.assertFalse(self.is_access_token_valid(nonrefreshable_access_token)) - - @override_config( - {"refreshable_access_token_lifetime": "1m", "refresh_token_lifetime": "2m"} - ) - def test_refresh_token_expiry(self): - """ - The refresh token can be configured to have a limited lifetime. - When that lifetime has ended, the refresh token can no longer be used to - refresh the session. - """ - - body = { - "type": "m.login.password", - "user": "test", - "password": self.user_pass, - "refresh_token": True, - } - login_response = self.make_request( - "POST", - "/_matrix/client/r0/login", - body, - ) - self.assertEqual(login_response.code, HTTPStatus.OK, login_response.result) - refresh_token1 = login_response.json_body["refresh_token"] - - # Advance 119 seconds in the future (just shy of 2 minutes) - self.reactor.advance(119.0) - - # Refresh our session. The refresh token should still JUST be valid right now. - # By doing so, we get a new access token and a new refresh token. - refresh_response = self.use_refresh_token(refresh_token1) - self.assertEqual(refresh_response.code, HTTPStatus.OK, refresh_response.result) - self.assertIn( - "refresh_token", - refresh_response.json_body, - "No new refresh token returned after refresh.", - ) - refresh_token2 = refresh_response.json_body["refresh_token"] - - # Advance 121 seconds in the future (just a bit more than 2 minutes) - self.reactor.advance(121.0) - - # Try to refresh our session, but instead notice that the refresh token is - # not valid (it just expired). - refresh_response = self.use_refresh_token(refresh_token2) - self.assertEqual( - refresh_response.code, HTTPStatus.FORBIDDEN, refresh_response.result - ) - - @override_config( - { - "refreshable_access_token_lifetime": "2m", - "refresh_token_lifetime": "2m", - "session_lifetime": "3m", - } - ) - def test_ultimate_session_expiry(self): - """ - The session can be configured to have an ultimate, limited lifetime. - """ - - body = { - "type": "m.login.password", - "user": "test", - "password": self.user_pass, - "refresh_token": True, - } - login_response = self.make_request( - "POST", - "/_matrix/client/r0/login", - body, - ) - self.assertEqual(login_response.code, 200, login_response.result) - refresh_token = login_response.json_body["refresh_token"] - - # Advance shy of 2 minutes into the future - self.reactor.advance(119.0) - - # Refresh our session. The refresh token should still be valid right now. - refresh_response = self.use_refresh_token(refresh_token) - self.assertEqual(refresh_response.code, 200, refresh_response.result) - self.assertIn( - "refresh_token", - refresh_response.json_body, - "No new refresh token returned after refresh.", - ) - # Notice that our access token lifetime has been diminished to match the - # session lifetime. - # 3 minutes - 119 seconds = 61 seconds. - self.assertEqual(refresh_response.json_body["expires_in_ms"], 61_000) - refresh_token = refresh_response.json_body["refresh_token"] - - # Advance 61 seconds into the future. Our session should have expired - # now, because we've had our 3 minutes. - self.reactor.advance(61.0) - - # Try to issue a new, refreshed, access token. - # This should fail because the refresh token's lifetime has also been - # diminished as our session expired. - refresh_response = self.use_refresh_token(refresh_token) - self.assertEqual(refresh_response.code, 403, refresh_response.result) def test_refresh_token_invalidation(self): """Refresh tokens are invalidated after first use of the next token. @@ -864,15 +640,10 @@ class RefreshAuthTests(unittest.HomeserverTestCase): |-> fourth_refresh (fails) """ - body = { - "type": "m.login.password", - "user": "test", - "password": self.user_pass, - "refresh_token": True, - } + body = {"type": "m.login.password", "user": "test", "password": self.user_pass} login_response = self.make_request( "POST", - "/_matrix/client/r0/login", + "/_matrix/client/r0/login?org.matrix.msc2918.refresh_token=true", body, ) self.assertEqual(login_response.code, 200, login_response.result) @@ -880,7 +651,7 @@ class RefreshAuthTests(unittest.HomeserverTestCase): # This first refresh should work properly first_refresh_response = self.make_request( "POST", - "/_matrix/client/v1/refresh", + "/_matrix/client/unstable/org.matrix.msc2918.refresh_token/refresh", {"refresh_token": login_response.json_body["refresh_token"]}, ) self.assertEqual( @@ -890,7 +661,7 @@ class RefreshAuthTests(unittest.HomeserverTestCase): # This one as well, since the token in the first one was never used second_refresh_response = self.make_request( "POST", - "/_matrix/client/v1/refresh", + "/_matrix/client/unstable/org.matrix.msc2918.refresh_token/refresh", {"refresh_token": login_response.json_body["refresh_token"]}, ) self.assertEqual( @@ -900,7 +671,7 @@ class RefreshAuthTests(unittest.HomeserverTestCase): # This one should not, since the token from the first refresh is not valid anymore third_refresh_response = self.make_request( "POST", - "/_matrix/client/v1/refresh", + "/_matrix/client/unstable/org.matrix.msc2918.refresh_token/refresh", {"refresh_token": first_refresh_response.json_body["refresh_token"]}, ) self.assertEqual( @@ -928,7 +699,7 @@ class RefreshAuthTests(unittest.HomeserverTestCase): # Now that the access token from the last valid refresh was used once, refreshing with the N-1 token should fail fourth_refresh_response = self.make_request( "POST", - "/_matrix/client/v1/refresh", + "/_matrix/client/unstable/org.matrix.msc2918.refresh_token/refresh", {"refresh_token": login_response.json_body["refresh_token"]}, ) self.assertEqual( @@ -938,7 +709,7 @@ class RefreshAuthTests(unittest.HomeserverTestCase): # But refreshing from the last valid refresh token still works fifth_refresh_response = self.make_request( "POST", - "/_matrix/client/v1/refresh", + "/_matrix/client/unstable/org.matrix.msc2918.refresh_token/refresh", {"refresh_token": second_refresh_response.json_body["refresh_token"]}, ) self.assertEqual( |