0

I am using python-ldap to process an LDIF file and (conditionally) import the records from that file into an LDAP server. Every piece of documentation and every example I can find, just assumes LDIF records are additions. However the LDIF files my script processes are version 1 files with a changetype, like so:

version: 1

dn: cn=group,ou=groups,o=vault
changetype: add
cn: group
mail: [email protected]
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
-

According to the documentation of python-ldap I need to use modlist.addModlist for adds and modlist.modifyModlist for modifications.

My question is: how do I get from the parsed LDIF data to a modification in LDAP? Something along the lines of:

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)

The above does not work; modlist.modifyModlist() requires two arguments. Also, the entry contains just the exact lines from the LDIF in an array of tuples, including the changetype and the (mandatory) separator line with the single dash :-(

Do I really need to parse the entry data line by line and create my own modifications? What is the added value of the LDIF parser if that is the case?

2 Answers 2

0

First of all, you should be processing entries in parser's handle method instead of in an external loop after all of the records have been parsed. So this:

class myParser( LDIFParser ):

    def handle( self, dn, entry ):
        # Your code/logic here...

parser = myParser( open(....
parser.parse()

instead of:

parser = myParser( open(...
parser.parse()

for dn, entry...

As for the modlist, you need to pass the old entry (dictionary as presented in the handle method) and a new, modified dictionary with all unchanged items, new ones, modified ones and without the deleted ones. Something like this:

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 ) )
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for this response. Your example also assumes complete entries, not modification entries. After doing more tests and looking at the LDIF parser source code I concluded that processing LDIF modify records is not possible.
0

I did more research and tests.

With the current version (3.3.1) of python-ldap it is not possible to reliably process LDIF modify records. Consider the following LDIF snippet:

dn: cn=user,ou=org
changetype: modify
add: memberOf
memberOf: cn=group,o=org
-
delete: description
description: groupless
-
add: description
description: grouped
-

When reading this from an LDIF file with python-ldap, the data is transferred to a dict with key: [value] entries. However dict does not allow duplicate keys so the keys are merged which is undesirable.

This is the resulting 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']}

As you can see, it is no longer possible to determine which operation should come first (add or delete), or which value should be deleted and which value added (groupless or grouped).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.