@@ -257,7 +257,7 @@ def _delete_device(self, access_token, user_id, password, device_id):
257257 self .assertEquals (channel .code , 200 , channel .result )
258258
259259
260- class CASRedirectConfirmTestCase (unittest .HomeserverTestCase ):
260+ class CASTestCase (unittest .HomeserverTestCase ):
261261
262262 servlets = [
263263 login .register_servlets ,
@@ -274,6 +274,9 @@ def make_homeserver(self, reactor, clock):
274274 "service_url" : "https://matrix.goodserver.com:8448" ,
275275 }
276276
277+ cas_user_id = "username"
278+ self .user_id = "@%s:test" % cas_user_id
279+
277280 async def get_raw (uri , args ):
278281 """Return an example response payload from a call to the `/proxyValidate`
279282 endpoint of a CAS server, copied from
@@ -282,10 +285,11 @@ async def get_raw(uri, args):
282285 This needs to be returned by an async function (as opposed to set as the
283286 mock's return value) because the corresponding Synapse code awaits on it.
284287 """
285- return """
288+ return (
289+ """
286290 <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
287291 <cas:authenticationSuccess>
288- <cas:user>username </cas:user>
292+ <cas:user>%s </cas:user>
289293 <cas:proxyGrantingTicket>PGTIOU-84678-8a9d...</cas:proxyGrantingTicket>
290294 <cas:proxies>
291295 <cas:proxy>https://proxy2/pgtUrl</cas:proxy>
@@ -294,6 +298,8 @@ async def get_raw(uri, args):
294298 </cas:authenticationSuccess>
295299 </cas:serviceResponse>
296300 """
301+ % cas_user_id
302+ )
297303
298304 mocked_http_client = Mock (spec = ["get_raw" ])
299305 mocked_http_client .get_raw .side_effect = get_raw
@@ -304,6 +310,9 @@ async def get_raw(uri, args):
304310
305311 return self .hs
306312
313+ def prepare (self , reactor , clock , hs ):
314+ self .deactivate_account_handler = hs .get_deactivate_account_handler ()
315+
307316 def test_cas_redirect_confirm (self ):
308317 """Tests that the SSO login flow serves a confirmation page before redirecting a
309318 user to the redirect URL.
@@ -370,3 +379,30 @@ def _test_redirect(self, redirect_url):
370379 self .assertEqual (channel .code , 302 )
371380 location_headers = channel .headers .getRawHeaders ("Location" )
372381 self .assertEqual (location_headers [0 ][: len (redirect_url )], redirect_url )
382+
383+ @override_config ({"sso" : {"client_whitelist" : ["https://legit-site.com/" ]}})
384+ def test_deactivated_user (self ):
385+ """Logging in as a deactivated account should error."""
386+ redirect_url = "https://legit-site.com/"
387+
388+ # First login (to create the user).
389+ self ._test_redirect (redirect_url )
390+
391+ # Deactivate the account.
392+ self .get_success (
393+ self .deactivate_account_handler .deactivate_account (self .user_id , False )
394+ )
395+
396+ # Request the CAS ticket.
397+ cas_ticket_url = (
398+ "/_matrix/client/r0/login/cas/ticket?redirectUrl=%s&ticket=ticket"
399+ % (urllib .parse .quote (redirect_url ))
400+ )
401+
402+ # Get Synapse to call the fake CAS and serve the template.
403+ request , channel = self .make_request ("GET" , cas_ticket_url )
404+ self .render (request )
405+
406+ # Because the user is deactivated they are served an error template.
407+ self .assertEqual (channel .code , 403 )
408+ self .assertIn (b"SSO account deactivated" , channel .result ["body" ])
0 commit comments