From 96525a0b614663ae6272c4d2d8135df0df65825c Mon Sep 17 00:00:00 2001 From: stroeder Date: Sat, 19 Sep 2015 13:38:30 +0000 Subject: [PATCH] Added ldap.controls.deref implementing support for dereference control --- CHANGES | 3 +- Demo/pyasn1/derefcontrol.py | 47 ++++++++++++++ Lib/ldap/controls/deref.py | 125 ++++++++++++++++++++++++++++++++++++ setup.py | 3 +- 4 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 Demo/pyasn1/derefcontrol.py create mode 100644 Lib/ldap/controls/deref.py diff --git a/CHANGES b/CHANGES index 3e88321..2e10005 100644 --- a/CHANGES +++ b/CHANGES @@ -10,6 +10,7 @@ Lib/ argument add_ctrls which is internally passed to LDAPObject.result4() and lets the method also return response control along with the search results. +* Added ldap.controls.deref implementing support for dereference control Tests/ * Unit tests for module ldif (thanks to Petr Viktorin) @@ -1194,4 +1195,4 @@ Released 2.0.0pre02 2002-02-01 ---------------------------------------------------------------- Released 1.10alpha3 2000-09-19 -$Id: CHANGES,v 1.354 2015/09/18 20:20:32 stroeder Exp $ +$Id: CHANGES,v 1.355 2015/09/19 13:38:30 stroeder Exp $ diff --git a/Demo/pyasn1/derefcontrol.py b/Demo/pyasn1/derefcontrol.py new file mode 100644 index 0000000..885b66e --- /dev/null +++ b/Demo/pyasn1/derefcontrol.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +""" +This sample script demonstrates the use of the dereference control +(see https://tools.ietf.org/html/draft-masarati-ldap-deref) + +Requires module pyasn1 (see http://pyasn1.sourceforge.net/) +""" + +import pprint,ldap,ldap.modlist,ldap.resiter + +from ldap.controls.deref import DereferenceControl + +uri = "ldap://localhost:2071/" + +class MyLDAPObject(ldap.ldapobject.LDAPObject,ldap.resiter.ResultProcessor): + pass + + +l = MyLDAPObject(uri,trace_level=2) +l.simple_bind_s('uid=diradm,dc=example,dc=com','testsecret') + +dc = DereferenceControl( + True, + { + 'member':[ + 'uid', + 'description', +# 'cn', +# 'mail', + ], + } +) +print dc._derefSpecs().prettyPrint() +dc.encodeControlValue() + +msg_id = l.search_ext( + 'dc=example,dc=com', + ldap.SCOPE_SUBTREE, + '(objectClass=groupOfNames)', + attrlist=['cn','objectClass','member','description'], + serverctrls = [dc] +) + +for res_type,res_data,res_msgid,res_controls in l.allresults(msg_id,add_ctrls=1): + for dn,entry,deref_control in res_data: + # process dn and entry + print dn,entry['objectClass'] diff --git a/Lib/ldap/controls/deref.py b/Lib/ldap/controls/deref.py new file mode 100644 index 0000000..c8cef79 --- /dev/null +++ b/Lib/ldap/controls/deref.py @@ -0,0 +1,125 @@ +# -*- coding: utf-8 -*- +""" +ldap.controls.deref - classes for +(see https://tools.ietf.org/html/draft-masarati-ldap-deref) + +See http://www.python-ldap.org/ for project details. + +$Id: deref.py,v 1.1 2015/09/19 13:38:30 stroeder Exp $ +""" + +__all__ = [ + 'DEREF_CONTROL_OID', + 'DereferenceControl', +] + +import ldap.controls +from ldap.controls import LDAPControl,KNOWN_RESPONSE_CONTROLS + +import pyasn1_modules.rfc2251 +from pyasn1.type import namedtype,univ,tag +from pyasn1.codec.ber import encoder,decoder +from pyasn1_modules.rfc2251 import LDAPDN,AttributeDescription,AttributeDescriptionList,AttributeValue + + +DEREF_CONTROL_OID = '1.3.6.1.4.1.4203.666.5.16' + + +# Request types +#--------------------------------------------------------------------------- + +# For compability with ASN.1 declaration in I-D +AttributeList = AttributeDescriptionList + +class DerefSpec(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType( + 'derefAttr', + AttributeDescription() + ), + namedtype.NamedType( + 'attributes', + AttributeList() + ), + ) + +class DerefSpecs(univ.SequenceOf): + componentType = DerefSpec() + +# Response types +#--------------------------------------------------------------------------- + + +class AttributeValues(univ.SetOf): + componentType = AttributeValue() + + +class PartialAttribute(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('type', AttributeDescription()), + namedtype.NamedType('vals', AttributeValues()), + ) + + +class PartialAttributeList(univ.SequenceOf): + componentType = PartialAttribute() + tagSet = univ.Sequence.tagSet.tagImplicitly( + tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,0) + ) + + +class DerefRes(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('derefAttr', AttributeDescription()), + namedtype.NamedType('derefVal', LDAPDN()), + namedtype.OptionalNamedType('attrVals', PartialAttributeList()), + ) + + +class DerefResultControlValue(univ.SequenceOf): + componentType = DerefRes() + + +class DereferenceControl(LDAPControl): + controlType = DEREF_CONTROL_OID + + def __init__(self,criticality=False,derefSpecs=None): + LDAPControl.__init__(self,self.controlType,criticality) + self.derefSpecs = derefSpecs or {} + + def _derefSpecs(self): + deref_specs = DerefSpecs() + i = 0 + for deref_attr,deref_attribute_names in self.derefSpecs.items(): + deref_spec = DerefSpec() + deref_attributes = AttributeList() + for j in range(len(deref_attribute_names)): + deref_attributes.setComponentByPosition(j,deref_attribute_names[j]) + deref_spec.setComponentByName('derefAttr',AttributeDescription(deref_attr)) + deref_spec.setComponentByName('attributes',deref_attributes) + deref_specs.setComponentByPosition(i,deref_spec) + i += 1 + return deref_specs + + def encodeControlValue(self): + return encoder.encode(self._derefSpecs()) + + def decodeControlValue(self,encodedControlValue): + decodedValue,_ = decoder.decode(encodedControlValue,asn1Spec=DerefResultControlValue()) + print decodedValue.prettyPrint() + self.derefRes = {} + for deref_res in decodedValue: + deref_attr,deref_val,deref_vals = deref_res + partial_attrs_dict = dict([ + (str(t),map(str,v)) + for t,v in deref_vals or [] + ]) + try: + self.derefRes[str(deref_attr)].append((str(deref_val),partial_attrs_dict)) + except KeyError: + self.derefRes[str(deref_attr)] = [(str(deref_val),partial_attrs_dict)] + import pprint + pprint.pprint(self.derefRes) + + +KNOWN_RESPONSE_CONTROLS[DereferenceControl.controlType] = DereferenceControl diff --git a/setup.py b/setup.py index b2fe367..868d2f0 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ See http://www.python-ldap.org/ for details. -$Id: setup.py,v 1.72 2014/03/12 20:29:23 stroeder Exp $ +$Id: setup.py,v 1.73 2015/09/19 13:38:30 stroeder Exp $ """ has_setuptools = False @@ -150,6 +150,7 @@ class OpenLDAP2: 'ldap', 'ldap.async', 'ldap.controls', + 'ldap.controls.deref', 'ldap.controls.libldap', 'ldap.controls.openldap', 'ldap.controls.ppolicy',