From acf8acf29fc27c81ba98748ba61c35b30e8057d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Wed, 17 Apr 2024 13:05:14 +0200 Subject: [PATCH] fix: locked users cannot use OIDC authorization codes --- canaille/oidc/oauth.py | 3 +- tests/oidc/test_authorization_code_flow.py | 41 ++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/canaille/oidc/oauth.py b/canaille/oidc/oauth.py index ffa31052..b4031ad3 100644 --- a/canaille/oidc/oauth.py +++ b/canaille/oidc/oauth.py @@ -245,7 +245,8 @@ class AuthorizationCodeGrant(_AuthorizationCodeGrant): authorization_code.delete() def authenticate_user(self, authorization_code): - return authorization_code.subject + if authorization_code.subject and not authorization_code.subject.locked: + return authorization_code.subject class OpenIDCode(_OpenIDCode): diff --git a/tests/oidc/test_authorization_code_flow.py b/tests/oidc/test_authorization_code_flow.py index a1f5156a..3113031f 100644 --- a/tests/oidc/test_authorization_code_flow.py +++ b/tests/oidc/test_authorization_code_flow.py @@ -1,3 +1,4 @@ +import datetime from urllib.parse import parse_qs from urllib.parse import urlsplit @@ -712,3 +713,43 @@ def test_code_with_invalid_user(testclient, admin, client): "error_description": 'There is no "user" for this code.', } authcode.delete() + + +def test_locked_account(testclient, logged_user, client, keypair, trusted_client): + """Users with a locked account should not be able to exchange code against + tokens.""" + res = testclient.get( + "/oauth/authorize", + params=dict( + response_type="code", + client_id=client.client_id, + scope="openid profile email groups address phone", + nonce="somenonce", + ), + status=200, + ) + + logged_user.lock_date = datetime.datetime.now(datetime.timezone.utc) + logged_user.save() + + res = res.form.submit(name="answer", value="accept", status=302) + + assert res.location.startswith(client.redirect_uris[0]) + params = parse_qs(urlsplit(res.location).query) + code = params["code"][0] + authcode = models.AuthorizationCode.get(code=code) + assert authcode is not None + + res = testclient.post( + "/oauth/token", + params=dict( + grant_type="authorization_code", + code=code, + scope="openid profile email groups address phone", + redirect_uri=client.redirect_uris[0], + ), + headers={"Authorization": f"Basic {client_credentials(client)}"}, + status=400, + ) + + assert "access_token" not in res.json