#python #ldap #python-ldap #ldif
Вопрос:
Я использую python-ldap для обработки файла LDIF и (условно) импорта записей из этого файла на сервер LDAP. Каждая часть документации и каждый пример, который я могу найти, просто предполагает, что записи LDIF являются дополнениями. Однако файлы LDIF, которые обрабатывает мой скрипт, являются файлами версии 1 с типом изменений, например так:
version: 1 dn: cn=group,ou=groups,o=vault changetype: add cn: group mail: group@a.org member: cn=users,ou=users,o=vault dn:cn=users,ou=users,o=vault changetype: modify add: memberOf memberOf: cn=group,ou=groups,o=vault -
Согласно документации python-ldap, которую мне нужно использовать modlist.addModlist
для добавлений и modlist.modifyModlist
модификаций.
Мой вопрос: как мне перейти от проанализированных данных LDIF к модификации в LDAP? Что-то вроде:
parser = ldif.LDIFRecordList(open(filename,'r')) parser.parse() for dn, entry in parser.all_records: if entry['changetype'] == "add": crud = modlist.addModlist(entry) ldapcon.add_s(dn,crud) else: crud = modlist.modifyModlist(entry) ldapcon.modify_s(dn,crud)
Вышесказанное не работает; modlist.modifyModlist()
требуется два аргумента. Кроме того, entry
он содержит только точные строки из LDIF в массиве кортежей, включая тип изменений и (обязательную) разделительную строку с одним тире 🙁
Действительно ли мне нужно анализировать входные данные строка за строкой и создавать свои собственные изменения? Какова дополнительная ценность анализатора LDIF, если это так?
Ответ №1:
Прежде всего, вы должны обрабатывать записи в методе обработки синтаксического анализатора, а не во внешнем цикле после того, как все записи будут проанализированы. Так что это:
class myParser( LDIFParser ): def handle( self, dn, entry ): # Your code/logic here... parser = myParser( open(.... parser.parse()
вместо:
parser = myParser( open(... parser.parse() for dn, entry...
Что касается модлиста, вам нужно передать старую запись (словарь, представленный в методе дескриптора) и новый, измененный словарь со всеми неизмененными элементами, новыми, измененными и без удаленных. Что-то вроде этого:
class myParser( LDIFParser ): def handle( self, dn, entry ): # Filter for objectClass if needed if b'some_class' not in entry['objectClass']: return # new_entry is a copy of old entry new_entry = entry.copy() # Add an attribute named 'add_new' new_entry['add_new'] = 'Added' # Modify an attribute named 'modify existing' new_entry['modify_existing'] = [b'99'] print( 'OLD:', entry ) print( 'NEW:', new_entry ) print( ldap.modlist.modifyModlist( entry, new_entry ) )
Комментарии:
1. Спасибо вам за этот ответ. В вашем примере также предполагается наличие полных записей, а не записей изменений. После проведения дополнительных тестов и изучения исходного кода анализатора LDIF я пришел к выводу, что обработка записей изменения LDIF невозможна.
Ответ №2:
Я провел больше исследований и тестов.
С текущей версией (3.3.1) python-ldap невозможно надежно обрабатывать записи об изменении LDIF. Рассмотрим следующий фрагмент LDIF:
dn: cn=user,ou=org changetype: modify add: memberOf memberOf: cn=group,o=org - delete: description description: groupless - add: description description: grouped -
При чтении этого из файла LDIF с python-ldap данные передаются в dict
файл с key: [value]
записями. Однако dict
не позволяет дублировать ключи, поэтому ключи объединяются, что нежелательно.
Это и есть результат dict
:
{'changetype': [b'modify'], 'add': [b'memberOf', b'description'], 'memberOf': [b'cn=group,o=org'], '-': [None, None, None], 'delete': [b'description'], 'description': [b'groupless', b'grouped']}
Как вы можете видеть, больше невозможно определить, какая операция должна быть первой (добавление или удаление), или какое значение должно быть удалено, а какое добавлено (без групп или сгруппировано).