1"""
2ldap.controls.deref - classes for
3(see https://tools.ietf.org/html/draft-masarati-ldap-deref)
4
5See https://www.python-ldap.org/ for project details.
6"""
7
8__all__ = [
9  'DEREF_CONTROL_OID',
10  'DereferenceControl',
11]
12
13import ldap.controls
14from ldap.controls import LDAPControl,KNOWN_RESPONSE_CONTROLS
15
16import pyasn1_modules.rfc2251
17from pyasn1.type import namedtype,univ,tag
18from pyasn1.codec.ber import encoder,decoder
19from pyasn1_modules.rfc2251 import LDAPDN,AttributeDescription,AttributeDescriptionList,AttributeValue
20
21
22DEREF_CONTROL_OID = '1.3.6.1.4.1.4203.666.5.16'
23
24
25# Request types
26#---------------------------------------------------------------------------
27
28# For compatibility with ASN.1 declaration in I-D
29AttributeList = AttributeDescriptionList
30
31class DerefSpec(univ.Sequence):
32  componentType = namedtype.NamedTypes(
33    namedtype.NamedType(
34      'derefAttr',
35      AttributeDescription()
36    ),
37    namedtype.NamedType(
38      'attributes',
39      AttributeList()
40    ),
41  )
42
43class DerefSpecs(univ.SequenceOf):
44  componentType = DerefSpec()
45
46# Response types
47#---------------------------------------------------------------------------
48
49
50class AttributeValues(univ.SetOf):
51    componentType = AttributeValue()
52
53
54class PartialAttribute(univ.Sequence):
55  componentType = namedtype.NamedTypes(
56    namedtype.NamedType('type', AttributeDescription()),
57    namedtype.NamedType('vals', AttributeValues()),
58  )
59
60
61class PartialAttributeList(univ.SequenceOf):
62  componentType = PartialAttribute()
63  tagSet = univ.Sequence.tagSet.tagImplicitly(
64    tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,0)
65  )
66
67
68class DerefRes(univ.Sequence):
69  componentType = namedtype.NamedTypes(
70    namedtype.NamedType('derefAttr', AttributeDescription()),
71    namedtype.NamedType('derefVal', LDAPDN()),
72    namedtype.OptionalNamedType('attrVals', PartialAttributeList()),
73  )
74
75
76class DerefResultControlValue(univ.SequenceOf):
77    componentType = DerefRes()
78
79
80class DereferenceControl(LDAPControl):
81  controlType = DEREF_CONTROL_OID
82
83  def __init__(self,criticality=False,derefSpecs=None):
84    LDAPControl.__init__(self,self.controlType,criticality)
85    self.derefSpecs = derefSpecs or {}
86
87  def _derefSpecs(self):
88    deref_specs = DerefSpecs()
89    i = 0
90    for deref_attr,deref_attribute_names in self.derefSpecs.items():
91      deref_spec = DerefSpec()
92      deref_attributes = AttributeList()
93      for j in range(len(deref_attribute_names)):
94        deref_attributes.setComponentByPosition(j,deref_attribute_names[j])
95      deref_spec.setComponentByName('derefAttr',AttributeDescription(deref_attr))
96      deref_spec.setComponentByName('attributes',deref_attributes)
97      deref_specs.setComponentByPosition(i,deref_spec)
98      i += 1
99    return deref_specs
100
101  def encodeControlValue(self):
102    return encoder.encode(self._derefSpecs())
103
104  def decodeControlValue(self,encodedControlValue):
105    decodedValue,_ = decoder.decode(encodedControlValue,asn1Spec=DerefResultControlValue())
106    self.derefRes = {}
107    for deref_res in decodedValue:
108      deref_attr,deref_val,deref_vals = deref_res[0],deref_res[1],deref_res[2]
109      partial_attrs_dict = {
110        str(tv[0]): [str(v) for v in tv[1]]
111        for tv in deref_vals or []
112      }
113      try:
114        self.derefRes[str(deref_attr)].append((str(deref_val),partial_attrs_dict))
115      except KeyError:
116        self.derefRes[str(deref_attr)] = [(str(deref_val),partial_attrs_dict)]
117
118KNOWN_RESPONSE_CONTROLS[DereferenceControl.controlType] = DereferenceControl
119