OpenLDAP → iRedMail LDAP Sync and Dovecot Authentication
Introduction
iRedMail brings already a very nice interface for management. The system is highly integrated and it includes an OpenLDAP server. Hence I already have a centralized OpenLDAP server I had the challenge to bring them somehow together. One way would have been to point iRedMail to the existing OpenLDAP server. The other way was to sync these two systems.
I decided to sync them, because I didn't want to bring any side effects or problems to this integrated system.
First I tried the syncrepl protocol that is provided by OpenLDAP. Syncrepl wouldn't do the job hence it synchronizes two OpenLDAP servers to the last bit, but I only need the mail users to be synced. So finally I decided to to do the sync with LDAP tools and bash scripting.
The Script
#!/bin/bash
#
# Sync users from another LDAP
#
# run in iRedMail-1.6.8/tools
#
. ../conf/global
. ../conf/core
#
# LDAP from which users will be synced (Source LDAP) fill in your data
#
urlAAI="ldaps://openldap.simmy.ch:636"
basednAAI="dc=simmy,dc=ch"
binddnAAI="cn=binduser,ou=Users,dc=simmy,dc=ch"
bindpwAAI="*"
#
# iRedMail LDAP (target LDAP) fill in your data
#
urlMAIL="ldap://mail.simmy.ch:389"
basednMAIL="o=domains,dc=simmy,dc=ch"
#binddnMAIL="cn=vmail,dc=simmy,dc=ch"
#bindpwMAIL="*"
binddnMAIL="cn=Manager,dc=simmy,dc=ch"
bindpwMAIL="*"
#
# common variables from iRedMail setup
#
STORAGE_BASE_DIRECTORY="/var/vmail/vmail1"
STORAGE_BASE="$(dirname ${STORAGE_BASE_DIRECTORY})"
STORAGE_NODE="$(basename ${STORAGE_BASE_DIRECTORY})"
#
# Search filter for groups on source LDAP server
s_filter="(&(|(objectclass=inetOrgPerson))(|(memberof= cn=hMail_Users,ou=Groups,dc=simmy,dc=ch)))"
#
# get users uid from Source LDAP (I here have parameter which distinguish
# different types of users(hrEduPersonPrimaryAffiliation=djelatnik) for employees in Source LDAP
#
ldapsearch -H ${urlAAI} -x -D "${binddnAAI}" -w "${bindpwAAI}" -b "${basednAAI}" "${s_filter}" "uid" > AAI.ldif
#
# process .ldif output so in one line is only users uid
#
# example: AAI.ldif contains ONLY users uid each in newline
# user1
# user2
# etc...
#
sed '/#/d' < AAI.ldif > newAAI.ldif; mv newAAI.ldif AAI.ldif
sed '/search:/d' < AAI.ldif > newAAI.ldif; mv newAAI.ldif AAI.ldif
sed '/result:/d' < AAI.ldif > newAAI.ldif; mv newAAI.ldif AAI.ldif
sed '/dn:/d' < AAI.ldif > newAAI.ldif; mv newAAI.ldif AAI.ldif
sed 's/uid: //' < AAI.ldif > newAAI.ldif; mv newAAI.ldif AAI.ldif
sed '/^$/d' < AAI.ldif > newAAI.ldif; mv newAAI.ldif AAI.ldif
#
# add users to array (each line in another member of array) and delete temporary file
#
declare -a AAIkorisnici
let i=0
while IFS=$'\n' read -r line_data; do
AAIkorisnici[i]="${line_data}"
((++i))
done < AAI.ldif
rm -f AAI.ldif
#
# PROCESSING USERS
#
let i=0
while (( ${#AAIkorisnici[@]} > i )); do
#
# check if user already in Target LDAP (already have mailbox)
#
checkuserMAIL=$(ldapsearch -x -H ${urlMAIL} -b "${basednMAIL}" -D "${binddnMAIL}" -w "${bindpwMAIL}" uid=${AAIkorisnici[i]} | grep uid: | awk '{print $1}')
if [ "${checkuserMAIL}" = 'uid:' ];
then
#
# user exist on Target LDAP ... so I will only synchronize password beetwen two LDAPs
#
printf "User ${AAIkorisnici[i]} already exists on mail server\n";
printf "Synchronize mail password on openldap.simmy.cha: ${AAIkorisnici[i]}\n";
ldapsearch -H ${urlAAI} -x -D "${binddnAAI}" -w "${bindpwAAI}" -b "${basednAAI}" uid=${AAIkorisnici[i]} "(hrEduPersonPrimaryAffiliation=djelatnik)" "uid" "userPassword" | perl -MMIME::Base64 -MEncode=decode -n -00 -e 's/\n +//g;s/(?<=:: )(\S+)/decode("UTF-8",decode_base64($1))/eg;binmode(STDOUT, ":utf8");print' > userAAIpwtoMAILpw.ldif
#
# put user data in variables and delete temporary file
#
userUID=$(grep uid: userAAIpwtoMAILpw.ldif | awk '{print $2}')
userPASSWORD=$(grep userPassword: userAAIpwtoMAILpw.ldif | awk '{print $2}')
userMAIL=${userUID}@hmail.simmy.org
rm -f userAAIpwtoMAILpw.ldif
ldapmodify -x -H ${urlMAIL} -D "${binddnMAIL}" -w "${bindpwMAIL}" <<EOF
dn: mail=${userMAIL},ou=Users,domainName=hmail.simmy.org,${basednMAIL}
changetype: modify
replace: userPassword
userPassword: ${userPASSWORD}
EOF
else
#
# user does not exist on Target LDAP so it will be added
#
printf "User does not exist on Target LDAP: ${AAIkorisnici[i]}\n";
printf "User will be added to mail server: ${AAIkorisnici[i]}\n";
#
# get user data ftom Source LDAP (in my case i need: givenName, sn, userPassword, uid)
#
ldapsearch -H ${urlAAI} -x -D "${binddnAAI}" -w "${bindpwAAI}" -b "${basednAAI}" uid=${AAIkorisnici[i]} "(hrEduPersonPrimaryAffiliation=djelatnik)" "givenName" "sn" "userPassword" "uid"| perl -MMIME::Base64 -MEncode=decode -n -00 -e 's/\n +//g;s/(?<=:: )(\S+)/decode("UTF-8",decode_base64($1))/eg;binmode(STDOUT, ":utf8");print' > userAAItoMAIL.ldif
#
# put user data in variables and delete temporary file
#
userUID=$(grep uid: userAAItoMAIL.ldif | awk '{print $2}')
userGIVENNAME=$(grep givenName: userAAItoMAIL.ldif | awk '{print $2}')
userSN=$(grep sn: userAAItoMAIL.ldif | awk '{print $2}')
userPASSWORD=$(grep userPassword: userAAItoMAIL.ldif | awk '{print $2}')
userMAIL=${userUID}@hmail.simmy.org
#maildir="$( hash_domain "hmail.simmy.org")/$( hash_maildir ${userUID} )"
maildir="/var/vmail/vmail1/hmail.simmy.org/$( hash_maildir ${userUID} )"
#/var/vmail/vmail1/hmail.simmy.org/n/e/o/neo-2024.03.29.18.25.30/
rm -f userAAItoMAIL.ldif
#
# and finaly create user on mailserver....
#
ldapadd -x -H ${urlMAIL} -D "${binddnMAIL}" -w "${bindpwMAIL}" <<EOF
dn: mail=${userMAIL},ou=Users,domainName=hmail.simmy.org,${basednMAIL}
objectClass: inetOrgPerson
objectClass: shadowAccount
objectClass: amavisAccount
objectClass: mailUser
objectClass: top
accountStatus: active
storageBaseDirectory: ${STORAGE_BASE}
homeDirectory: ${STORAGE_BASE_DIRECTORY}/${maildir}
mailMessageStore: ${STORAGE_NODE}/${maildir}
mail: ${userMAIL}
mailQuota: 1048576000
userPassword: ${userPASSWORD}
cn: ${userSN} ${userGIVENNAME}
sn: ${userSN}
givenName: ${userGIVENNAME}
uid: ${userUID}
shadowLastChange: 0
amavisLocal: TRUE
enabledService: internal
enabledService: doveadm
enabledService: lib-storage
enabledService: mail
enabledService: pop3
enabledService: pop3secured
enabledService: imap
enabledService: imapsecured
enabledService: managesieve
enabledService: managesievesecured
enabledService: sieve
enabledService: sievesecured
enabledService: smtp
enabledService: smtpsecured
enabledService: deliver
enabledService: lda
enabledService: forward
enabledService: senderbcc
enabledService: recipientbcc
enabledService: shadowaddress
enabledService: displayedInGlobalAddressBook
EOF
fi
((++i))
done
The script is located in /root/iRedMail-1.6.8/tools and must be run from there. I basically found this script in an iRedMail forum.
First the scripts filters all users from cn=hMail_Users,ou=Groups,dc=simmy,dc=ch on the source LDAP server. Then the script checks if a user exists on iRedMail LDAP and if not, it creates the user. Otherwise only the password will be updated.
ldap.conf
Using the ldap client requires to configure /etc/ldap/ldap.conf. Furthermore every single certificate has to be inserted in this file. In this case the root ca of simmy.ch has to be inserted (line 4). Only after that, the LDAP client trust the certificate of the OpenLDAP source server.
BASE dc=simmy,dc=ch
URI ldap://127.0.0.1:389
TLS_CACERT /etc/ssl/certs/iRedMail.crt
TLS_CACERT /etc/ssl/certs/ca_simmy.ch.crt
Useful links
https://www.openldap.org/doc/admin22/syncrepl.html
ToDo
Add a cronjob
Useful commands
ldapsearch -x -LLL -H ldaps://openldap.simmy.ch -d1 -ZZ
No Comments