mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-18 14:13:10 +00:00
fix(oidc): close re-review gaps in the hardening commit
Follow-up to the OIDC security hardening, from a max-effort re-review: - Refresh now re-checks the denylist immediately before minting, against the (possibly remapped) identity but anchored on the original session `iat` — so a back-channel logout / SCIM deny that lands during the IdP grant, or one targeting the refreshed sub/sid, still blocks renewal instead of being escaped by the renewed token's fresh iat. Completes the watermark revocation fix. - SCIM PUT `userName` immutability check is now case-insensitive, matching the case-insensitive list/create — a differently-cased userName echo no longer 400s "userName is immutable" and blocks deprovision. Completes the SCIM case-insensitivity fix. - Drop the unconditional state-cookie deletion on every callback exit: it let one tab's callback clear another in-flight tab's cookie, breaking concurrent logins. The cookie self-expires (max_age) and the Redis state is single-use, so the delete wasn't needed. Tests added for the refresh revocation re-check and the case-insensitive PUT.
This commit is contained in:
1 parent
a3d09e8890
commit
321d88d5be
4 files changed
+59
-5
No files matched your search
@@ -1412,6 +1412,28 @@ class TestRefreshRoute:
|
||||
assert response.get_json() == {"error": "token_revoked"}
|
||||
assert "oidc:refresh:jti-1" in fake_redis.store
|
||||
|
||||
def test_revocation_during_grant_blocks_renewal(self, client, fake_redis):
|
||||
# is_denied passes the pre-grant check, but a back-channel logout lands
|
||||
# during the IdP grant; the pre-mint re-check (anchored on the old iat)
|
||||
# must catch it instead of minting a session that escapes the watermark.
|
||||
self.denylist.is_denied.side_effect = [False, True]
|
||||
token = make_session_token()
|
||||
fake_redis.store["oidc:refresh:jti-1"] = b"rt-old"
|
||||
id_claims = id_token_claims(sid="sess-1")
|
||||
del id_claims["nonce"]
|
||||
response, _ = self._refresh(
|
||||
client,
|
||||
token,
|
||||
idp_response={
|
||||
"access_token": "at-2",
|
||||
"refresh_token": "rt-new",
|
||||
"id_token": sign_id_token(id_claims),
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 401
|
||||
assert response.get_json() == {"error": "token_revoked"}
|
||||
|
||||
def test_disabled_user_rejected(self, client, fake_redis):
|
||||
self.db.users.get.return_value = {"user_id": "oidc-user-1", "active": False}
|
||||
token = make_session_token()
|
||||
|
||||
Reference in new issue
Block a user