Experiments with pyasn1 and preread control

Andreas Hasenack ahasenack at terra.com.br
Tue Jun 5 23:12:41 CEST 2007


I have been having fun with controls. Today I tried to use the Pre-Read
control together with the modify+increment extension, so that
modify+increment becomes actually useful.

I first added the encoding part to the ldap.so module, but later got a
response from the pyasn1 mailing list and tried again in pure python.
The result is attached. It's not complete yet, just a test.

The script uses mod_increment to increment uidNumber and gidNumber by
one. Attached to the modify operation is the preread control, so the
response includes the value prior to the modification.

Here is the output of two consecutive runs. Both attributes started at
1000 in LDAP:

$ ./preread-asn1.py
res: (103, [], 2, [PreReadControl(1.3.6.1.1.13.1,1.3.6.1.1.13.1,'0M\x04\x1fcn=unixIdPool,dc=example,dc=com0*0\x13\x04\tgidNumber1\x06\x04\x0410000\x13\x04\tuidNumber1\x06\x04\x041000')])
$ ./preread-asn1.py
res: (103, [], 2, [PreReadControl(1.3.6.1.1.13.1,1.3.6.1.1.13.1,'0M\x04\x1fcn=unixIdPool,dc=example,dc=com0*0\x13\x04\tgidNumber1\x06\x04\x0410010\x13\x04\tuidNumber1\x06\x04\x041001')])

First one returns "1000", and the second one "1001" for both attributes.
Now it's at 1002.

The decoding part will probably be more difficult... As the control
response is a SearchResultEntry which is a bit more complex to decode.
-------------- next part --------------
#!/usr/bin/env python

import ldap
from pyasn1.type import univ
from pyasn1.codec.der import encoder
from ldap.controls import LDAPControl

class LDAPString(univ.OctetString): pass

class AttributeSelection(univ.SequenceOf):
    componentType = LDAPString("")

class PreReadControl(LDAPControl):
  """
  Pre-Read LDAP Control

  see RFC 4527
  """

  controlType = ldap.LDAP_CONTROL_PRE_READ

  def __init__(self, criticality, controlValue=None,encodedControlValue=None):
    LDAPControl.__init__(self, self.controlType, criticality, controlValue, encodedControlValue)

  def encodeControlValue(self, value):
    attributeSelection = AttributeSelection()
    for i in range(len(value)):
      attributeSelection.setComponentByPosition(i, value[i])
    res = encoder.encode(attributeSelection)
    return res

  def decodeControlValue(self, value):
    # XXX
    return repr(value)


uri = "ldap://localhost:389"
base = "dc=example,dc=com"
scope = ldap.SCOPE_SUBTREE
filter = "(objectClass=sambaUnixIdPool)"

ld = ldap.initialize(uri)
ld.protocol_version = ldap.VERSION3
ld.bind_s("uid=LDAP Admin,ou=System Accounts,dc=example,dc=com", "ldapadmin")

pr = PreReadControl(criticality=True, controlValue=['uidNumber','gidNumber'])
modlist = [(ldap.MOD_INCREMENT, "uidNumber", "1"),(ldap.MOD_INCREMENT, "gidNumber", "1")]
msg = ld.modify_ext("cn=unixIdPool,dc=example,dc=com", modlist, serverctrls = [pr])

res = ld.result3(msgid = msg, timeout = -1)
print "res:", res

# vim:ts=2:sw=2:et:ai:si


More information about the python-ldap mailing list