# Integrate Microsoft Active Directory in iRedMail [TOC] __NOTE__: We tested this tutorial on Windows 2000, 2003, 2008 R2 server, if you tested it on other versions and works well, please let us know. [Contact us](http://www.iredmail.org/contact.html) ## Summary With Active Directory (AD) integration, you can get below features: * User authentication against Windows Active Directory. You can now manage mail user accounts, mail lists with AD. * Mail list support with group in AD. * Global LDAP Address Book with AD in Roundcube Webmail. * Account status support. Disable user in AD will cause this account disabled in iRedMail. Since AD uses different LDAP schema, you will lose some iRedMail special features. e.g. * Per-user, per-domain service control with LDAP (e.g. enable/disable POP3/IMAP/SMTP services). ## Requirements To integrate Microsoft Active Directory with iRedMail, you should have: * A working Linux/BSD server with iRedMail (OpenLDAP backend) installed. * A working Microsoft Windows (2000/2003) server, with Active Directory installed and working properly, listen on port 389 (ldap://) or 636 (ldaps://), and allow LDAP connections from iRedMail server. ## Install iRedMail Please follow [iRedMail installaion guides](http://iredmail.org/doc.html#installation_guide) to install iRedMail on Linux/BSD with OpenLDAP backend first, we will achieve this AD integration by simply modifying some configure files. ## Integrate Microsoft Active Directory with Postfix We assume: * Hostname of your AD server is `ad.example.com`, listen on port `389`. And it's accessible from iRedMail server. * We will use this hostname below, you can replace it by IP address of this AD server if you want. * If you want to force LDAP connection with LDAPS, use port `636` instead. * Base dn in AD is `dc=example,dc=com`, email addresses of all users end with `@example.com` (Your mail domain is `example.com`). * All user accounts and mail list accounts are placed under dn `cn=Users,dc=example,dc=com`. __Note:__ LDAP dn is case-insensitive. * For ldap connection, protocol version `3` is recommended. * Store all mails on Linux/BSD servers, not on AD server. * Storage directory is `/var/vmail/vmail1`, same as default in iRedMail. * Mailbox of user `support@example.com` will be `/var/vmail/vmail1/example.com/support/Maildir/` (Maildir format). ### Create user account in AD, used for LDAP query With iRedMail (OpenLDAP backend), we have a low-privileged account `cn=vmail,dc=xxx,dc=xxx` with read-only privilege. And we suggest you create a same account `vmail` in AD, with strong and complex password. __NOTE__: [Dovecot will treat characters as comment after a inline `#`, so please just don't use `#` in password](http://www.iredmail.org/forum/post8630.html#p8630) Please make sure this newly created user is able to connect to AD server with below command on iRedMail server: ```shell # ldapsearch -x -h ad.example.com -D 'vmail' -W -b 'cn=users,dc=example,dc=com' Enter password: password_of_vmail ``` If it prints all users stored in AD server, then it's working as expected. ### Enable LDAP query with AD in Postfix Disable unused iRedMail special settings: ```shell # postconf -e virtual_alias_maps='' # postconf -e sender_bcc_maps='' # postconf -e recipient_bcc_maps='' # postconf -e relay_domains='' # postconf -e relay_recipient_maps='' ``` Add your mail domain name in `smtpd_sasl_local_domain` and `virtual_mailbox_domains`: ```shell # postconf -e smtpd_sasl_local_domain='example.com' # postconf -e virtual_mailbox_domains='example.com' ``` Change transport maps setting: ``` # postconf -e transport_maps='hash:/etc/postfix/transport' ``` Enable AD query. __Note__: We will create these 3 files later. * Verify SMTP senders ```shell # postconf -e smtpd_sender_login_maps='proxy:ldap:/etc/postfix/ad_sender_login_maps.cf' ``` * Verify local mail users ```shell # postconf -e virtual_mailbox_maps='proxy:ldap:/etc/postfix/ad_virtual_mailbox_maps.cf' ``` * Verify local mail lists/groups. ``` # postconf -e virtual_alias_maps='proxy:ldap:/etc/postfix/ad_virtual_group_maps.cf' ``` * Create/edit file: `/etc/postfix/transport`. ``` example.com dovecot ``` __Note__: `dovecot` used here is a Postfix transport defined in `/etc/postfix/master.cf`, used to deliver received emails to local user mailboxes. Run `postmap` so that postfix can read it: ``` # postmap hash:/etc/postfix/transport ``` * Create file: `/etc/postfix/ad_sender_login_maps.cf`: ``` server_host = ad.example.com server_port = 389 version = 3 bind = yes start_tls = no bind_dn = vmail bind_pw = password_of_vmail search_base = cn=users,dc=example,dc=com scope = sub query_filter = (&(userPrincipalName=%s)(objectClass=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2))) result_attribute= userPrincipalName debuglevel = 0 ``` * Create file: `/etc/postfix/ad_virtual_mailbox_maps.cf`: ``` server_host = ad.example.com server_port = 389 version = 3 bind = yes start_tls = no bind_dn = vmail bind_pw = passwd_of_vmail search_base = cn=users,dc=example,dc=com scope = sub query_filter = (&(objectclass=person)(userPrincipalName=%s)) result_attribute= userPrincipalName result_format = %d/%u/Maildir/ debuglevel = 0 ``` __Note__: Here, we hard-code user's mailbox path to be `[domain]/[username]/Maildir` in `result_format` setting. for example: `example.com/postmaster/Maildir`. * Create file: `/etc/postfix/ad_virtual_group_maps.cf`: ``` server_host = ad.example.com server_port = 389 version = 3 bind = yes start_tls = no bind_dn = vmail bind_pw = password_of_vmail search_base = cn=users,dc=example,dc=com scope = sub query_filter = (&(objectClass=group)(mail=%s)) special_result_attribute = member leaf_result_attribute = mail result_attribute= userPrincipalName debuglevel = 0 ``` __Note__: * If your user have email address in both `mail` and `userPrincipalName`, you will get duplicate result. Comment out `leaf_result_attribute` line will fix it. * If your mail group account doesn't contain attribute `mail` and `userPrincipalName`, please try `query_filter = (&(objectClass=group)(sAMAccountName=%u))` instead. Also, we need to remove iRedAPD related settings in Postfix: 1. Open Postfix config file `/etc/postfix/main.cf` 1. Remove setting `check_policy_service inet:127.0.0.1:7777`. ### Verify LDAP query with AD in Postfix We can now use command line tool `postmap` to verify AD integration in postfix. Before testing, we have to create two testing mail accounts first: 1. Create a mail user in AD. e.g. `user@example.com`. 1. Create a mail group in AD. e.g. `testgroup@example.com`, then assign mail user `user@example.com` as group member. 1. Query mail user account with below command: ```shell # postmap -q user@example.com ldap:/etc/postfix/ad_virtual_mailbox_maps.cf example.com/user/Maildir/ ``` If nothing returned by the command, it means LDAP query doesn't get expected result. Please set `debuglevel = 1` file `/etc/postfix/ad_virtual_mailbox_maps.cf`, then query again, it now will print detailed debug message. If you're not familiar with LDAP related info, please post the debug message in our [online support forum](http://www.iredmail.org/forum/) to get help. Verify sender login check: ``` # postmap -q user@example.com ldap:/etc/postfix/ad_sender_login_maps.cf user@example.com ``` Verify mail group ``` # postmap -q testgroup@example.com ldap:/etc/postfix/ad_virtual_group_maps.cf user@example.com ``` __NOTE__: `postmap` return nothing if: 1. mail group doesn't exist 1. mail group doesn't have any members ## Enable Active Directory integration in Dovecot To query AD instead of local LDAP server, we have to modify Dovecot config file `/etc/dovecot/dovecot-ldap.conf` like below: ``` hosts = ad.example.com:389 ldap_version = 3 auth_bind = yes dn = vmail dnpass = passwd_of_vmail base = cn=users,dc=example,dc=com scope = subtree deref = never user_filter = (&(userPrincipalName=%u)(objectClass=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2))) pass_filter = (&(userPrincipalName=%u)(objectClass=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2))) pass_attrs = userPassword=password default_pass_scheme = CRYPT user_attrs = =home=/var/vmail/vmail1/%Ld/%Ln/Maildir/,=mail=maildir:/var/vmail/vmail1/%Ld/%Ln/Maildir/ ``` Restart dovecot service to make it work. __Note__: we don't have per-user quota limit here, you can set a hard-coded quota for all users in `/etc/dovecot/dovecot.conf`. For example: ``` plugin { [... omit other settings here ...] # Format: integer number + M/G/T (M -> MB, G -> GB, T -> TB). quota_rule = *:storage=1G } ``` Now use command `telnet` to verify AD query after restarted Dovecot service: ``` # telnet localhost 143 # <- Type this * OK [...] Dovecot ready. . login user@example.com password_of_user # <- Type this. Do not miss the dot in the beginning . OK [...] Logged in ^] # <- Quit telnet with "Ctrl+]", then type 'quit'. ``` Note: Do NOT miss the dot character before `login` command. if it returns `Logged in`, then dovecot + AD works. ## Enable Active Directory integration in Roundcube webmail for Global LDAP Address Book Edit roundcube config file `config/config.inc.php`, comment out the LDAP address book setting added by iRedMail, and add new setting for AD like below: * on RHEL/CentOS and OpenBSD: it's `/var/www/roundcubemail/config/config.inc.php` * on Debian/Ubuntu: it's `/usr/share/apache2/roundcubemail/config/config.inc.php` * on FreeBSD: it's `/usr/local/www/roundcubemail/config/config.inc.php` ```php # # "sql" is personal address book stored in roundcube database. # "example.com" is new LDAP address book with AD, we will create it below. # $rcmail_config['autocomplete_addressbooks'] = array("sql", "example.com"); # # Global LDAP Address Book with AD. # $config['ldap_public']["global_ldap_abook"] = array( 'name' => 'Global LDAP Address Book', 'hosts' => array("ad.example.com"), // <- Set AD hostname or IP address here. 'port' => 389, 'use_tls' => false, // <- Set to true if you want to use LDAP over TLS. 'ldap_version' => '3', 'network_timeout' => 10, 'user_specific' => false, 'base_dn' => "cn=users,dc=example,dc=com", // <- Set base dn in AD 'bind_dn' => "vmail", // <- bind dn 'bind_pass' => "password_of_vmail", // <- bind password 'writable' => false, // <- Do not allow mail user write data back to AD. 'search_fields' => array('mail', 'cn', 'sAMAccountName', 'displayname', 'sn', 'givenName'), // mapping of contact fields to directory attributes 'fieldmap' => array( 'name' => 'cn', 'surname' => 'sn', 'firstname' => 'givenName', 'title' => 'title', 'email' => 'mail:*', 'phone:work' => 'telephoneNumber', 'phone:mobile' => 'mobile', 'street' => 'street', 'zipcode' => 'postalCode', 'locality' => 'l', 'department' => 'departmentNumber', 'notes' => 'description', 'name' => 'cn', 'surname' => 'sn', 'firstname' => 'givenName', 'title' => 'title', 'email' => 'mail:*', 'phone:work' => 'telephoneNumber', 'phone:mobile' => 'mobile', 'phone:workfax' => 'facsimileTelephoneNumber', 'street' => 'street', 'zipcode' => 'postalCode', 'locality' => 'l', 'department' => 'departmentNumber', 'notes' => 'description', 'photo' => 'jpegPhoto', ), 'sort' => 'cn', 'scope' => 'sub', //'filter' => "(&(objectclass=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))", 'filter' => "(mail=*@*)", 'fuzzy_search' => true, 'vlv' => false, // Enable Virtual List View to more efficiently fetch paginated data (if server supports it) 'sizelimit' => '0', // Enables you to limit the count of entries fetched. Setting this to 0 means no limit. 'timelimit' => '0', // Sets the number of seconds how long is spend on the search. Setting this to 0 means no limit. 'referrals' => false, // Sets the LDAP_OPT_REFERRALS option. Mostly used in multi-domain Active Directory setups ); ``` ## Additions documents * If your mail domain name is different than Windows Active Directory domain: [http://www.iredmail.org/forum/topic3165-integration-with-windows-domain.html](http://www.iredmail.org/forum/topic3165-integration-with-windows-domain.html)