diff --git a/zerver/management/commands/query_ldap.py b/zerver/management/commands/query_ldap.py index c3b0bf61d9..89f3cdbc7c 100644 --- a/zerver/management/commands/query_ldap.py +++ b/zerver/management/commands/query_ldap.py @@ -17,9 +17,9 @@ def query_ldap(**options: str) -> None: print("No such user found") else: for django_field, ldap_field in settings.AUTH_LDAP_USER_ATTR_MAP.items(): - value = ldap_attrs[ldap_field] + value = ldap_attrs.get(ldap_field, ["LDAP field not present", ])[0] if django_field == "avatar": - if isinstance(value[0], bytes): + if isinstance(value, bytes): value = "(An avatar image file)" print("%s: %s" % (django_field, value)) if settings.LDAP_EMAIL_ATTR is not None: diff --git a/zerver/tests/test_auth_backends.py b/zerver/tests/test_auth_backends.py index f53cc7a402..d1d53db62c 100644 --- a/zerver/tests/test_auth_backends.py +++ b/zerver/tests/test_auth_backends.py @@ -2881,6 +2881,23 @@ class TestZulipLDAPUserPopulator(ZulipLDAPTestCase): self.perform_ldap_sync(self.example_user('hamlet')) f.assert_called_once_with(*expected_call_args) + def test_update_custom_profile_field_not_present_in_ldap(self) -> None: + self.mock_ldap.directory = { + 'uid=hamlet,ou=users,dc=zulip,dc=com': { + 'cn': ['King Hamlet', ], + } + } + hamlet = self.example_user('hamlet') + no_op_field = CustomProfileField.objects.get(realm=hamlet.realm, name='Birthday') + expected_value = CustomProfileFieldValue.objects.get(user_profile=hamlet, field=no_op_field).value + + with self.settings(AUTH_LDAP_USER_ATTR_MAP={'full_name': 'cn', + 'custom_profile_field__birthday': 'birthDate'}): + self.perform_ldap_sync(self.example_user('hamlet')) + + actual_value = CustomProfileFieldValue.objects.get(user_profile=hamlet, field=no_op_field).value + self.assertEqual(actual_value, expected_value) + class TestZulipAuthMixin(ZulipTestCase): def test_get_user(self) -> None: backend = ZulipAuthMixin() diff --git a/zproject/backends.py b/zproject/backends.py index a71d9d1f7f..0ae9b04ec6 100644 --- a/zproject/backends.py +++ b/zproject/backends.py @@ -347,7 +347,13 @@ class ZulipLDAPAuthBackendBase(ZulipAuthMixin, LDAPBackend): if not attr.startswith('custom_profile_field__'): continue var_name = attr.split('custom_profile_field__')[1] - value = ldap_user.attrs[ldap_attr][0] + try: + value = ldap_user.attrs[ldap_attr][0] + except KeyError: + # If this user doesn't have this field set then ignore this + # field and continue syncing other fields. `django-auth-ldap` + # automatically logs error about missing field. + continue values_by_var_name[var_name] = value fields_by_var_name = {} # type: Dict[str, CustomProfileField]