This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
slapd-supann/lib/import

136 lines
5.1 KiB
Python
Executable File

#!/usr/bin/env python
import os
import hashlib
import argparse
import ldif
import sys
import ldap
import ldap.sasl
import ldap.dn
import ldap.modlist
import base64
parser = argparse.ArgumentParser(description='Load LDIF files into and LDAP server.')
parser.add_argument('ldifs', metavar='LDIF', nargs='+', help='files to parse')
parser.add_argument('-H', dest='url', help='URL of the LDAP server')
parser.add_argument('--quiet', dest='verbose', action='store_false', default=True, help='do not report all modifications')
parser.add_argument('--fake', action='store_true', default=False, help='do not apply modifications, only simulate them')
parser.add_argument('--merged-attribute', dest='merged_attribute', action='append',
default=[], help='attribute that should be merged, not replaced (old values are merged with the new ones)')
conn = ldap.initialize('ldapi://')
conn.sasl_interactive_bind_s("", ldap.sasl.external())
def lower_keys(d):
return dict((key.lower(), value) for key, value in d.iteritems())
def ssha_password(password):
'''Hash a password using salted SHA1'''
salt = os.urandom(4)
h = hashlib.sha1(password)
h.update(salt)
return "{SSHA}" + base64.urlsafe_b64encode(h.digest() + salt)
class MyLDIFParser(ldif.LDIFParser):
def __init__(self, *args, **kwargs):
self.entries = []
ldif.LDIFParser.__init__(self, *args, **kwargs)
def transform_entry(self, entry):
# crypt passwords with SSHA
for key in entry:
if key.lower() == 'userpassword':
hashed_passwords = []
for value in entry['userPassword']:
if not value.startswith('{'):
value = ssha_password(value)
hashed_passwords.append(value)
entry[key] = hashed_passwords
def handle(self, dn, entry):
self.transform_entry(entry)
self.entries.append((dn, lower_keys(entry)))
args = parser.parse_args()
args.merged_attribute = map(str.lower, args.merged_attribute)
# Array to store futures adds and modifies
adds = []
modifies = []
for ldif_path in args.ldifs:
parser = MyLDIFParser(file(ldif_path))
parser.parse()
parser.entries.sort(key=lambda x: ldap.dn.str2dn(x[0])[::-1])
for dn, attrs in parser.entries:
pass
try:
result = conn.search_s(dn, ldap.SCOPE_BASE)
old_attrs = lower_keys(result[0][1])
new_attrs = {}
# keep attributes to merge that are unchanged
for key in args.merged_attribute:
if key not in attrs:
new_attrs[key] = old_attrs[key]
for key in attrs:
# merge attributes with their old value
if key in args.merged_attribute:
new_attrs[key] = list(set(old_attrs[key])|set(attrs[key]))
else:
new_attrs[key] = attrs[key]
modlist = []
for key in old_attrs:
if key not in new_attrs:
modlist.append((ldap.MOD_DELETE, key, None))
for key in new_attrs:
new = set(new_attrs[key])
if key in old_attrs:
old = set(old_attrs[key])
if old & new:
if old-new:
modlist.append((ldap.MOD_DELETE, key, list(old-new)))
if new-old:
modlist.append((ldap.MOD_ADD, key, list(new-old)))
else:
modlist.append((ldap.MOD_REPLACE, key, list(new)))
else:
modlist.append((ldap.MOD_ADD, key, list(new)))
if modlist:
modifies.append((dn, modlist))
except ldap.NO_SUCH_OBJECT:
adds.append((dn, ldap.modlist.addModlist(attrs)))
for dn, add in adds:
try:
if not args.fake:
conn.add_s(dn, add)
if args.verbose:
attributes = [entry[0] for entry in add]
print '- added entry %s' % dn
for name, values in add:
print ' -', name, ':', ', '.join(values)
except ldap.LDAPError, e:
print >>sys.stderr, 'Unable to create entry %s: %s' % (dn, e)
for dn, modify in modifies:
try:
if not args.fake:
conn.modify_s(dn, modify)
if args.verbose:
print 'modified entry %s' % dn
for op, name, values in modify:
if op == ldap.MOD_ADD:
print ' - add values "', ', '.join(values), '" to attribute', name
elif op == ldap.MOD_DELETE:
if values == None:
print ' - removed all values of attribute', name
else:
print ' - removed values "', ', '.join(values), '" from attribute', name
elif op == ldap.MOD_REPLACE:
print ' - replaced values of attribute', name, 'with values "', ', '.join(values), '"'
except ldap.LDAPError, e:
print >>sys.stderr, 'Unable to modify entry %s: %s' % (dn, e)