Syncing from LDAP or Active Directory

Keep mailboxes in step with the directory you already have, on a schedule — who arrives, who changes, who leaves — without typing anyone in twice.

If your people already exist in Active Directory or an LDAP server, you should not have to keep them here as well. A sync reads that directory on a schedule and makes this one agree: people who appeared get mailboxes, people whose names changed get the new ones, people who left stop being able to sign in.

It works with Active Directory, OpenLDAP, and anything else that speaks LDAP.

Before you start

You need a read-only account in your directory — Nixt Server never writes to it — and the distinguished name of the part of the tree your people are in.

Turn it on

sudo -u versealx versealx-server admin put tenants/1/directory-sync \
  "url=ldaps://dc1.example.com" \
  "bindDn=cn=versealx,ou=service,dc=example,dc=com" \
  "bindPassword=the-password" \
  "baseDn=ou=people,dc=example,dc=com"

Then see what it would do, without doing any of it:

sudo -u versealx versealx-server sync 1 --dry-run
tenant 1 — ldaps://dc1.example.com
  + ada@example.com (Ada Lovelace)
  + bob@example.com (Bob Stone)
  nothing was changed (--dry-run)

If that looks right, run it:

sudo -u versealx versealx-server sync 1

After that it runs on its own, every everyMinutes.

FieldMeaning
urlldaps://host or ldap://host. Use ldaps:// unless the directory is on the same machine.
bindDnThe account that reads the directory.
bindPasswordIts password. Never shown again; leave it out of later calls to keep it.
baseDnWhere under the tree to look.
userFilterWhich entries are people. (&(objectClass=person)(mail=*)) if you leave it out.
groupFilterWhich entries are groups. Leave it out and no groups are synced.
mappingWhich attribute becomes which field — see below.
everyMinutesHow often. 60 if you leave it out; 0 runs only when you say so.
enabledfalse keeps the settings and stops the schedule.
mostAtOnce, atLeastThe safety limits — see below.
passThroughtrue and the people this sync creates sign in with their directory password — see below. false if you leave it out.

Check what is configured, what it manages and how the last run went:

sudo -u versealx versealx-server admin get tenants/1/directory-sync

The attributes in that answer are exactly what a search will ask your directory for. Compare it with what your directory publishes if a sync finds fewer people than you expected.

Which attribute becomes which

The defaults are what Active Directory publishes. On OpenLDAP you will want to change two:

sudo -u versealx versealx-server admin put tenants/1/directory-sync \
  "url=ldaps://ldap.example.com" \
  "bindDn=cn=versealx,dc=example,dc=com" \
  "baseDn=ou=people,dc=example,dc=com" \
  'mapping={"id":"entryUUID","disabledFlag":""}'
FieldDefaultWhat it is
idobjectGUIDThe identifier that survives a rename. entryUUID on OpenLDAP.
addressmailThe mailbox address.
displayNamedisplayNameWhat to call them. Falls back to cn, then to the address.
givenName, familyNamegivenName, snKept alongside the account.
disabledFlaguserAccountControlWhether the account is in use. Set it to "" on a directory that has no such attribute.
groupNamecnA group’s name.
groupAddressmailA group’s address, where it has one.
groupMembersmemberA group’s members, as distinguished names.

id is the one that matters. People are matched on it, never on their address, so somebody who marries and has their name — and therefore their whole distinguished name — changed in the directory keeps the same mailbox. Matching on the address would give them a new empty one.

Mail-enabled groups on OpenLDAP

The standard groupOfNames class does not permit a mail attribute, so a group that is also a distribution address needs an auxiliary class:

dn: cn=Engineering,ou=groups,dc=example,dc=com
objectClass: groupOfNames
objectClass: extensibleObject
cn: Engineering
mail: eng@example.com
member: cn=Ada Lovelace,ou=people,dc=example,dc=com

Active Directory groups carry mail already. A group with no address still syncs — it is a set of people, and not everything a directory calls a group is something mail is sent to.

What a sync will and will not do

It never deletes anyone. Someone the directory no longer holds is offboarded with the organisation’s default choices: they stop being able to sign in, their mail goes on arriving and is handed on, and their mailbox stays where it is (see When somebody leaves). With offboarding.on_deprovision set to disable, they are only disabled. A sync is a reading of your directory, and a reading is not a reason to destroy mail. Remove the mailbox yourself when you mean to.

It only touches what it created. Accounts you made by hand, and accounts SCIM provisioned, are never changed or disabled by a sync — so you can run both without them fighting.

A run happens whole or not at all. If one entry cannot be taken — most often an address in a domain the organisation does not own — the run changes nothing and says which entry and why. Nobody is added halfway through a run that failed.

Every change is in the audit log. Each person added, changed, suspended or let back in, each group added, changed or removed, and one line for the run with its counts, written by the sync itself (role directory-sync). See Roles and the audit log.

It stops itself if something looks wrong. A run is refused whole, changing nothing, when:

  • the directory returns nothing at all while the sync manages somebody, or
  • it would disable more than a fifth of what it manages and at least five accounts.

A bind that fails open, a filter with a typo and a base DN pointing at an empty subtree all read as “everybody has left”, and all three have emptied a real mail system. The refusal names the numbers:

this run would disable 30 of the 100 accounts it manages, which is more
than the 20% one run may; check the filter and the base first, and
confirm the run when you mean it

Both numbers are yours to change (mostAtOnce, atLeast). After a genuine reorganisation, say you mean it:

sudo -u versealx versealx-server sync 1 --confirm

A scheduled run is never confirmed automatically. The valve exists for exactly the run nobody is watching.

Signing in with the directory password

If you have a directory but no identity provider for single sign-on, your people can sign in to their mail with the password they already use for everything else:

sudo -u versealx versealx-server admin put tenants/1/directory-sync \
  "url=ldaps://dc1.example.com" \
  "bindDn=cn=versealx,ou=service,dc=example,dc=com" \
  "baseDn=ou=people,dc=example,dc=com" \
  "passThrough=true"

A PUT sets everything at once, so send the other fields you rely on — mapping, the filters, the schedule — in the same call.

From then on, when one of the people this sync created signs in — to IMAP, POP3, sending mail, calendars, or a sign-in page — Nixt Server finds them in the directory and asks the directory whether the password is right. There is nothing to set up per person, and a password changed in the directory works at once.

  • Only the people the sync created. Accounts you made here, and accounts SCIM provisioned, keep the passwords set here.
  • App passwords still work. They belong to this server, one per device, and are checked here.
  • A password set here stops working for those people. The directory decides.
  • The directory must use ldaps://, or ldap:// to the same machine. People’s passwords are sent to it on every sign-in, so a directory reached over plain ldap:// across a network is refused.
  • Choose PLAIN or LOGIN in mail apps that let you pick, or let them sign in with a password over TLS as most do by default. SCRAM needs a password stored here, and these people do not have one.

If an address in the directory is given to somebody else, the old mailbox does not open to the new person’s password: the entry has to still be the person the mailbox was made for.

If the directory cannot be reached, those people cannot sign in until it can — and it does not count against them. A mail client will ask for the password again; the account is not locked, and it works again as soon as the directory answers. It shows in monitoring as vsx_authentications_total{outcome="unavailable"}.

Wrong passwords do count, the same as for anyone else, and lockout applies before the directory is ever asked.

A directory with its own certificate authority

Most on-premises directories present a certificate signed by an internal CA rather than a public one:

[federation]
trust = "/etc/versealx-server/internal-ca.pem"

This adds a root; the certificate is still checked. It is the same setting single sign-on uses.

When a sync does not work

sudo -u versealx versealx-server admin get tenants/1/directory-sync

The lastRun in that answer holds the problem from the last attempt, so you can see a sync that has been failing since Tuesday without running one.

What it saysWhat to do
the directory refused the bind for …The bind DN or password is wrong, or the account is locked.
the directory refused the search …The base DN does not exist, or the bind account cannot read it.
the directory answered 4 for …A size or time limit. Your directory is sending part of an answer — narrow the filter, or raise the limit for the bind account. A partial answer is refused rather than treated as the whole directory.
cannot reach …The address, the port, or the firewall.
returned nothing at allThe filter matches nobody. Try it with ldapsearch first.
has no stable identifierThe id attribute is not being returned — check the mapping against what your directory publishes.
that domain is not this tenant'sThe address attribute is giving addresses in a domain this tenant does not own.
pass-through sends people's passwords to the directory, so it needs ldaps://…Point url at ldaps://, or turn passThrough off.
pass-through signs people in against the directory a sync reads, and this tenant has no sync configuredConfigure the sync first; passThrough goes in the same call.

A sync that finds fewer people than you expected is usually the filter. Entries with no address and no identifier are passed over rather than stopping the run — a service account with no mail is not a mailbox.

Something unclear or out of date on this page? Tell us.