Synchronisation des utilisateurs OSE basée sur Active Directory Collaboration Zimbra

1. Origines


Lors de la configuration d'un serveur zimbra, j'ai rencontré le problème de synchronisation des utilisateurs par groupe dans Active Directory (AD). Si nous créons un nouvel utilisateur dans AD, il est normalement ajouté, mais si nous rendons l'accès au serveur de messagerie par groupe, alors pour la première fois tous les utilisateurs sont synchronisés. Mais alors, les changements dans le groupe n'affectent pas les changements dans les utilisateurs du serveur de messagerie zimbra.

Ce qui n'aimait pas dans ces articles, c'est l'utilisation d'un script PowerShell (pourquoi, s'il y a ldapsearch) et l'utilisation constante de l'utilitaire zmprov, et lorsqu'un grand nombre d'utilisateurs sont synchronisés, le script s'exécute pendant longtemps

2. Les données source


Serveur OS: CentOS 7
Langage de script: bash
Domaine Zimbra: test.ru
Serveur Zimbra: zimbra.test.local Domaine
Active Directory: test.local
Groupe AD pour l'accès au courrier: mail

Un utilisateur peut avoir un courrier différent de sa connexion, tel que le courrier ajoutez-le à AD dans le champ de messagerie et utilisez-le pour créer un alias dans zimbra (par exemple, Vasya Pupkin se connecte au système en utilisant le nom d'utilisateur vasia, mais le courrier doit être envoyé et reçu en tant qu'utilisateur v.pupkin@test.ru)

3. Schéma du script


  1. Enregistrer dans le fichier utilisateur AD inclus dans le groupe de messagerie
  2. Nous enregistrons tous les utilisateurs de zimbra avec tous les attributs dans un fichier
  3. Nous divisons le fichier avec une liste de tous les utilisateurs de zimbra en fichiers de format: nom de fichier - connexion utilisateur, contenu - attributs utilisateur
  4. Nous supprimons de la liste des utilisateurs les comptes système zimbra (admin, gal, antivirus)
  5. Comparer la liste d'utilisateurs AD et zimbra
  6. Créer un fichier avec les commandes pour ajouter, supprimer (dans mon cas, bloquer l'utilisateur), synchroniser et créer des alias
  7. Appliquer ces actions dans zimbra (un appel à zmprov)
  8. Envoyez un rapport à l'administrateur par mail (si vous avez quelque chose à envoyer)
  9. Supprimer les fichiers et répertoires temporaires

4. Script de synchronisation


Le script a deux modes de fonctionnement - il se lance sans paramètres, alors seuls le blocage et l'ajout d'utilisateurs fonctionneront. Et commencez par le paramètre «all», puis tous les utilisateurs du groupe de messagerie dans AD seront synchronisés.

Il est également nécessaire de prêter attention à l'utilisation de l'utilitaire de décodage base64 dans la fonction de synchronisation, il doit être utilisé pour les champs AD dans lesquels des caractères russes sont utilisés.

Le script lui-même:
#!/bin/bash
#
#1.  
#
#1.1  
#   
path="/mnt/zimbra/user-sync"
# 
timestamp=`date +%F-%H-%M`
#   
tmp_dir=$path/tmp
#      zimbra
zim_us=$tmp_dir/zim-us
#   
log_dir=$path/log
# -
log=$log_dir/grouplog_$timestamp.txt
#      
usname=$tmp_dir/usname
#          zmprov
zmcmdfile=$tmp_dir/zmcmdfile
#        AD 
userfil=$tmp_dir/userfil
# 
mutt="/usr/bin/mutt"

#
#1.2   zimbra
#  Zimbra
domain="test.ru"
#   zmprov
zmprov="/opt/zimbra/bin/zmprov"
#
#1.3    AD  LDAP
#LDAP search
ldapsearch=/opt/zimbra/common/bin/ldapsearch
#    ( ,   (   ))
ldap_server="ldap://test.local:389"
# OU 
basedn="DC=test,DC=local"
#      AD  LDAP
binddn="CN=zimbra,CN=Users,DC=test,DC=local"
bindpw="qwe123" #user password 
#  -     mail
filter="(memberof=cn=mail,cn=users,dc=test,dc=local)"
#    (,             )
fields="sAMAccountName mail description displayName givenName cn sn department title"
#  

# 

# 
#   
function err_log()
{
if [ $1 -eq 0 ]; then
		#echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
		#echo
		echo $2" [Ok]"  >> $log
	else
		#echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]"
		#echo
		echo  $2" [Fail]" >> $log
	fi
}

#  
function if_path ()
{
	#      
	if [ ! -d $1 ]; then
	#   
	echo "  $1..." >> $log
	mkdir -p $1
	err_log $? "  $1"
	
else
	echo "  $1 " >> $log	
fi
}

#      AD
function search_users_AD()
{
	echo "     AD..." >> $log
	$ldapsearch -x -o ldif-wrap=no -H $ldap_server -D $binddn -w $bindpw -b $basedn $filter $fields | 
	grep sAMAccountName | 
	egrep -v '^#|^$' | 
	awk '{print $2}' |
	sort > $usname.ad
	echo "Found () "`cat $usname.ad | wc -l`" Group in AD (  AD)" >> $log
}

function all_user_attr_zimbra()
{
	#        
	$zmprov -l gaa -v $domain > $usname.gaa
	#         
	cd $zim_us
	#      ,     
	csplit $usname.gaa --prefix='user.' --suffix-format='%03d.zim' --elide-empty-files -s /"# name"/ '{*}'

	#   .      zimbra  
	for i in $( ls $zim_us )
	do
		nam=`grep "# name" $zim_us/$i | awk '{ print $3}' | sed 's/@.*//g'`
		mv -f $zim_us/$i $zim_us/$nam
	done
	cd $path
}

#      zimbra 
function search_user_zimbra()
{
	echo "    zimbra..." >> $log
	ls $zim_us | sort > $usname.tem
	#    .  $path/system.acc    
	diff -u -i $usname.tem $path/system.acc  | sed 1,3d | grep ^- | cut -c 2- | sort > $usname.zim
	#rm -f $usname.tem
	echo "Found () "`cat $usname.zim | wc -l`" Group in Zimbra (  Zimbra)" >> $log
	
}

#    (   
function diff_user_list()
{
	diff -u -i $usname.zim $usname.ad | sed 1,3d | sed '/@.*/d' > $usname.diff
}

# 
function adduser()
{
#    	
adddif=`grep ^+ $usname.diff | sed '1!d'`
	if [ -n $adddif ];
	then
		for addus in $( grep ^+ $usname.diff | cut -c 2- )
		do
			#       zimbra (  - ,  - )
                        ifclos=`grep "zimbraAccountStatus:" $zim_us/$addus | awk '{print $2}' | cut -c -1`
			if [ $ifclos = "c" ];
			then
				echo "ma $addus@$domain zimbraAccountStatus active" >> $zmcmdfile
				echo " $addus " >> $tmp_dir/send.txt
				if [ $addus != "" ];
				then
					sync_one_user $addus
				fi
			else
				#123456 -  ,    .   ,         AD
				echo "ca $addus@$domain 123456" >> $zmcmdfile
				echo " $addus " >> $tmp_dir/send.txt
				if [ $addus != "" ];
				then
					sync_one_user $addus
				fi
			fi
		done
		
	fi
}

#   
function block_user()
{
	deldif==`grep ^- $usname.diff | sed '1!d'`
	if [ -n $deldif ];
	then
		for delus in $( grep ^- $usname.diff | cut -c 2- )
		do
			#zimbraAccountStatus closed
			if [ $delus != "" ];
			then
				ifclos=`grep "zimbraAccountStatus:" $zim_us/$delus | awk '{print $2}'`
				if [ "$ifclos" != "closed" ];
				then
					echo "user closed - $delus"
					echo "ma $delus@$domain zimbraAccountStatus closed" >> $zmcmdfile
					echo " $delus !     !" >> $tmp_dir/send.txt
					echo $delus >> $path/close.1
					cat $path/close.1 | sort > $path/close.diff
					echo "$delus" 
				fi
			fi
		done
	fi
}

#   
function ifattr()
{
	if1char=`echo $2 | cut -c -1`
	if [[ -n $2 && $if1char != "" ]];
	#if [ $2 != "" ];
	then 
	    #echo $2
	    echo -n " $1 \"$2\""  >> $zmcmdfile
	fi
}

#  
function sync_one_user()
{
	echo "  $1..." >> $log
	$ldapsearch -x -o ldif-wrap=no -H $ldap_server -D $binddn -w $bindpw -b $basedn "(sAMAccountName=$1)" $fields > $userfil/$1.ad
	
	#   
	echo -n  "ma "$1 >> $zmcmdfile
	
	#samacc=`grep "sAMAccountName:" $userfil/$1 | awk '{print $2}'`  
		
	description=`grep "description:" $userfil/$1.ad | awk '{split ($0, a, ": "); print a[2]}'`
	#echo $description
	ifattr "description" "$description"
		
	displayName=`grep "displayName:" $userfil/$1.ad | awk '{split ($0, a, ": "); print a[2]}' | base64 -d`
	ifattr "displayName" "$displayName"
	
	givenName=`grep "givenName:" $userfil/$1.ad | awk '{split ($0, a, ": "); print a[2]}' | base64 -d`
	ifattr "givenName" "$givenName"
	
	cn=`grep "cn:" $userfil/$1.ad | awk '{split ($0, a, ": "); print a[2]}'`
	ifattr "cn" "$cn"
	
	sn=`grep "sn:" $userfil/$1.ad | awk '{split ($0, a, ": "); print a[2]}' | base64 -d`
	ifattr "sn" "$sn"
	
	department=`grep "department:" $userfil/$1.ad | awk '{split ($0, a, ": "); print a[2]}' | base64 -d`
	ifattr "company" "$department"
	
	title=`grep "title:" $userfil/$1.ad | awk '{split ($0, a, ": "); print a[2]}' | base64 -d`
	ifattr "title" "$title"
	
	#    
	echo >> $zmcmdfile
	# 
	mailnew=`grep "mail:" $userfil/$1.ad | awk '{print $2}'`
	if [ "$mailnew" != "" ];
	then 
	# [ -n $mailnew ] 
	#    echo $2
		#    
		#${1,,} -      
		useralias=`grep "zimbraMailAlias:" $zim_us/${1,,} | awk '{print $2}'`
	    if [ $useralias != $mailnew ];
		then
			echo "aaa \"$1@$domain\" \"$mailnew\""  >> $zmcmdfile
		fi
	fi
	#ifattr "mail" $mailnew
#	echo $mailnew
	echo "  $1 " >> $tmp_dir/send.txt 
	
#	echo " $1 - $atrruser"
	
	#echo "Found () "`cat $usname.ad | wc -l`" Group in AD (  AD)" >> $log
}


# 
date +%F-%H-%M
#2.  
#  
if_path $path
#  
if_path $tmp_dir
# -
if_path $log_dir
#   
if_path $userfil
#    
if_path $zim_us

#         zmprov
:> $zmcmdfile
#    
:> $tmp_dir/send.txt
#3.     AD 
search_users_AD

#4.    zimbra 
all_user_attr_zimbra
#  ()
search_user_zimbra

#5.    
diff_user_list
# 
block_user
#    
adduser

#tckb    "all"  ,        mail AD
if [[ -n $1 && $1 = "all" ]];
then
	for us in $(cat $usname.ad );
	do
	#	echo $us
		sync_one_user $us
	done
fi
#      zmprov  
$zmprov -f $zmcmdfile
#       
cat $zmcmdfile >> $log
#     (  )
if [ -s $tmp_dir/send.txt ];
then
	$mutt  -s "   $timestamp" admins@test.ru -a $log < $tmp_dir/send.txt
fi

#    
rm -R -f $tmp_dir


5. Conclusion


En général, le script s'est avéré assez rapide, l'utilitaire zmprov n'est utilisé que deux fois, les autres utilitaires et fonctions fonctionnent beaucoup plus rapidement.

6. Références


Lors de la création de cet article, des idées et des articles ont été utilisés:

1. Andrey Sysoev
2. DruGoeDeLo
3. Mon commentaire sur l'article 1) avec un script pour synchroniser les listes de diffusion

All Articles