Skip to content

Commit

Permalink
fixed regression with newer version of pyasn1
Browse files Browse the repository at this point in the history
  • Loading branch information
cannatag committed Aug 2, 2017
1 parent a3171a3 commit 04adf56
Show file tree
Hide file tree
Showing 12 changed files with 40 additions and 29 deletions.
12 changes: 6 additions & 6 deletions docs/manual/source/encoding.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The LDAP protocol stores strings in a **Directory String** type that should alwa
``DEFAULT_CLIENT_ENCODING`` config parameter. For flaky server this encoding can be changed with::

>>> from ldap3 import set_config_parameter
>>> set_config_parameter('DEFAULT_SERVER_ENCODING', 'server_encoding')
>>> set_config_parameter('DEFAULT_SERVER_ENCODING', 'latin-1')

DEFAULT_SERVER_ENCODING can be changed multiple times as needed. To know the current ``DEFAULT_SERVER_ENCODING`` you can use the following code::

Expand All @@ -27,11 +27,11 @@ DEFAULT_SERVER_ENCODING can be changed multiple times as needed. To know the cur
'utf-8'


Some servers don't completely follow the LDAP RFCs and send data in a different encoding or in a mix of encodings. For example Active Directory can send
the DN of entries found in a search in a different encoding than utf-8. In this case you can use the ``ADDITIONAL_SERVER_ENCODINGS`` config
parameter to decode the DN of the Search operation response. It can be set to one encoding or a list of encodings. If a list of encodings is
provided ldap3 tries sequentially each encoding until a valid decode is performed. If any of the specified encodings is not able
to decode the value then an ``UnicodeError`` exception is raised.
Some servers don't completely follow the LDAP RFCs and send data in a different encoding or in a mix of encodings. For example Active Directory
can send the DN of entries found in a search in a different encoding than utf-8. In this case you can use the ``ADDITIONAL_SERVER_ENCODINGS``
config parameter to decode the DN of the Search operation response. It can be set to one encoding or a list of encodings. If
a list of encodings is provided ldap3 tries sequentially each encoding until a valid decode is performed. If any of the specified
encodings is able to decode the value then an ``UnicodeError`` exception is raised.

``ADDITIONAL_SERVER_ENCODINGS`` defaults to ['latin1, 'koi8-r'] for european and russian encodings

Expand Down
3 changes: 2 additions & 1 deletion ldap3/abstract/attrDef.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ def __init__(self, name, key=None, validate=None, pre_query=None, post_query=Non
if not alias:
self.other_names = None
elif isinstance(alias, SEQUENCE_TYPES): # multiple aliases
self.other_names = set(alias)
self.\
other_names = set(alias)
else: # single alias
self.other_names = set([alias]) # python 2 compatibility

Expand Down
1 change: 1 addition & 0 deletions ldap3/abstract/entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ def entry_writable(self, object_def=None, writer_cursor=None, attributes=None, c
new_attr.values = writable_entry._state.attributes[original_attr.name].values
new_attr.response = writable_entry._state.attributes[original_attr.name].response
writable_entry._state.attributes[attr] = new_attr
# writable_entry._state.attributes.set_alias(attr, new_attr.other_names)
del writable_entry._state.attributes[original_attr.name]

writable_entry._state.set_status(STATUS_WRITABLE)
Expand Down
4 changes: 3 additions & 1 deletion ldap3/operation/bind.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ def bind_operation(version,
sasl_creds['mechanism'] = sasl_mechanism
if sasl_credentials is not None:
sasl_creds['credentials'] = sasl_credentials
# else:
# sasl_creds['credentials'] = None
request['authentication'] = AuthenticationChoice().setComponentByName('sasl', sasl_creds)
elif authentication == ANONYMOUS:
if name:
Expand Down Expand Up @@ -121,7 +123,7 @@ def bind_response_to_dict(response):
'dn': str(response['matchedDN']),
'message': str(response['diagnosticMessage']),
'referrals': referrals_to_list(response['referral']),
'saslCreds': bytes(response['serverSaslCreds']) if response['serverSaslCreds'] is not None else None}
'saslCreds': bytes(response['serverSaslCreds']) if response['serverSaslCreds'] is not None and response['serverSaslCreds'].hasValue() else None}


def sicily_bind_response_to_dict(response):
Expand Down
5 changes: 3 additions & 2 deletions ldap3/operation/extended.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,15 @@ def extended_operation(request_name,
request['requestValue'] = request_value
elif request_value: # tries to encode as a octet string
request['requestValue'] = RequestValue(encoder.encode(OctetString(str(request_value))))

# elif request_value is not None:
# raise LDAPExtensionError('unable to encode value for extended operation')
return request


def extended_request_to_dict(request):
# return {'name': str(request['requestName']), 'value': bytes(request['requestValue']) if request['requestValue'] else None}
return {'name': str(request['requestName']), 'value': bytes(request['requestValue']) if 'requestValue' in request and request['requestValue'] and request['requestValue'].hasValue() else None}
return {'name': str(request['requestName']), 'value': bytes(request['requestValue']) if 'requestValue' in request and request['requestValue'] is not None and request['requestValue'].hasValue() else None}

def extended_response_to_dict(response):
return {'result': int(response['resultCode']),
Expand All @@ -66,7 +67,7 @@ def extended_response_to_dict(response):
'description': ResultCode().getNamedValues().getName(response['resultCode']),
'referrals': referrals_to_list(response['referral']),
'responseName': str(response['responseName']) if response['responseName'] else None,
'responseValue': bytes(response['responseValue']) if response['responseValue'] else bytes()}
'responseValue': bytes(response['responseValue']) if 'responseValue' in response and response['responseValue'] is not None and response['responseValue'].hasValue() else bytes()}


def intermediate_response_to_dict(response):
Expand Down
2 changes: 1 addition & 1 deletion ldap3/operation/modifyDn.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def modify_dn_request_to_dict(request):
return {'entry': str(request['entry']),
'newRdn': str(request['newrdn']),
'deleteOldRdn': bool(request['deleteoldrdn']),
'newSuperior': str(request['newSuperior']) if 'newSuperior' in request and request['newSuperior'] and request['newSuperior'].hasValue() else None}
'newSuperior': str(request['newSuperior']) if 'newSuperior' in request and request['newSuperior'] is not None and request['newSuperior'].hasValue() else None}


def modify_dn_response_to_dict(response):
Expand Down
29 changes: 18 additions & 11 deletions ldap3/operation/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def evaluate_match(match, schema, auto_escape, auto_encode):
left_part = left_part[:-1].strip()
right_part = right_part.strip()
assertion = {'attr': left_part, 'value': validate_assertion_value(schema, left_part, right_part, auto_escape, auto_encode)}
elif left_part.endswith('<'): # # less or equal match '<='
elif left_part.endswith('<'): # less or equal match '<='
tag = MATCH_LESS_OR_EQUAL
left_part = left_part[:-1].strip()
right_part = right_part.strip()
Expand Down Expand Up @@ -139,19 +139,26 @@ def evaluate_match(match, schema, auto_escape, auto_encode):
attribute_name = attribute_name.strip() if attribute_name else None
matching_rule = matching_rule.strip() if matching_rule else None
assertion = {'attr': attribute_name, 'value': validate_assertion_value(schema, attribute_name, right_part, auto_escape, auto_encode), 'matchingRule': matching_rule, 'dnAttributes': dn_attributes}
elif right_part == '*': # # attribute present match '=*'
elif right_part == '*': # attribute present match '=*'
tag = MATCH_PRESENT
left_part = left_part.strip()
assertion = {'attr': left_part}
elif '*' in right_part: # # substring match '=initial*substring*substring*final'
elif '*' in right_part: # substring match '=initial*substring*substring*final'
tag = MATCH_SUBSTRING
left_part = left_part.strip()
right_part = right_part.strip()
substrings = right_part.split('*')
initial = validate_assertion_value(schema, left_part, substrings[0], auto_escape, auto_encode) if substrings[0] else None
final = validate_assertion_value(schema, left_part, substrings[-1], auto_escape, auto_encode) if substrings[-1] else None
any_string = [validate_assertion_value(schema, left_part, substring, auto_escape, auto_encode) for substring in substrings[1:-1] if substring]
assertion = {'attr': left_part, 'initial': initial, 'any': any_string, 'final': final}
#assertion = {'attr': left_part, 'initial': initial, 'any': any_string, 'final': final}
assertion = {'attr': left_part}
if initial:
assertion['initial'] = initial
if any_string:
assertion['any'] = any_string
if final:
assertion['final'] = final
else: # equality match '='
tag = MATCH_EQUAL
left_part = left_part.strip()
Expand Down Expand Up @@ -195,7 +202,7 @@ def parse_filter(search_filter, schema, auto_escape, auto_encode):
end_pos = pos
if start_pos:
if current_node.tag == NOT and len(current_node.elements) > 0:
raise LDAPInvalidFilterError('not clause in filter cannot be multiple')
raise LDAPInvalidFilterError('NOT (!) clause in filter cannot be multiple')
current_node.append(evaluate_match(search_filter[start_pos:end_pos], schema, auto_escape, auto_encode))
start_pos = None
state = SEARCH_OPEN_OR_CLOSE
Expand Down Expand Up @@ -267,14 +274,14 @@ def compile_filter(filter_node):
matching_filter['type'] = AttributeDescription(filter_node.assertion['attr'])
substrings = Substrings()
pos = 0
if filter_node.assertion['initial']:
if 'initial' in filter_node.assertion and filter_node.assertion['initial']:
substrings[pos] = Substring().setComponentByName('initial', Initial(prepare_filter_for_sending(filter_node.assertion['initial'])))
pos += 1
if filter_node.assertion['any']:
if 'any' in filter_node.assertion and filter_node.assertion['any']:
for substring in filter_node.assertion['any']:
substrings[pos] = Substring().setComponentByName('any', Any(prepare_filter_for_sending(substring)))
pos += 1
if filter_node.assertion['final']:
if 'final' in filter_node.assertion and filter_node.assertion['final']:
substrings[pos] = Substring().setComponentByName('final', Final(prepare_filter_for_sending(filter_node.assertion['final'])))
matching_filter['substrings'] = substrings
compiled_filter['substringFilter'] = matching_filter
Expand Down Expand Up @@ -469,12 +476,12 @@ def filter_to_string(filter_object):
attribute = filter_object['substringFilter']['type']
filter_string += str(attribute) + '='
for substring in filter_object['substringFilter']['substrings']:
if substring['initial']:
if 'initial' in substring and substring['initial'] is not None and substring['initial'].hasValue():
filter_string += str(substring['initial']) + '*'
elif substring['any']:
elif 'any' in substring and substring['any'] is not None and substring['any'].hasValue():
filter_string += str(substring['any']) if filter_string.endswith('*') else '*' + str(substring['any'])
filter_string += '*'
elif substring['final']:
elif 'final' in substring and substring['final'] is not None and substring['final'].hasValue():
filter_string += '*' + str(substring['final'])
elif filter_type == 'greaterOrEqual':
ava = ava_to_dict(filter_object['greaterOrEqual'])
Expand Down
2 changes: 1 addition & 1 deletion ldap3/protocol/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def search_refs_to_list_fast(search_refs):


def sasl_to_dict(sasl):
return {'mechanism': str(sasl['mechanism']), 'credentials': str(sasl['credentials'])}
return {'mechanism': str(sasl['mechanism']), 'credentials': str(sasl['credentials'] if sasl['credentials'] is not None and sasl['credentials'].hasValue() else None)}


def authentication_choice_to_dict(authentication_choice):
Expand Down
6 changes: 3 additions & 3 deletions ldap3/strategy/mockBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -807,16 +807,16 @@ def evaluate_filter_node(self, node, candidates):
elif node.tag == MATCH_SUBSTRING:
attr_name = node.assertion['attr']
# rebuild the original substring filter
if node.assertion['initial']:
if 'initial' in node.assertion and node.assertion['initial'] is not None:
substring_filter = re.escape(to_unicode(node.assertion['initial'], SERVER_ENCODING))
else:
substring_filter = ''

if node.assertion['any']:
if 'any' in node.assertion and node.assertion['any'] is not None:
for middle in node.assertion['any']:
substring_filter += '.*' + re.escape(to_unicode(middle, SERVER_ENCODING))

if node.assertion['final']:
if 'final' in node.assertion and node.assertion['final'] is not None:
substring_filter += '.*' + re.escape(to_unicode(node.assertion['final'], SERVER_ENCODING))

if substring_filter and not node.assertion['any'] and not node.assertion['final']: # only initial, adds .*
Expand Down
1 change: 0 additions & 1 deletion ldap3/strategy/mockSync.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ def post_send_search(self, payload):
self.connection.result = dict()
if message_type == 'searchRequest':
responses, result = self.mock_search(request, controls)
result['type'] = 'searchResDone'
for entry in responses:
response = search_result_entry_response_to_dict(entry, self.connection.server.schema, self.connection.server.custom_formatter, self.connection.check_names)
response['type'] = 'searchResEntry'
Expand Down
2 changes: 1 addition & 1 deletion ldap3/utils/ciDict.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def set_alias(self, key, alias):
self._alias_keymap[ci_key] = list()
self._alias_keymap[ci_key].append(self._ci_key(ci_alias))
else:
if ci_key == self._ci_key(self._case_insensitive_keymap[ci_alias]): # passes if alias is already defined to the same key
if ci_key == self._ci_key(self._alias_keymap[ci_alias]): # passes if alias is already defined to the same key
pass
else:
raise KeyError('\'' + str(alias_to_add) + '\' already used as alias')
Expand Down
2 changes: 1 addition & 1 deletion test/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
test_pooling_active = 20
test_pooling_exhaust = 15

test_fast_decoder = True # True uses internal 10x faster than pyasn1 decoder
test_fast_decoder = False # True uses internal 10x faster than pyasn1 decoder
test_port = 389 # ldap port
test_port_ssl = 636 # ldap secure port
test_authentication = SIMPLE # authentication type
Expand Down

0 comments on commit 04adf56

Please sign in to comment.