diff --git a/litellm/types/proxy/ldap_sync.py b/litellm/types/proxy/ldap_sync.py index 0b47e095d2a..73e2f0a168f 100644 --- a/litellm/types/proxy/ldap_sync.py +++ b/litellm/types/proxy/ldap_sync.py @@ -6,7 +6,7 @@ from typing_extensions import Self class LDAPSyncSettings(BaseModel): - model_config = ConfigDict(frozen=True, extra="forbid") + model_config = ConfigDict(frozen=True, extra="forbid", hide_input_in_errors=True) enabled: bool = False server_url: str = "" diff --git a/tests/unit/proxy/common_utils/test_ldap_directory.py b/tests/unit/proxy/common_utils/test_ldap_directory.py index 21542869738..3de67f00335 100644 --- a/tests/unit/proxy/common_utils/test_ldap_directory.py +++ b/tests/unit/proxy/common_utils/test_ldap_directory.py @@ -242,6 +242,22 @@ def test_invalid_configuration_is_rejected(updates: Mapping[str, object]): LDAPSyncSettings.model_validate({**SETTINGS.model_dump(), **updates}) +@pytest.mark.parametrize( + "updates,message", + [ + ({"bind_dn": "cn=admin", "start_tls": False}, "require TLS"), + ({}, "bind_dn and bind_password must be configured together"), + ], +) +def test_invalid_configuration_errors_do_not_expose_bind_password(updates: Mapping[str, object], message: str): + password: Final = "qa-secret-42" + with pytest.raises(ValidationError, match=message) as error: + LDAPSyncSettings.model_validate( + {**SETTINGS.model_dump(exclude_unset=True), **updates, "bind_password": password} + ) + assert password not in str(error.value) + + def test_cancelled_reader_stops_before_opening_ldap(): cancellation = Event() cancellation.set()