[python-ldap] Deref request control appears to not recieve results,

William Brown william at blackhats.net.au
Wed Aug 26 03:35:26 CEST 2015


Hi,

I am trying to write a dereference control [0] to use for the 389ds project,
with the intent that once it is working, to include it in python-ldap.

I am adding the control to the search with:

try:
    drc = DereferenceControl(True, deref=deref.encode('UTF-8'))
    sctrl = [drc]
    self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)

    res = self.search(base, scope, *args, **kwargs)
    resp_type, resp_data, resp_msgid, decoded_resp_ctrls = self.result3(res,
resp_ctrl_classes={CONTROL_DEREF: DereferenceControl})
finally:
    self.set_option(ldap.OPT_SERVER_CONTROLS, [])
return resp_data, decoded_resp_ctrls

The request is formatted correctly through the control [1], and I can see the
search on the 389ds server as:

[26/Aug/2015:10:49:04 +091800] deref-plugin - --> deref_pre_search
[26/Aug/2015:10:49:04 +091800] deref-plugin - <-- deref_pre_op
[26/Aug/2015:10:49:05 +091800] - Calling plugin 'deref' #2 type 410
[26/Aug/2015:10:49:05 +091800] deref-plugin - deref slapi_value_get_string
uid=test,dc=example,dc=com
[26/Aug/2015:10:49:05 +091800] - Calling plugin 'deref' #2 type 403
[26/Aug/2015:10:49:05 +091800] deref-plugin - --> deref_pre_search
[26/Aug/2015:10:49:05 +091800] deref-plugin - <-- deref_pre_op
[26/Aug/2015:10:49:05 +091800] - Calling plugin 'deref' #2 type 410
[26/Aug/2015:10:49:05 +091800] deref-plugin - Added control -1073736768
[26/Aug/2015:10:49:05 +091800] deref-plugin - Sending deref results to client

So I can see that the control is processed, the search occurs, and the correct
result of uid=test is found and dereferenced, and the control is added to the
server response. 

However, with trace_level=3, I don't see this result in python ldap:

*** <lib389.DirSrv instance at 0x7f9625f6d2d8>
ldap://localhost.localdomain:54321/ - DirSrv.set_option
((18,
  [('1.3.6.1.4.1.4203.666.5.16',
    True,
    '0\x1b0\x19\x04\x0cuniqueMember0\t\x04\x03uid\x04\x02dn')]),
 {})
=> result:
None
...
*** <lib389.DirSrv instance at 0x7f9625f6d2d8>
ldap://localhost.localdomain:54321/ - DirSrv.search_ext
(('dc=example,dc=com', 2, '(cn=testgroup)', None, 0, None, None, -1, 0), {})
=> result:
8
...
*** <lib389.DirSrv instance at 0x7f9625f6d2d8>
ldap://localhost.localdomain:54321/ - DirSrv.result4
((8, 1, -1, 0, 0, 0), {})
=> result:
(101,
 [('cn=testgroup,dc=example,dc=com',
   {'cn': ['testgroup'],
    'objectClass': ['top', 'extensibleobject'],
    'uniqueMember': ['uid=test,dc=example,dc=com']})],
 8,
 [])
*** <lib389.DirSrv instance at 0x7f9625f6d2d8>
ldap://localhost.localdomain:54321/ - DirSrv.set_option
((18, []), {})
=> result:
None

Printing my values of resp_data, decoded_resp_ctrls:

[('cn=testgroup,dc=example,dc=com', {'objectClass': ['top', 'extensibleobject'],
'uniqueMember': ['uid=test,dc=example,dc=com'], 'cn': ['testgroup']})]
[]


Where should I go from here to continue to investigate this? I'm not seeing any
calls into my decodeControlValue function on the control, so I suspect either I
haven't registered my DereferenceControl correctly to be used for responses, or
the response is "going missing" at some stage. Doing this same deref with
ldapsearch -E yields a correct response, so it's not a server issue as I can
see.

Your advice is appreciated.

Sincerely,

William




[0] https://tools.ietf.org/html/draft-masarati-ldap-deref-00
[1]:

from pyasn1.type import namedtype,univ
from pyasn1.codec.ber import encoder,decoder
from pyasn1_modules.rfc2251 import AttributeDescription

# Could use AttributeDescriptionList

"""
 controlValue ::= SEQUENCE OF derefSpec DerefSpec

 DerefSpec ::= SEQUENCE {
     derefAttr       attributeDescription,    ; with DN syntax
     attributes      AttributeList }

 AttributeList ::= SEQUENCE OF attr AttributeDescription

 Needs to be matched by ber_scanf(ber, "{a{v}}", ... )
"""

CONTROL_DEREF = '1.3.6.1.4.1.4203.666.5.16'

class AttributeList(univ.SequenceOf):
    componentType = AttributeDescription()

class DerefSpec(univ.Sequence):
    componentType = namedtype.NamedTypes(
        namedtype.NamedType('derefAttr', AttributeDescription()),
        namedtype.NamedType('attributes', AttributeList()),
    )

class DerefControlValue(univ.SequenceOf):
    componentType = DerefSpec()

class DereferenceControl(LDAPControl):
    """
    Dereference Control
    """

    def __init__(self, criticality, deref):
        LDAPControl.__init__(self, CONTROL_DEREF, criticality)
        self.deref = deref

    def encodeControlValue(self):
        cv = DerefControlValue()
        cvi = 0
        for derefSpec in self.deref.split(';'):
            derefAttr, attributes = derefSpec.split(':')
            attributes = attributes.split(',')
            al = AttributeList()
            i = 0
            while len(attributes) > 0:
                al.setComponentByPosition(i, attributes.pop())
                i += 1
            ds = DerefSpec()
            ds.setComponentByName('derefAttr', derefAttr)
            ds.setComponentByName('attributes', al)
            cv.setComponentByPosition(cvi, ds)
            cvi += 1
        print(cv.prettyPrint())
        return encoder.encode(cv)

    def decodeControlValue(self,encodedControlValue):
        print('DEREF decode')
        print(encodedControlValue)


More information about the python-ldap mailing list