fix(ldap): treat ldapts empty-array attributes as absent, not "undefined"
ldapts represents a missing/absent LDAP attribute as an empty array
([]), not undefined -- entry['mail'] is [] when an account has no mail
set. The field-mapping loop did Array.isArray(value) ? String(value[0])
: ..., and String(undefined) is the literal string "undefined". Every
synced entry without that attribute got mappedData['email'] = "undefined"
(a truthy string, so the `|| fallback` never kicked in), and the second
such entry onward crashed with a unique constraint violation on email
since they all shared the exact same literal string.
Found live: syncing against a real Zentyal/Samba AD directory failed
on every entry after the first (Kevin Schaller, krbtgt, Guest, the DC
computer object, etc.) with "Unique constraint failed on the fields:
(email)".
Fix: resolve array values to their first element (or use the raw
value for non-arrays) and only keep it when actually present and
non-empty, so a genuinely missing attribute falls through to the
`${username}@ldap.local` fallback instead of the string "undefined".
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -211,15 +211,20 @@ export class LdapService {
|
|||||||
const dn = entry.dn;
|
const dn = entry.dn;
|
||||||
syncedDns.push(dn);
|
syncedDns.push(dn);
|
||||||
|
|
||||||
// Map LDAP fields to Tessera fields
|
// Map LDAP fields to Tessera fields.
|
||||||
|
// ldapts represents a missing/absent attribute as an empty array
|
||||||
|
// ([]), not undefined -- naively doing String(value[0]) on that
|
||||||
|
// produces the literal string "undefined", identical across every
|
||||||
|
// entry lacking the attribute (e.g. no `mail` set), which then
|
||||||
|
// collides on unique constraints like email. Resolve to the first
|
||||||
|
// array element (or the raw value) and skip when it's actually
|
||||||
|
// missing/empty.
|
||||||
const mappedData: Record<string, string> = {};
|
const mappedData: Record<string, string> = {};
|
||||||
for (const mapping of config.fieldMappings) {
|
for (const mapping of config.fieldMappings) {
|
||||||
const value = entry[mapping.ldapField];
|
const value = entry[mapping.ldapField];
|
||||||
if (value !== undefined && value !== null) {
|
const resolved = Array.isArray(value) ? value[0] : value;
|
||||||
// LDAP attributes can be arrays; take first value
|
if (resolved !== undefined && resolved !== null && resolved !== '') {
|
||||||
mappedData[mapping.tesseraField] = Array.isArray(value)
|
mappedData[mapping.tesseraField] = String(resolved);
|
||||||
? String(value[0])
|
|
||||||
: String(value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user