diff --git a/litellm/_redis.py b/litellm/_redis.py index 58f37cf569d..70ffaab458a 100644 --- a/litellm/_redis.py +++ b/litellm/_redis.py @@ -458,6 +458,8 @@ def _get_redis_client_logic(**env_overrides): # are intentionally NOT exposed on the function to avoid leaking # credentials via inspection or logging. redis_kwargs["redis_connect_func"]._azure_redis_ad_token = True + redis_kwargs.pop("username", None) + redis_kwargs.pop("password", None) # Always remove Azure-specific kwargs that shouldn't be passed to Redis client redis_kwargs.pop("azure_redis_ad_token", None) diff --git a/tests/test_litellm/test_redis.py b/tests/test_litellm/test_redis.py index 3762181f5c3..cacbff9123a 100644 --- a/tests/test_litellm/test_redis.py +++ b/tests/test_litellm/test_redis.py @@ -247,6 +247,31 @@ def test_get_redis_async_client_without_connection_pool(): assert "connection_pool" not in call_kwargs, "connection_pool should not be in kwargs when not provided" +def test_azure_ad_connection_pool_does_not_duplicate_credentials(monkeypatch): + credential = MagicMock() + credential.get_token.return_value.token = "azure-token" + monkeypatch.setenv("REDIS_USERNAME", "entra-user") + monkeypatch.setenv("REDIS_PASSWORD", "static-password") + + with patch("litellm._redis._build_azure_credential", return_value=credential): + pool = get_redis_connection_pool( + host="cache.redis.azure.net", + port=10000, + ssl=True, + azure_redis_ad_token="true", + ) + + assert pool is not None + connection = pool.make_connection() + assert isinstance(connection.credential_provider, AzureADCredentialProvider) + assert connection.username is None + assert connection.password is None + assert connection.credential_provider.get_credentials() == ( + "entra-user", + "azure-token", + ) + + def test_gcp_iam_credential_provider_get_credentials(): """GCPIAMCredentialProvider.get_credentials() returns a token tuple.""" service_account = "projects/-/serviceAccounts/test@project.iam.gserviceaccount.com"