Dovecot + Samba-DC / Active Directory Authentication

Hello everyone,

I am currently facing some issues regarding the migration of my Dovecot authentication backend from OpenLDAP to Samba-DC.

Since both are LDAP-based directories, I assumed the migration would be straightforward, but that turned out not to be the case. I am fairly certain it is just a minor configuration detail, but I have been searching for a solution for three days now without success.

I would like to share my current configuration, which is working flawlessly with OpenLDAP.

The directory entry:

# extended LDIF
#
# LDAPv3
# base <dc=domain1,dc=tld> with scope subtree
# filter: (mail=user@domain3.tld)
# requesting: ALL
#

# user.surname, users, domain1.tld
dn: uid=user.surname,ou=users,dc=domain1,dc=tld
uid: user.surname
sn: surname
givenName: user
cn: user surname
displayName: user surname
mail: user@domain1.tld
mail: user@domain2.tld
mail: user@domain3.tld
uidNumber: 13113
gidNumber: 13000
homeDirectory: /home/user.surname
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: sambaSamAccount
sambaSID: S-1-5-21-2286081015-3344157248-104006538-1009
sambaNTPassword: [REDACTED]
sambaPasswordHistory: [REDACTED]
sambaPwdLastSet: 1753387770
sambaAcctFlags: [U          ]
initials: 10000G

My Dovecot auth-ldap.conf.ext configuration for this setup looks like this:

# Global LDAP connection settings
ldap_version = 3
ldap_uris = ldap://[SERVER_IP]
ldap_auth_dn = cn=admin,dc=domain1,dc=tld
ldap_auth_dn_password = [PASSWORD]
ldap_base = dc=domain1,dc=tld

# --- Password Database (passdb) ---
# Handles the password verification (Authentication Bind)
passdb ldap {
  ldap_bind = yes
  uid=%{user},ou=users,dc=domain1,dc=tld
  ldap_filter = (&(objectClass=posixAccount)(mail=%{user}))
}

# --- User Database (userdb) ---
# Retrieves user details for mailbox location and access rights.
userdb ldap {
  ldap_filter = (&(objectClass=posixAccount)(mail=%{user}))

  fields {
    home = /srv/vmail/%{user|domain|lower}/%{user|username|lower}
    uid = vmail
    gid = vmail
    quota_rule = *:storage=%{ldap:initials}
    quota_rule2 = Trash:storage=500G
    quota_rule3 = Spam:storage=50M
    quota_storage_size = %{ldap:initials}
    quota_mailbox_message_count = 30000
    quota_mailbox_message_count = 5000
  }
}

The setup is straightforward and works perfectly. The mail attribute is multivalued, containing the three email addresses associated with my three domains. The username remains consistent across all of them.

Now, here is a directory entry from my Samba-DC (Active Directory) for comparison:

# extended LDIF
#
# LDAPv3
# base <dc=domain1,dc=tld> with scope subtree
# filter: (mail=user@domain1.tld)
# requesting: ALL
#

# User Name, Users, domain1.tld
dn: CN=User Name,OU=Users,DC=domain1,DC=tld
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: User Name
sn: Surname
givenName: User
instanceType: 4
whenCreated: 20260510123059.0Z
displayName: User Name
uSNCreated: 4168
name: User Name
objectGUID:: [REDACTED]
badPwdCount: 0
codePage: 0
countryCode: 0
badPasswordTime: 0
lastLogoff: 0
primaryGroupID: 513
objectSid:: [REDACTED]
accountExpires: 9223372036854775807
sAMAccountName: username
sAMAccountType: 805306368
userPrincipalName: user@domain1.tld
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=domain1,DC=tld
mail: user@domain1.tld
pwdLastSet: 134228898599390930
userAccountControl: 512
memberOf: CN=MailUsers,CN=Users,DC=domain1,DC=tld
lastLogonTimestamp: 134250693872343440
logonCount: 9
msDS-cloudExtensionAttribute1: 10000G
proxyAddresses: user@domain2.tld
proxyAddresses: user@domain3.tld
proxyAddresses: user@domain1.tld
msDS-cloudExtensionAttribute2: user@domain2.tld
msDS-cloudExtensionAttribute3: user@domain3.tld
msDS-cloudExtensionAttribute4: user@domain1.tld
whenChanged: 20260609104109.0Z
uSNChanged: 5875
distinguishedName: CN=User Name,OU=Users,DC=domain1,DC=tld

For testing purposes, I have used proxyAddresses as a multivalued field, as well as msDS-cloudExtensionAttribute2 through msDS-cloudExtensionAttribute4.

My Dovecot auth-ldap.conf.ext configuration for this setup looks like this:

# Global LDAP connection settings
ldap_version = 3
ldap_uris = ldaps://dc1.domain1.tld
ldap_auth_dn = "administrator@domain1.tld"
ldap_auth_dn_password = [PASSWORD]
ldap_base = dc=domain1,dc=tld

# IMPORTANT: Samba DC / AD often requires disabling referrals
# referral = no

# --- Password Database (passdb) ---
# Handles the password verification (Authentication Bind)
passdb ldap {
  driver = ldap
  
  # Search filter
  ldap_filter = (&(objectClass=user)(|(msDS-cloudExtensionAttribute4=%{user|username|lower}@%{user|domain|lower})(msDS-cloudExtensionAttribute3=%{user|username|lower}@%{user|domain|lower})(msDS-cloudExtensionAttribute2=%{user|username|lower}@%{user|domain|lower})))
  
  # AD/Samba allows direct bind with the user's mail address
  bind_userdn = %{user|username|lower}@domain1.tld
  bind = yes

  fields {
    user = %{user|username}@domain1.tld
  }
}

# --- User Database (userdb) ---
# Retrieves user details for mailbox location and access rights.
userdb ldap {
  driver = ldap
  
  ldap_filter = (&(objectClass=user)(|(mail=%{user})(userPrincipalName=%{user})))

  fields {
    home = /srv/vmail/%{original_user|domain|lower}/%{original_user|username|lower}
    uid = vmail
    gid = vmail
    quota_rule = *:storage=%{ldap:msDS-cloudExtensionAttribute1}
    quota_rule2 = Trash:storage=500G
    quota_rule3 = Spam:storage=50M
    quota_storage_size = %{ldap:msDS-cloudExtensionAttribute1}
    quota_message_count = 30000
    quota_mailbox_message_count = 5000
  }
}

The password authentication works flawlessly, but no fields attributes are being returned, causing the entire connection to fail.

Here are a few lines from the log:

Jun 09 17:49:44 auth: Debug: Loading modules from directory: /usr/lib/dovecot/modules/auth
Jun 09 17:49:44 auth: Debug: Loading modules from directory: /usr/lib/dovecot/modules/auth
Jun 09 17:49:44 auth: Debug: Module loaded: /usr/lib/dovecot/modules/auth/libauthdb_ldap.so
Jun 09 17:49:44 auth: Debug: Read auth token secret from /run/auth-token-secret.dat
Jun 09 17:49:44 auth: Debug: ldap(ldaps://dc1.domain1.tld:636): initialization took 15 msecs
Jun 09 17:49:44 auth: Debug: conn unix:/run/auth-userdb (pid=20421,uid=0): Server accepted connection (fd=20)
Jun 09 17:49:44 auth: Debug: master in: USER    1      user1@domain1.tld protocol=doveadm        debug
Jun 09 17:49:44 auth(user1@domain1.tld): Debug: ldap: Performing userdb lookup
Jun 09 17:49:44 auth(user1@domain1.tld): Debug: ldap: userdb cache miss
Jun 09 17:49:44 auth(user1@domain1.tld): Debug: ldap: user search: base=dc=domain1,dc=tld scope=subtree filter=(&(objectClass=user)(|(mail=user1@domain1.tld)(msDS-cloudExtensionAttribute2=user1@domain1.tld)(msDS-cloudExtensionAttribute3=user1@domain1.tld)(msDS-cloudExtensionAttribute4=user1@domain1.tld)))
Jun 09 17:51:01 auth: Debug: conn unix:/run/auth-userdb (pid=20432,uid=0): Server accepted connection (fd=22)
Jun 09 17:51:01 auth: Debug: master in: USER    1      user2@domain2.tld   protocol=doveadm
Jun 09 17:51:01 auth(user2@domain2.tld): Debug: ldap: Performing userdb lookup
Jun 09 17:51:01 auth(user2@domain2.tld): Debug: ldap: userdb cache miss
Jun 09 17:51:01 auth(user2@domain2.tld): Debug: ldap: user search: base=dc=domain1,dc=tld scope=subtree filter=(&(objectClass=user)(|(mail=user2@domain2.tld)(msDS-cloudExtensionAttribute2=user2@domain2.tld)(msDS-cloudExtensionAttribute3=user2@domain2.tld)(msDS-cloudExtensionAttribute4=user2@domain2.tld)))
Jun 09 17:51:01 auth(user1@domain1.tld): Debug: ldap: Finished userdb lookup
Jun 09 17:51:01 auth(user1@domain1.tld): Debug: ldap: userdb cache miss
Jun 09 17:51:01 auth: Debug: ldap(ldaps://dc1.domain1.tld:636): initialization took 6 msecs
Jun 09 17:51:03 auth: Debug: userdb out: FAIL   1
Jun 09 17:51:03 auth: Debug: conn unix:/run/auth-userdb (pid=20421,uid=0): auth-master client: Disconnected: Connection closed (fd=20)

If anyone has any experience or insights into this mapping issue, I would be extremely grateful for any guidance. I am currently running Dovecot version 2.4 on an Ubuntu Server environment.

Thank you

Nicky

Did you already select the new AD user domain in the mail app general settings?
I don’t think that a manual configuration of auth-ldap.conf.ext is needed.
See Mail — NS8 documentation

Is this related to NethServer 7 or NethServer 8?

If it is about NethServer 8, please note that NS8 does not use Dovecot 2.4, so unfortunately we cannot provide much help with Dovecot-specific configuration or LDAP/AD integration issues in that version.

Since your authentication works and the problem appears to be in Dovecot’s LDAP userdb attribute mapping, you will likely get more accurate assistance from the Dovecot community. I suggest posting the question to the Dovecot mailing list or support channels, including your LDAP configuration and the relevant debug logs you already collected.

Please let us know if there is an NS7/NS8-specific component involved.

2 Likes

Thank you for your replies and for looking into this! Just to clarify and answer your questions: this setup is not related to NethServer 7 or NethServer 8, and I am not using the built-in mail apps or default configurations of those systems. This is a standalone, manual Dovecot installation on a clean Linux environment where I am building the configuration from scratch. That is why I am editing the auth-ldap.conf.ext directly and working with Dovecot 2.4. Since the issue is purely related to how Dovecot’s userdb handles LDAP attribute mapping and referrals specifically with a Samba AD DC (while OpenLDAP works flawlessly with the exact same mapping logic), you are absolutely right—this is a specific Dovecot/Active Directory behavior. I will follow your advice and look further into the Dovecot community and mailing lists to analyze the raw debug logs. Thanks again for your time and for pointing me in the right direction!

1 Like