diff --git a/tests/test_litellm/proxy/management_endpoints/test_entraid_app_roles.py b/tests/test_litellm/proxy/management_endpoints/test_entraid_app_roles.py index c5a21d31c2f..144e5b44979 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_entraid_app_roles.py +++ b/tests/test_litellm/proxy/management_endpoints/test_entraid_app_roles.py @@ -98,8 +98,6 @@ def test_defaults_to_internal_user_viewer_when_no_role(): @pytest.mark.parametrize( "app_roles, expected", [ - # Regression for #33434: the most permissive role wins regardless of - # its position in the array, instead of always picking the first entry. (["internal_user", "proxy_admin"], LitellmUserRoles.PROXY_ADMIN), (["proxy_admin", "internal_user"], LitellmUserRoles.PROXY_ADMIN), ( @@ -107,11 +105,9 @@ def test_defaults_to_internal_user_viewer_when_no_role(): LitellmUserRoles.PROXY_ADMIN_VIEW_ONLY, ), (["org_admin", "proxy_admin_viewer"], LitellmUserRoles.ORG_ADMIN), - # Unknown roles are ignored; the single valid one is selected. (["some_custom_role", "internal_user"], LitellmUserRoles.INTERNAL_USER), (["PROXY_ADMIN", "internal_user"], LitellmUserRoles.PROXY_ADMIN), (["internal_user"], LitellmUserRoles.INTERNAL_USER), - # No valid roles at all. (["some_custom_role", "another_unknown_role"], None), ([], None), ], diff --git a/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py b/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py index 92d1b870d75..349cfea7b0e 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py +++ b/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py @@ -223,6 +223,43 @@ def test_get_microsoft_callback_response(): assert result.last_name == "User" +def test_get_microsoft_callback_response_picks_most_permissive_app_role(): + from litellm.proxy._types import LitellmUserRoles + + mock_request = MagicMock(spec=Request) + mock_response = { + "mail": "microsoft_user@example.com", + "displayName": "Microsoft User", + "id": "msft123", + "givenName": "Microsoft", + "surname": "User", + } + + with patch.dict( + os.environ, + {"MICROSOFT_CLIENT_SECRET": "mock_secret", "MICROSOFT_TENANT": "mock_tenant"}, + ): + mock_verify = AsyncMock(return_value=mock_response) + with patch( + "fastapi_sso.sso.microsoft.MicrosoftSSO.verify_and_process", + new=mock_verify, + ), patch.object( + MicrosoftSSOHandler, + "get_app_roles_from_id_token", + return_value=["internal_user", "proxy_admin"], + ): + result = asyncio.run( + MicrosoftSSOHandler.get_microsoft_callback_response( + request=mock_request, + microsoft_client_id="mock_client_id", + redirect_url="http://mock_redirect_url", + ) + ) + + assert isinstance(result, CustomOpenID) + assert result.user_role == LitellmUserRoles.PROXY_ADMIN + + def test_get_microsoft_callback_response_raw_sso_response(): # Arrange mock_request = MagicMock(spec=Request)