fix: skip LDAP users without an email instead of failing the whole sync (#1835)

This commit is contained in:
Jay Hemnani
2026-10-11 18:15:11 +02:00
committed by GitHub
parent 34477f5aa3
commit 68fe926de8
2 changed files with 71 additions and 0 deletions
+6
View File
@@ -378,6 +378,12 @@ func (s *Service) fetchUsersFromLDAP(ctx context.Context, client ldapClient, dbC
continue
}
// Saving a user without an email fails when emails are required, which would abort the whole sync
if dbConfig.RequireUserEmail.IsTrue() && newUser.Email == nil {
slog.WarnContext(ctx, "Skipping LDAP user without an email address because emails are required", slog.String("username", newUser.Username))
continue
}
desiredUsers = append(desiredUsers, ldapDesiredUser{
ldapID: ldapID,
input: newUser,
+65
View File
@@ -401,6 +401,71 @@ func TestLdapServiceSyncAllBumpsUpdatedAtOfSoftDeletedUsers(t *testing.T) {
assert.Equal(t, lastSync.ToTime().Unix(), disabled.UpdatedAt.ToTime().Unix())
}
func TestLdapServiceSyncAllSkipsUsersWithoutEmailWhenEmailIsRequired(t *testing.T) {
service, db := newTestLdapService(t, newFakeLDAPClient(
ldapSearchResult(
ldapEntry("uid=alice,ou=people,dc=example,dc=com", map[string][]string{
"entryUUID": {"u-alice"},
"uid": {"alice"},
"mail": {"alice@example.com"},
"givenName": {"Alice"},
"sn": {"Jones"},
}),
ldapEntry("uid=service,ou=people,dc=example,dc=com", map[string][]string{
"entryUUID": {"u-service"},
"uid": {"service"},
"givenName": {"Service"},
"sn": {"Account"},
}),
ldapEntry("uid=bob,ou=people,dc=example,dc=com", map[string][]string{
"entryUUID": {"u-bob"},
"uid": {"bob"},
"givenName": {"Bob"},
"sn": {"Brown"},
}),
),
ldapSearchResult(
ldapEntry("cn=team,ou=groups,dc=example,dc=com", map[string][]string{
"entryUUID": {"g-team"},
"cn": {"team"},
"member": {
"uid=alice,ou=people,dc=example,dc=com",
"uid=service,ou=people,dc=example,dc=com",
},
}),
),
))
// Bob was synced earlier, before his mail attribute was removed in LDAP
bobLdapID := "u-bob"
require.NoError(t, db.Create(&model.User{
Username: "bob",
Email: new("bob@example.com"),
FirstName: "Bob",
LastName: "Brown",
LdapID: &bobLdapID,
}).Error)
config := defaultTestLDAPAppConfig()
config.RequireUserEmail = "true"
err := service.SyncAll(t.Context(), config)
require.NoError(t, err)
var users []model.User
require.NoError(t, db.Order("username").Find(&users).Error)
assert.Equal(t, []string{"alice", "bob"}, usernames(users))
var bob model.User
require.NoError(t, db.First(&bob, "ldap_id = ?", bobLdapID).Error)
assert.Equal(t, new("bob@example.com"), bob.Email)
assert.False(t, bob.Disabled)
var team model.UserGroup
require.NoError(t, db.Preload("Users").First(&team, "ldap_id = ?", "g-team").Error)
assert.Equal(t, []string{"alice"}, usernames(team.Users))
}
func TestLdapServiceSyncAllSetsAdminFromGroupMembership(t *testing.T) {
tests := []struct {
name string