Contents |
The program allows to export user accounts from Active Directory (AD) in to LDAP. It is applied if user accounts are stored in your organization in AD, and accounts OX users are stored in LDAP.
This program useful for:
This program useless for:
Program consists of two files settings.py and main.py. Settings.py contains common variable, which values are described in the comments. Main.py is, actually, body of the program.
The program is not the full completed. You can make changes, necessary for you.
Setup Python and python-ldap, python-psycopg2 components (example for Debian)
apt-get install python2.4 python-ldap python-psycopg2
Create in AD group 'OX_Users' and send in it the necessary users (in this example it is 'CN=OX_Users,OU=SupportUsers,DC=org')
Create in AD group 'OX_Groups' and send in it the necessary group of users (in this example it is 'CN=OX_Users,OU=SupportUsers,DC=org')
Move in settings.py information on:
Active Directory: AD_Server, AD_BaseDN, AD_User, AD_Password, AD_UsersFilter, AD_GroupFilter
LDAP: LDAP_Server, LDAP_BaseDN, LDAP_User, LDAP_Password, LDAP_UsersFilter, LDAP_GroupFilter, LDAP_ServiceUsers, LDAP_ServiceGroups
Postgre SQL: SQL_server, SQL_db_name, SQL_user, SQL_password
Note: add to Postres SQL config pg_hba.conf line
host <ox_db_name> <ox_user_name> 127.0.0.1 255.255.255.255 trust
where <ox_db_name> = SQL_db_name and <ox_user_name> = SQL_user from file settings.py
Path to Open-xchange /sbin directory: OX_SBIN_PATH
Last letter must be '/'
It is important:
To set another default password edit string in main.py file
attrs['userPassword'] = '1'
Run program:
python main.py
# -*- coding: cp1251 -*-
# settings.py
# Active Directory (AD) server settings
## IP address of the AD server
AD_Server = '10.0.0.1'
## Base DN of AD server
AD_BaseDN = 'DC=org'
## Name of the user, having access to AD (there is enough reading)
AD_User = 'CN=AD_READ_USER,DC=org'
## Password for AD_User
AD_Password = 'xxxxxxxx'
## AD users export filter
AD_UsersFilter = '(&(objectClass=person)(memberOf=CN=OX_Users,OU=SupportUsers,DC=org))'
## AD groups export filter
AD_GroupFilter = '(&(objectClass=group)(memberOf=CN=OX_Groups,OU=SupportUsers,DC=org))'
# LDAP server settings
## IP address of the LDAP server
LDAP_Server = '10.0.0.2'
## Base DN of LDAP
LDAP_BaseDN = 'dc=org'
## Name of the user having access to LDAP
##(Rights on add, edit, remove are necessary)
LDAP_User = 'cn=LDAP_WRITER,dc=org'
## Password for LDAP_User
LDAP_Password = 'xxxxxxxxx'
## Place for users in LDAP
LDAP_UsersFilter = 'ou=Users,ou=OxObjects,dc=org'
## Place for groups in LDAP
LDAP_GroupFilter = 'ou=Groups,ou=OxObjects,dc=org'
## Support or system users in LDAP
##(this users not editable, removable)
LDAP_ServiceUsers = ['mailadmin']
## Support or system groups in LDAP
##(this groups not editable, removable)
LDAP_ServiceGroups = ['Administration','users','OXUserAdmins','OXSMTPAdmins','OXResourceAdmins','OXIMAPAdmins','OXGroupAdmins','OXDNSAdmins']
## Default settings for new OX users in LDAP
DefaultOXUserSettings = {'gidNumber':'500','OXAppointmentDays':'7',
'OXGroupID':'500','OXTaskDays':'7',
'OXTimeZone':'Asia/Novosibirsk',
'OXDayviewEndTime':'19:00',
'OXDayviewStartTime':'8:00',
'preferredLanguage':'DE',
'lnetMailAccess':'TRUE',
'mailEnabled':'OK',
'o':'Organisation Name',
'shadowExpire':'0',
'shadowMax':'9999',
'shadowMin':'0',
'shadowWarning':'7',
'loginShell':'/bin/bash',
'userCountry':'Some country'
}
# Postgre SQL server settings
## IP address of SQL server
SQL_server = '127.0.0.1'
## OX database name
SQL_db_name = 'openxchange'
## User having access to SQL_db_name
##(Rights on add, edit, remove records are necessary)
SQL_user='openxchange'
## SQL_user password
SQL_password='xxxxxxxx'
## Path to Open-xchange /sbin directory
## Last letter must be '/' or '\'
OX_SBIN_PATH='/usr/local/openxchange/sbin/'
# This tale - sample.
# It is need, if your AD contain russian(cyrillic) names
# You may modify this tale for other language
#AD_Server = unicode(AD_Server,"cp1251").encode('utf8')
#AD_BaseDN = unicode(AD_BaseDN,"cp1251").encode('utf8')
#AD_User = unicode(AD_User,"cp1251").encode('utf8')
#AD_Password = unicode(AD_Password,"cp1251").encode('utf8')
#AD_UsersFilter = unicode(AD_UsersFilter,"cp1251").encode('utf8')
#AD_GroupFilter = unicode(AD_GroupFilter,"cp1251").encode('utf8')
#LDAP_Server = unicode(LDAP_Server,"cp1251").encode('utf8')
#LDAP_BaseDN = unicode(LDAP_BaseDN,"cp1251").encode('utf8')
#LDAP_User = unicode(LDAP_User,"cp1251").encode('utf8')
#LDAP_Password = unicode(LDAP_Password,"cp1251").encode('utf8')
#LDAP_UsersFilter = unicode(LDAP_UsersFilter,"cp1251").encode('utf8')
#LDAP_GroupFilter = unicode(LDAP_GroupFilter,"cp1251").encode('utf8')
#LDAP_ServiceUsers = unicode(LDAP_ServiceUsers,"cp1251").encode('utf8')
#LDAP_ServiceGroups = unicode(LDAP_ServiceGroups,"cp1251").encode('utf8')
# -*- coding: cp1251 -*-
# main.py
import ldap
import ldap.modlist as modlist
import settings
from psycopg import *
import subprocess
## Find adduser permission string
f = open(settings.OX_SBIN_PATH + "addusersql_ox","r")
ss = "-Dopenexchange.propfile"
text = 'start'
while text <> '':
text = f.readline()
if text.find(ss) > 0:
ss = text
text = ''
f.close
str_add = ss [: ss.find('$USERNAME') -1 ]
## Find deluser permission string
f = open(settings.OX_SBIN_PATH + "deluser_ox","r")
ss = "-Dopenexchange.propfile"
text = 'start'
while text <> '':
text = f.readline()
if text.find(ss) > 0:
ss = text
text = ''
f.close
ss = ss [: ss.find('$USERNAME') -1 ]
str_del = ss [19:]
# Connect to AD
try:
l = ldap.open(settings.AD_Server)
l.protocol_version = ldap.VERSION3
l.simple_bind(settings.AD_User,settings.AD_Password)
except ldap.LDAPError, e:
print e
# Export groups from AD
baseDN = settings.AD_BaseDN
searchScope = ldap.SCOPE_SUBTREE
searchFilter = settings.AD_GroupFilter
retrieveAttributes =['cn','distinguishedName','sAMAccountName']
try:
ldap_result_id = l.search(baseDN, searchScope, searchFilter, retrieveAttributes)
groups = {}
while 1:
result_type, result_data = l.result(ldap_result_id, 0)
if (result_data == []):
break
else:
if result_type == ldap.RES_SEARCH_ENTRY:
groups[result_data[0][1]['distinguishedName'][0]] = [result_data[0][1]['cn'][0],result_data[0][1]['sAMAccountName'][0],[]]
except ldap.LDAPError, e:
print e
# Export users from AD
searchFilter = settings.AD_UsersFilter
retrieveAttributes =['displayName','mail','sAMAccountName','memberOf']
try:
ldap_result_id = l.search(baseDN, searchScope, searchFilter, retrieveAttributes)
users = {}
while 1:
result_type, result_data = l.result(ldap_result_id, 0)
if (result_data == []):
break
else:
if result_type == ldap.RES_SEARCH_ENTRY:
try:
dname = result_data[0][1]['displayName'][0]
except:
dname = ' '
try:
mail = result_data[0][1]['mail'][0]
except:
mail = ' '
san = result_data[0][1]['sAMAccountName'][0].lower()
users[san] = [dname,mail]
for i in result_data[0][1]['memberOf']:
if i in groups:
groups[i][2].append(san)
except ldap.LDAPError, e:
print e
l.unbind
# Connect to LDAP
try:
l = ldap.open(settings.LDAP_Server)
l.protocol_version = ldap.VERSION3
l.simple_bind(settings.LDAP_User,settings.LDAP_Password)
except ldap.LDAPError, e:
print e
# Export groups from LDAP
baseDN = settings.LDAP_GroupFilter
searchScope = ldap.SCOPE_SUBTREE
searchFilter = '(&(cn=*)(gidNumber=*))'
retrieveAttributes = ['cn','gidNumber','memberUid']
MaxGid = 0
try:
ldap_result_id = l.search(baseDN, searchScope, searchFilter, retrieveAttributes)
ldap_groups = {}
while 1:
result_type, result_data = l.result(ldap_result_id, 0)
if (result_data == []):
break
else:
if (result_type == ldap.RES_SEARCH_ENTRY) and (not (result_data[0][1]['cn'][0] in settings.LDAP_ServiceGroups)):
ldap_groups[result_data[0][1]['cn'][0]] = [result_data[0][1]['gidNumber'][0],result_data[0][1]['memberUid']]
if MaxGid < int(result_data[0][1]['gidNumber'][0]):
MaxGid = int(result_data[0][1]['gidNumber'][0])
except ldap.LDAPError, e:
print e
# Refresh in LDAP members of the groups
for group in groups.values():
if group[1] in ldap_groups:
# refresh members list
NewDN='cn=' + group[1] + ',' + settings.LDAP_GroupFilter
old = {'memberUid':ldap_groups[group[1]][1]}
new = {'memberUid':group[2]}
if old != new:
ldif = modlist.modifyModlist(old,new)
l.modify(NewDN,ldif)
del ldap_groups[group[1]]
else:
# add new group
NewDN='cn=' + group[1] + ',' + settings.LDAP_GroupFilter
attrs = {}
attrs['objectClass'] = ['top','posixGroup']
attrs['cn'] = group[1]
attrs['gidNumber'] = str(MaxGid + 1)
attrs['memberUid'] = group[2]
MaxGid += 1
ldif = modlist.addModlist(attrs)
l.add(NewDN,ldif)
# Remove groups from LDAP,
# which are not present in AD
for i in ldap_groups:
NewDN='cn=' + i + ',' + settings.LDAP_GroupFilter
try:
l.delete(NewDN)
except ldap.LDAPError, e:
print e
del ldap_groups[i]
ldap_groups = None
groups = None
# Add all users read permission to GlobalAdresBook
GAB_Members = []
NewDN = settings.LDAP_UsersFilter
for i in settings.LDAP_ServiceUsers:
GAB_Members.append ('uid=' + i + ',' + NewDN)
for i in users:
GAB_Members.append ('uid=' + i + ',' + NewDN)
NewDN = settings.LDAP_UsersFilter.split(',')
NewDN = 'cn=AddressReadAdmins,o=AddressBook,' + ','.join(NewDN[1:])
try:
l.delete(NewDN)
except ldap.LDAPError, e:
print e
attrs = {}
attrs['cn'] = ['AddressReadAdmins']
attrs['objectClass'] = ['top','groupOfNames']
attrs['member'] = GAB_Members
ldif = modlist.addModlist(attrs)
l.add(NewDN,ldif)
# Export users from LDAP
baseDN = settings.LDAP_UsersFilter
searchScope = ldap.SCOPE_SUBTREE
searchFilter = '(&(uid=*)(uidNumber=*))'
retrieveAttributes = ['uid','uidNumber','mail','description']
MaxGid = 0
try:
ldap_result_id = l.search(baseDN, searchScope, searchFilter, retrieveAttributes)
ldap_users = {}
while True:
result_type, result_data = l.result(ldap_result_id, 0)
if result_data == []:
break
else:
if result_type == ldap.RES_SEARCH_ENTRY and result_data[0][1]['uid'][0] not in settings.LDAP_ServiceUsers:
ldap_users[result_data[0][1]['uid'][0]] = [result_data[0][1]['uidNumber'][0],result_data[0][1]['description'][0],result_data[0][1]['mail'][0]]
MaxGid = max(MaxGid, int(result_data[0][1]['uidNumber'][0]))
except ldap.LDAPError, e:
print e
# Connect to SQL
conx = connect(host=settings.SQL_server,database=settings.SQL_db_name,user=settings.SQL_user,password=settings.SQL_password)
cur = conx.cursor()
# Refresh in LDAP setings of the users
for i in users:
if i in ldap_users:
# refresh user setinngs
NewDN='uid=' + i + ',' + settings.LDAP_UsersFilter
try:
fam, im, otch = ldap_users[i][1].split()
except:
fam = ldap_users[i][1]
im = ' '
otch = ' '
old = {'description':ldap_users[i][1],'mail':ldap_users[i][2],'sn':fam,'givenName':im}
try:
fam, im, otch = users[i][0].split()
except:
fam = users[i][0]
im = ' '
otch = ' '
new = {'description':users[i][0],'mail':users[i][1],'sn':fam,'givenName':im}
if old != new:
ldif = modlist.modifyModlist(old,new)
l.modify(NewDN,ldif)
del ldap_users[i]
else:
# add new user
NewDN='uid=' + i + ',' + settings.LDAP_UsersFilter
try:
fam, im, otch = users[i][0].split()
except:
fam = users[i][0]
im = ' '
otch = ' '
attrs = settings.DefaultOXUserSettings
attrs['objectClass'] = ['top','shadowAccount','posixAccount','person','inetOrgPerson','OXUserObject']
attrs['cn'] = i
attrs['uid'] = i
attrs['uidNumber'] = str(MaxGid + 1)
attrs['homeDirectory'] = '/tmp'
attrs['sn'] = fam
attrs['givenName'] = im
attrs['mail'] = users[i][1]
attrs['description'] = users[i][0]
attrs['userPassword'] = '1'
MaxGid += 1
ldif = modlist.addModlist(attrs)
l.add(NewDN,ldif)
# add user mail container
NewDN = 'ou=addr,' + NewDN
attrs = {}
attrs['ou'] = 'addr'
attrs['objectClass'] = ['top','organizationalUnit']
ldif = modlist.addModlist(attrs)
l.add(NewDN,ldif)
# Setup OX folder permissions
sql = str_add + ' \'' + i + '\' ' + 'DE'
try:
subprocess.call(sql, shell=True)
except:
pass
# Add new user in SQL
sql = 'INSERT INTO usr_general_rights SELECT creating_date, created_from, changing_date, changed_from, \''
sql = sql + i
sql = sql + '\', addr_u, addr_r, addr_d, cont_u, cont_r, cont_d, data_u, data_r, data_d, serie_u, serie_r, serie_d, task_u, task_r, task_d, refer, proj_u, proj_r, proj_d, dfolder_u, dfolder_r, dfolder_d, doc_u, doc_r, doc_d, knowl_u, knowl_r, knowl_d, bfolder_u, bfolder_r, bfolder_d, bookm_u, bookm_r, bookm_d, pin_u, pin_r, pin_d, forum_n, fentrie_n, setup, pin_public, internal, int_groups, kfolder_u, kfolder_r, kfolder_d, webmail FROM sys_gen_rights_template WHERE login LIKE \'default_template\''
try:
cur.execute(sql)
except:
pass
conx.commit()
# Remove LDAP users,
# which are not present in AD
for i in ldap_users:
NewDN='uid=' + i + ',' + settings.LDAP_UsersFilter
NewDNadr='ou=addr,' + NewDN
try:
l.delete(NewDNadr)
except ldap.LDAPError, e:
print e
try:
l.delete(NewDN)
print 'delete user ' + i
except ldap.LDAPError, e:
print e
# Remove permissions to OX folder
sql = str_del + ' \'' + i + '\''
try:
subprocess.call(sql, shell=True)
except:
pass
# Remove user from SQL
sql = 'DELETE FROM usr_general_rights WHERE login LIKE \'' + i + '\''
try:
cur.execute(sql)
except:
pass
conx.commit()
del ldap_users[i]
ldap_users = None
users = None
l.unbind
cur.close()
conx.close