Casper van der Wel 1 год назад
Родитель
Сommit
c2e427d245

+ 1 - 1
CHANGES.md

@@ -4,7 +4,7 @@
 ## 0.8.4 (unreleased)
 ---------------------
 
-- Nothing changed yet.
+- Fixed verification of client credentials tokens.
 
 
 ## 0.8.3 (2023-11-09)

+ 7 - 2
clean_python/oauth2/token.py

@@ -21,14 +21,19 @@ class Token(ValueObject):
             return v
         assert v.get("sub"), "missing 'sub' claim"
         assert v.get("scope"), "missing 'scope' claim"
-        assert v.get("username"), "missing 'username' claim"
+        assert v.get("username") or v.get(
+            "client_id"
+        ), "missing 'username' / 'client_id' claim"
         if v.get("tenant"):
             assert v.get("tenant_name"), "missing 'tenant_name' claim"
         return v
 
     @property
     def user(self) -> User:
-        return User(id=self.claims["sub"], name=self.claims["username"])
+        return User(
+            id=self.claims["sub"],
+            name=self.claims.get("username") or self.claims["client_id"],
+        )
 
     @property
     def scope(self) -> Scope:

+ 0 - 1
tests/oauth2/conftest.py

@@ -50,7 +50,6 @@ def token_generator(private_key):
         "token_use": "access",
         "exp": int(time.time()) + 3600,
         "iat": int(time.time()) - 3600,
-        "nbf": int(time.time()) - 3600,
     }
 
     def generate_token(**claim_overrides):

+ 12 - 0
tests/oauth2/test_service_auth.py

@@ -110,3 +110,15 @@ def test_context(app, client: TestClient, token_generator):
     }
     assert ctx.user.id != "foo"
     assert ctx.tenant is None
+
+
+@pytest.mark.usefixtures("jwk_patched")
+def test_client_credentials_ok(app, client: TestClient, token_generator):
+    response = client.get(
+        app.url_path_for("v1/testing"),
+        headers={
+            "Authorization": "Bearer " + token_generator(username=None, client_id="foo")
+        },
+    )
+
+    assert response.status_code == HTTPStatus.OK

+ 14 - 0
tests/oauth2/test_token.py

@@ -62,3 +62,17 @@ def test_tenant(claims_multitenant):
 def test_no_tenant(claims):
     actual = Token(claims=claims).tenant
     assert actual is None
+
+
+@pytest.fixture
+def claims_client_credentials():
+    return {
+        "sub": "abc123",
+        "scope": "a b",
+        "client_id": "foo",
+    }
+
+
+def test_user_client_credentials(claims_client_credentials):
+    actual = Token(claims=claims_client_credentials).user
+    assert actual == User(id="abc123", name="foo")