Sincronización de usuarios OSE de colaboración basada en Active Directory de Zimbra

1. Antecedentes


Al configurar un servidor zimbra, encontré el problema de sincronizar usuarios por grupo en Active Directory (AD). Si creamos un nuevo usuario en AD, normalmente se agrega, pero si hacemos acceso al servidor de correo por grupo, por primera vez, todos los usuarios se sincronizan. Pero luego, los cambios en el grupo no afectan los cambios en los usuarios del servidor de correo zimbra.

Lo que no le gustó en estos artículos es el uso de un script de PowerShell (por qué, si hay ldapsearch) y el uso constante de la utilidad zmprov, y cuando un gran número de usuarios están sincronizados, el script se ejecuta durante mucho tiempo

2. Los datos de origen


SO del servidor: CentOS 7
Lenguaje de script: bash
Dominio de Zimbra: test.ru
Servidor de Zimbra: zimbra.test.local Dominio de
Active Directory: test.local
Grupo de AD para acceso a correo: correo

Un usuario puede tener un correo diferente de su nombre de usuario, tal correo agréguelo a AD en el campo de correo y úselo para crear un alias en zimbra (por ejemplo, Vasya Pupkin inicia sesión en el sistema usando el nombre de usuario vasia, pero el correo debe enviarse y recibirse como usuario v.pupkin@test.ru)

3. Esquema del guión


  1. Guardar en el archivo de usuario AD incluido en el grupo de correo
  2. Guardamos todos los usuarios de zimbra con todos los atributos en un archivo
  3. Dividimos el archivo con una lista de todos los usuarios de zimbra en archivos de formato: nombre de archivo - inicio de sesión de usuario, contenido - atributos de usuario
  4. Eliminamos de la lista de usuarios las cuentas del sistema zimbra (admin, gal, antivirus)
  5. Compare la lista de usuarios de AD y zimbra
  6. Crear un archivo con los comandos para agregar, eliminar (en mi caso, bloquear al usuario), sincronizar y crear alias
  7. Aplicar estas acciones en zimbra (una llamada a zmprov)
  8. Envíe un informe al administrador por correo (si tiene algo que enviar)
  9. Eliminar archivos y directorios temporales

4. Script de sincronización


El script tiene dos modos de operación: se inicia sin parámetros, luego solo funciona el bloqueo y la adición de usuarios. Y comience con el parámetro "todos", luego todos los usuarios del grupo de correo en AD se sincronizarán.

También es necesario prestar atención al uso de la utilidad de decodificación base64 en la función de sincronización, debe usarse para campos AD en los que se usan caracteres rusos.

El guión en sí:
#!/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. Conclusión


En general, el script resultó ser bastante rápido, la utilidad zmprov se usa solo dos veces, el resto de las utilidades y funciones funcionan mucho más rápido.

6. Referencias


Al crear este artículo, se utilizaron ideas y artículos:

1. Andrey Sysoev
2. DruGoeDeLo
3. Mi comentario sobre el artículo 1) con un script para sincronizar listas de correo

All Articles