-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added modules ldap.controls.vlv and ldap.controls.sss for Virtual Lis…
…t View (see draft-ietf-ldapext-ldapv3-vlv) and Server-side Sorting (see RFC 2891)
- Loading branch information
stroeder
committed
Jun 22, 2015
1 parent
086e689
commit a4169eb
Showing
3 changed files
with
271 additions
and
1 deletion.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| # -*- coding: utf-8 -*- | ||
| """ | ||
| ldap.controls.sss - classes for Server Side Sorting | ||
| (see RFC 2891) | ||
| See http://www.python-ldap.org/ for project details. | ||
| $Id: sss.py,v 1.1 2015/06/22 16:47:08 stroeder Exp $ | ||
| """ | ||
|
|
||
| __all__ = [ | ||
| 'SSSRequestControl', | ||
| 'SSSResponseControl', | ||
| 'SSSVLVPagedLDAPObject' | ||
| ] | ||
|
|
||
|
|
||
| import ldap | ||
| from ldap.ldapobject import LDAPObject | ||
| from ldap.controls import (RequestControl, ResponseControl, | ||
| KNOWN_RESPONSE_CONTROLS, DecodeControlTuples) | ||
|
|
||
| from pyasn1.type import univ, namedtype, tag, namedval, constraint | ||
| from pyasn1.codec.ber import encoder, decoder | ||
|
|
||
|
|
||
| # SortKeyList ::= SEQUENCE OF SEQUENCE { | ||
| # attributeType AttributeDescription, | ||
| # orderingRule [0] MatchingRuleId OPTIONAL, | ||
| # reverseOrder [1] BOOLEAN DEFAULT FALSE } | ||
|
|
||
|
|
||
| class SortKeyType(univ.Sequence): | ||
| componentType = namedtype.NamedTypes( | ||
| namedtype.NamedType('attributeType', univ.OctetString()), | ||
| namedtype.OptionalNamedType('orderingRule', | ||
| univ.OctetString().subtype( | ||
| implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0) | ||
| ) | ||
| ), | ||
| namedtype.DefaultedNamedType('reverseOrder', univ.Boolean(False).subtype( | ||
| implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)))) | ||
|
|
||
|
|
||
| class SortKeyListType(univ.SequenceOf): | ||
| componentType = SortKeyType() | ||
|
|
||
|
|
||
| class SSSRequestControl(RequestControl): | ||
| '''Order result server side | ||
| >>> s = SSSRequestControl('-cn') | ||
| ''' | ||
| controlType = '1.2.840.113556.1.4.473' | ||
|
|
||
| def __init__( | ||
| self, | ||
| criticality=False, | ||
| ordering_rules=None, | ||
| ): | ||
| RequestControl.__init__(self,self.controlType,criticality) | ||
| self.ordering_rules = ordering_rules | ||
| if isinstance(ordering_rules, basestring): | ||
| ordering_rules = [ordering_rules] | ||
| for rule in ordering_rules: | ||
| rule = rule.split(':') | ||
| assert len(rule) < 3, 'syntax for ordering rule: [-]<attribute-type>[:ordering-rule]' | ||
|
|
||
| def asn1(self): | ||
| p = SortKeyListType() | ||
| for i, rule in enumerate(self.ordering_rules): | ||
| q = SortKeyType() | ||
| reverse_order = rule.startswith('-') | ||
| if reverse_order: | ||
| rule = rule[1:] | ||
| if ':' in rule: | ||
| attribute_type, ordering_rule = rule.split(':') | ||
| else: | ||
| attribute_type, ordering_rule = rule, None | ||
| q.setComponentByName('attributeType', attribute_type) | ||
| if ordering_rule: | ||
| q.setComponentByName('orderingRule', ordering_rule) | ||
| if reverse_order: | ||
| q.setComponentByName('reverseOrder', 1) | ||
| p.setComponentByPosition(i, q) | ||
| return p | ||
|
|
||
| def encodeControlValue(self): | ||
| return encoder.encode(self.asn1()) | ||
|
|
||
|
|
||
| class SortResultType(univ.Sequence): | ||
| componentType = namedtype.NamedTypes( | ||
| namedtype.NamedType('sortResult', univ.Enumerated().subtype( | ||
| namedValues=namedval.NamedValues( | ||
| ('success', 0), | ||
| ('operationsError', 1), | ||
| ('timeLimitExceeded', 3), | ||
| ('strongAuthRequired', 8), | ||
| ('adminLimitExceeded', 11), | ||
| ('noSuchAttribute', 16), | ||
| ('inappropriateMatching', 18), | ||
| ('insufficientAccessRights', 50), | ||
| ('busy', 51), | ||
| ('unwillingToPerform', 53), | ||
| ('other', 80)), | ||
| subtypeSpec=univ.Enumerated.subtypeSpec + constraint.SingleValueConstraint( | ||
| 0, 1, 3, 8, 11, 16, 18, 50, 51, 53, 80))), | ||
| namedtype.OptionalNamedType('attributeType', | ||
| univ.OctetString().subtype( | ||
| implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0) | ||
| ) | ||
| )) | ||
|
|
||
|
|
||
| class SSSResponseControl(ResponseControl): | ||
| controlType = '1.2.840.113556.1.4.474' | ||
|
|
||
| def __init__(self,criticality=False): | ||
| ResponseControl.__init__(self,self.controlType,criticality) | ||
|
|
||
| def decodeControlValue(self, encoded): | ||
| p, rest = decoder.decode(encoded, asn1Spec=SortResultType()) | ||
| assert not rest, 'all data could not be decoded' | ||
| self.result = int(p.getComponentByName('sortResult')) | ||
| self.result_code = p.getComponentByName('sortResult').prettyOut(self.result) | ||
| self.attribute_type_error = p.getComponentByName('attributeType') | ||
|
|
||
|
|
||
| KNOWN_RESPONSE_CONTROLS[SSSRequestControl.controlType] = SSSRequestControl | ||
| KNOWN_RESPONSE_CONTROLS[SSSResponseControl.controlType] = SSSResponseControl |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| # -*- coding: utf-8 -*- | ||
| """ | ||
| ldap.controls.vlv - classes for Simple Paged control | ||
| (see draft-ietf-ldapext-ldapv3-vlv) | ||
| See http://www.python-ldap.org/ for project details. | ||
| $Id: vlv.py,v 1.1 2015/06/22 16:47:08 stroeder Exp $ | ||
| """ | ||
|
|
||
| __all__ = [ | ||
| 'VLVRequestControl', | ||
| 'VLVResponseControl', | ||
| ] | ||
|
|
||
| import ldap | ||
| from ldap.ldapobject import LDAPObject | ||
| from ldap.controls import (RequestControl, ResponseControl, | ||
| KNOWN_RESPONSE_CONTROLS, DecodeControlTuples) | ||
|
|
||
| from pyasn1.type import univ, namedtype, tag, namedval, constraint | ||
| from pyasn1.codec.ber import encoder, decoder | ||
|
|
||
|
|
||
| class ByOffsetType(univ.Sequence): | ||
| tagSet = univ.Sequence.tagSet.tagImplicitly( | ||
| tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)) | ||
| componentType = namedtype.NamedTypes( | ||
| namedtype.NamedType('offset', univ.Integer()), | ||
| namedtype.NamedType('contentCount', univ.Integer())) | ||
|
|
||
|
|
||
| class TargetType(univ.Choice): | ||
| componentType = namedtype.NamedTypes( | ||
| namedtype.NamedType('byOffset', ByOffsetType()), | ||
| namedtype.NamedType('greaterThanOrEqual', univ.OctetString().subtype( | ||
| implicitTag=tag.Tag(tag.tagClassContext, | ||
| tag.tagFormatSimple, 1)))) | ||
|
|
||
|
|
||
| class VirtualListViewRequestType(univ.Sequence): | ||
| componentType = namedtype.NamedTypes( | ||
| namedtype.NamedType('beforeCount', univ.Integer()), | ||
| namedtype.NamedType('afterCount', univ.Integer()), | ||
| namedtype.NamedType('target', TargetType()), | ||
| namedtype.OptionalNamedType('contextID', univ.OctetString())) | ||
|
|
||
| class VLVRequestControl(RequestControl): | ||
| controlType = '2.16.840.1.113730.3.4.9' | ||
|
|
||
| def __init__( | ||
| self, | ||
| criticality=False, | ||
| before_count=0, | ||
| after_count=0, | ||
| offset=None, | ||
| content_count=None, | ||
| greater_than_or_equal=None, | ||
| context_id=None, | ||
| ): | ||
| RequestControl.__init__(self,self.controlType,criticality) | ||
| assert (offset is not None and content_count is not None) or greater_than_or_equal, 'offset and ' \ | ||
| 'content_count must be set together or greater_than_or_equal must be ' \ | ||
| 'used' | ||
| self.before_count = before_count | ||
| self.after_count = after_count | ||
| self.offset = offset | ||
| self.content_count = content_count | ||
| self.greater_than_or_equal = greater_than_or_equal | ||
| self.context_id = context_id | ||
|
|
||
| def encodeControlValue(self): | ||
| p = VirtualListViewRequestType() | ||
| p.setComponentByName('beforeCount', self.before_count) | ||
| p.setComponentByName('afterCount', self.after_count) | ||
| if self.offset is not None and self.content_count is not None: | ||
| by_offset = ByOffsetType() | ||
| by_offset.setComponentByName('offset', self.offset) | ||
| by_offset.setComponentByName('contentCount', self.content_count) | ||
| target = TargetType() | ||
| target.setComponentByName('byOffset', by_offset) | ||
| elif self.greater_than_or_equal: | ||
| target = TargetType() | ||
| target.setComponentByName('greaterThanOrEqual', | ||
| self.greater_than_or_equal) | ||
| else: | ||
| raise NotImplementedError | ||
| p.setComponentByName('target', target) | ||
| return encoder.encode(p) | ||
|
|
||
| KNOWN_RESPONSE_CONTROLS[VLVRequestControl.controlType] = VLVRequestControl | ||
|
|
||
|
|
||
| class VirtualListViewResultType(univ.Enumerated): | ||
| namedValues = namedval.NamedValues( | ||
| ('success', 0), | ||
| ('operationsError', 1), | ||
| ('protocolError', 3), | ||
| ('unwillingToPerform', 53), | ||
| ('insufficientAccessRights', 50), | ||
| ('adminLimitExceeded', 11), | ||
| ('innapropriateMatching', 18), | ||
| ('sortControlMissing', 60), | ||
| ('offsetRangeError', 61), | ||
| ('other', 80), | ||
| ) | ||
|
|
||
|
|
||
| class VirtualListViewResponseType(univ.Sequence): | ||
| componentType = namedtype.NamedTypes( | ||
| namedtype.NamedType('targetPosition', univ.Integer()), | ||
| namedtype.NamedType('contentCount', univ.Integer()), | ||
| namedtype.NamedType('virtualListViewResult', | ||
| VirtualListViewResultType()), | ||
| namedtype.OptionalNamedType('contextID', univ.OctetString())) | ||
|
|
||
|
|
||
| class VLVResponseControl(ResponseControl): | ||
| controlType = '2.16.840.1.113730.3.4.10' | ||
|
|
||
| def __init__(self,criticality=False): | ||
| ResponseControl.__init__(self,self.controlType,criticality) | ||
|
|
||
| def decodeControlValue(self,encoded): | ||
| p, rest = decoder.decode(encoded, asn1Spec=VirtualListViewResponseType()) | ||
| assert not rest, 'all data could not be decoded' | ||
| self.target_position = int(p.getComponentByName('targetPosition')) | ||
| self.content_count = int(p.getComponentByName('contentCount')) | ||
| self.result = int(p.getComponentByName('virtualListViewResult')) | ||
| self.result_code = p.getComponentByName('virtualListViewResult') \ | ||
| .prettyOut(self.result) | ||
| self.context_id = p.getComponentByName('contextID') | ||
| if self.context_id: | ||
| self.context_id = str(self.context_id) | ||
|
|
||
| KNOWN_RESPONSE_CONTROLS[VLVResponseControl.controlType] = VLVResponseControl |