Skip to content

Commit cf6f69b

Browse files
authored
Merge pull request #1 from pacnpal/copilot/fix-admin-role-claim-issues
Fix OIDC login downgrading existing user roles when provider sends no role claims
2 parents e651cfc + 2a7c86e commit cf6f69b

File tree

2 files changed

+35
-1
lines changed

2 files changed

+35
-1
lines changed

backend/handler/auth/base_handler.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,9 @@ async def get_current_active_user_from_openid_token(self, token: Any):
337337
)
338338

339339
role = Role.VIEWER
340+
claims_provided = False
340341
if OIDC_CLAIM_ROLES and OIDC_CLAIM_ROLES in userinfo:
342+
claims_provided = True
341343
roles = userinfo[OIDC_CLAIM_ROLES] or []
342344
if OIDC_ROLE_ADMIN and OIDC_ROLE_ADMIN in roles:
343345
role = Role.ADMIN
@@ -368,7 +370,7 @@ async def get_current_active_user_from_openid_token(self, token: Any):
368370
role=role,
369371
)
370372
user = db_user_handler.add_user(new_user)
371-
elif OIDC_CLAIM_ROLES and user.role != role:
373+
elif claims_provided and user.role != role:
372374
user = db_user_handler.update_user(user.id, {"role": role})
373375

374376
if not user.enabled:

backend/tests/handler/auth/test_oidc.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,38 @@ async def test_oidc_token_without_email_verified_claim(
350350
assert userinfo.get("email") == mock_jwt_payload.claims.get("email")
351351

352352

353+
async def test_oidc_valid_no_edit_user_role_if_claim_not_in_userinfo(
354+
mocker,
355+
mock_oidc_enabled,
356+
mock_token,
357+
mock_openid_configuration,
358+
):
359+
"""Test that role is not changed for existing user on login if OIDC role claim is configured but not provided by the OIDC provider."""
360+
mocker.patch("handler.auth.base_handler.OIDC_CLAIM_ROLES", "roles")
361+
mocker.patch("handler.auth.base_handler.OIDC_ROLE_ADMIN", "admin")
362+
# The OIDC provider does NOT include the roles claim in userinfo
363+
mock_token["userinfo"].pop("roles", None)
364+
mock_user = MagicMock(enabled=True, role=Role.ADMIN)
365+
mocker.patch(
366+
"handler.database.db_user_handler.get_user_by_email", return_value=mock_user
367+
)
368+
mock_edit_user = mocker.patch(
369+
"handler.database.db_user_handler.update_user", return_value=mock_user
370+
)
371+
mocker.patch.object(
372+
StarletteOAuth2App,
373+
"load_server_metadata",
374+
return_value=mock_openid_configuration,
375+
)
376+
377+
oidc_handler = OpenIDHandler()
378+
user, _ = await oidc_handler.get_current_active_user_from_openid_token(mock_token)
379+
380+
# The user's existing ADMIN role should be preserved
381+
mock_edit_user.assert_not_called()
382+
assert user.role == Role.ADMIN
383+
384+
353385
async def test_oidc_invalid_token_signature(mock_oidc_enabled):
354386
"""Test token decoding raises exception for invalid signature."""
355387
oidc_handler = OpenIDHandler()

0 commit comments

Comments
 (0)