Hello community, here is the log from the commit of package python-ldap3 for openSUSE:Factory checked in at 2019-05-16 22:07:40 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-ldap3 (Old) and /work/SRC/openSUSE:Factory/.python-ldap3.new.5148 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-ldap3" Thu May 16 22:07:40 2019 rev:8 rq:703011 version:2.6 Changes: -------- --- /work/SRC/openSUSE:Factory/python-ldap3/python-ldap3.changes 2019-02-27 15:05:46.330453891 +0100 +++ /work/SRC/openSUSE:Factory/.python-ldap3.new.5148/python-ldap3.changes 2019-05-16 22:07:43.938409006 +0200 @@ -1,0 +2,18 @@ +Tue May 14 21:44:09 UTC 2019 - Gary Smith <[email protected]> + +- update to version 2.6 + +# 2.6 - 2019.03.24 + - fixed empty digestMd5.py file in 2.5.2 package + - explicitly declare digest module md5 in util.ntlm (thanks adawalli) + - change object passed to modify() was unexpectedly mutated (thanks John) + - added LDAPInfoError exception + - added Server.has_control(control) method to check if a server has a specific control + - added Server.has_extension(extension) method to check if a server has a specific extension + - added Server.has_feature(feature) method to check if a server has a specific feature + - fixed checking of \\ in safe_dn (thanks Maxim) + - fixed uuid checking with 5c byte value + - added single=True parameter to the ServerPool object definition. Servers state is shared between connections using the same pool + - updated copyright notice + +------------------------------------------------------------------- Old: ---- v2.5.2.tar.gz New: ---- v2.6.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-ldap3.spec ++++++ --- /var/tmp/diff_new_pack.AoAM7e/_old 2019-05-16 22:07:45.710407253 +0200 +++ /var/tmp/diff_new_pack.AoAM7e/_new 2019-05-16 22:07:45.710407253 +0200 @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-ldap3 -Version: 2.5.2 +Version: 2.6 Release: 0 Summary: A strictly RFC 4511 conforming LDAP V3 pure Python client License: LGPL-3.0-only ++++++ v2.5.2.tar.gz -> v2.6.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/.gitignore new/ldap3-2.6/.gitignore --- old/ldap3-2.5.2/.gitignore 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/.gitignore 2019-03-23 16:43:44.000000000 +0100 @@ -63,4 +63,178 @@ #PyCharm .idea/ -*.iml \ No newline at end of file +*.iml +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests +### VirtualEnv template +# Virtualenv +# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ +[Bb]in +[Ii]nclude +[Ll]ib +[Ll]ib64 +[Ll]ocal +[Ss]cripts +pyvenv.cfg +.venv +pip-selfcheck.json +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk +### Python template +# Byte-compiled / optimized / DLL files + +# C extensions + +# Distribution / packaging +wheels/ +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. + +# Installer logs + +# Unit test / coverage reports +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations + +# Django stuff: +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation + +# PyBuilder + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +### Backup template +*.bak +*.gho +*.ori +*.orig +*.tmp +docs/manual/source/_build/ +docs/manual/source/_static/ +docs/manual/source/_templates/ \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/CHANGES.txt new/ldap3-2.6/CHANGES.txt --- old/ldap3-2.5.2/CHANGES.txt 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/CHANGES.txt 2019-03-23 16:43:44.000000000 +0100 @@ -1,4 +1,5 @@ -# 2.5.2 - not yet released +# 2.5.2 - 2018.12.28 + - when starting tls before binding the connection is automatically open - fixed changelog date (thanks Adam) - support for AD timedeltas (thanks mprahl) - fixed WhoAmI in mock strategies (thanks mprahl) @@ -9,6 +10,9 @@ - fixed NTLM bind (thanks ribx) - server state in ServerPool is now a namedtuple "ServerState" (thanks Krisztian) - fixed error when adding member to AD group with unsafe DN (thanks Maxim) + - properly restore lazy status in reusable strategy (thanks Krisztian) + - ServerState namedtuple converted to class in core/pooling (thanks Krisztian) + - empty schema doesn't raise exception in Abstraction Layer (thanks ghost) # 2.5.1 - 2018.08.01 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/_changelog.txt new/ldap3-2.6/_changelog.txt --- old/ldap3-2.5.2/_changelog.txt 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/_changelog.txt 2019-03-23 16:43:44.000000000 +0100 @@ -1,4 +1,16 @@ -# 2.5.2 - not yet released +# 2.6 - not yet released + - fixed empty digestMd5.py file in 2.5.2 package + - explicitly declare digest module md5 in util.ntlm (thanks adawalli) + - change object passed to modify() was unexpectedly mutated (thanks John) + - added LDAPInfoError exception + - added Server.has_control(control) method to check if a server has a specific control + - added Server.has_extension(extension) method to check if a server has a specific extension + - added Server.has_feature(feature) method to check if a server has a specific feature + - fixed checking of \\ in safe_dn (thanks Maxim) + - fixed uuid checking with 5c byte value + - added single=True parameter to the ServerPool object definition. Now server states is shared between connections + +# 2.5.2 - 2018.12.28 - when starting tls before binding the connection is automatically open - fixed changelog date (thanks Adam) - support for AD timedeltas (thanks mprahl) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/_version.json new/ldap3-2.6/_version.json --- old/ldap3-2.5.2/_version.json 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/_version.json 2019-03-23 16:43:44.000000000 +0100 @@ -6,6 +6,6 @@ "url": "https://github.com/cannatag/ldap3", "description": "A strictly RFC 4510 conforming LDAP V3 pure Python client library", "author": "Giovanni Cannata", - "version": "2.5.2", + "version": "2.6", "license": "LGPL v3" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/docs/manual/source/searches.rst new/ldap3-2.6/docs/manual/source/searches.rst --- old/ldap3-2.5.2/docs/manual/source/searches.rst 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/docs/manual/source/searches.rst 2019-03-23 16:43:44.000000000 +0100 @@ -157,7 +157,7 @@ The scope of the search specifies how broad the search context will be. The LDAP database is a hierarchical structure (similar to a traditional file system) with a root and with container and leaf objects. a container can be stored in other -containers, but not in a leaf object. It must be _clear that containers and leafs structure has nothing to do with the group +containers, but not in a leaf object. It must be clear that containers and leafs structure has nothing to do with the group and group membership objects. A group (groupOfNames) object is a leaf object with a member attribute that contains references to other objects. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/docs/manual/source/server.rst new/ldap3-2.6/docs/manual/source/server.rst --- old/ldap3-2.5.2/docs/manual/source/server.rst 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/docs/manual/source/server.rst 2019-03-23 16:43:44.000000000 +0100 @@ -78,6 +78,7 @@ LDAPServerPoolExhaustedError exception. With ``exhaust=True`` if a server is not active it will be removed by the pool, if you set it to a number this will be the number of seconds an unreachable server is considered offline. When this timout expires the server is reinserted in the pool and checked again for availability. +The pool keeps a single state for all connections that use it. If you want a different state for each connection you must set ``single=False`` while defining the ServerPool. When all servers in a pool are not available the strategy will wait for the number of seconds specified in ``ldap.POOLING_LOOP_TIMEOUT`` before starting a new cycle. This defaults to 10 seconds. @@ -149,4 +150,3 @@ and then you can use the server as usual. Hostname must resolve to a real server. -Attribute missing diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/ldap3/core/connection.py new/ldap3-2.6/ldap3/core/connection.py --- old/ldap3-2.5.2/ldap3/core/connection.py 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/ldap3/core/connection.py 2019-03-23 16:43:44.000000000 +0100 @@ -1037,6 +1037,7 @@ log(ERROR, '%s for <%s>', self.last_error, self) raise LDAPChangeError(self.last_error) + changelist = dict() for attribute_name in changes: if self.server and self.server.schema and self.check_names: if ';' in attribute_name: # remove tags for checking @@ -1054,7 +1055,7 @@ log(ERROR, '%s for <%s>', self.last_error, self) raise LDAPChangeError(self.last_error) - changes[attribute_name] = [change] # insert change in a tuple + changelist[attribute_name] = [change] # insert change in a list else: for change_operation in change: if len(change_operation) != 2 or change_operation[0] not in [MODIFY_ADD, MODIFY_DELETE, MODIFY_REPLACE, MODIFY_INCREMENT, 0, 1, 2, 3]: @@ -1062,7 +1063,8 @@ if log_enabled(ERROR): log(ERROR, '%s for <%s>', self.last_error, self) raise LDAPChangeError(self.last_error) - request = modify_operation(dn, changes, self.auto_encode, self.server.schema if self.server else None, validator=self.server.custom_validator if self.server else None, check_names=self.check_names) + changelist[attribute_name] = change + request = modify_operation(dn, changelist, self.auto_encode, self.server.schema if self.server else None, validator=self.server.custom_validator if self.server else None, check_names=self.check_names) if log_enabled(PROTOCOL): log(PROTOCOL, 'MODIFY request <%s> sent via <%s>', modify_request_to_dict(request), self) response = self.post_send_single_response(self.send('modifyRequest', request, controls)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/ldap3/core/exceptions.py new/ldap3-2.6/ldap3/core/exceptions.py --- old/ldap3-2.5.2/ldap3/core/exceptions.py 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/ldap3/core/exceptions.py 2019-03-23 16:43:44.000000000 +0100 @@ -376,9 +376,11 @@ class LDAPCursorError(LDAPExceptionError): pass + class LDAPObjectDereferenceError(LDAPExceptionError): pass + # security exceptions class LDAPSSLNotSupportedError(LDAPExceptionError, ImportError): pass @@ -505,6 +507,10 @@ pass +class LDAPInfoError(LDAPExceptionError): + pass + + # communication exceptions class LDAPCommunicationError(LDAPExceptionError): pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/ldap3/core/pooling.py new/ldap3-2.6/ldap3/core/pooling.py --- old/ldap3-2.5.2/ldap3/core/pooling.py 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/ldap3/core/pooling.py 2019-03-23 16:43:44.000000000 +0100 @@ -195,7 +195,8 @@ servers=None, pool_strategy=ROUND_ROBIN, active=True, - exhaust=False): + exhaust=False, + single_state=True): if pool_strategy not in POOLING_STRATEGIES: if log_enabled(ERROR): @@ -209,6 +210,8 @@ self.pool_states = dict() self.active = active self.exhaust = exhaust + self.single = single_state + self._pool_state = None # used for storing the global state of the pool if isinstance(servers, SEQUENCE_TYPES + (Server, )): self.add(servers) elif isinstance(servers, STRING_TYPES): @@ -276,9 +279,13 @@ log(ERROR, 'server must be a Server of a list of Servers when adding to Server Pool <%s>', self) raise LDAPServerPoolError('server must be a Server or a list of Server') - for connection in self.pool_states: - # notifies connections using this pool to refresh - self.pool_states[connection].refresh() + if self.single: + if self._pool_state: + self._pool_state.refresh() + else: + for connection in self.pool_states: + # notifies connections using this pool to refresh + self.pool_states[connection].refresh() def remove(self, server): if server in self.servers: @@ -288,14 +295,22 @@ log(ERROR, 'server %s to be removed not in Server Pool <%s>', server, self) raise LDAPServerPoolError('server not in server pool') - for connection in self.pool_states: - # notifies connections using this pool to refresh - self.pool_states[connection].refresh() + if self.single: + if self._pool_state: + self._pool_state.refresh() + else: + for connection in self.pool_states: + # notifies connections using this pool to refresh + self.pool_states[connection].refresh() def initialize(self, connection): - pool_state = ServerPoolState(self) # registers pool_state in ServerPool object - self.pool_states[connection] = pool_state + if self.single: + if not self._pool_state: + self._pool_state = ServerPoolState(self) + self.pool_states[connection] = self._pool_state + else: + self.pool_states[connection] = ServerPoolState(self) def get_server(self, connection): if connection in self.pool_states: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/ldap3/core/server.py new/ldap3-2.6/ldap3/core/server.py --- old/ldap3-2.5.2/ldap3/core/server.py 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/ldap3/core/server.py 2019-03-23 16:43:44.000000000 +0100 @@ -28,7 +28,7 @@ from datetime import datetime, MINYEAR from .. import DSA, SCHEMA, ALL, BASE, get_config_parameter, OFFLINE_EDIR_8_8_8, OFFLINE_AD_2012_R2, OFFLINE_SLAPD_2_4, OFFLINE_DS389_1_3_3, SEQUENCE_TYPES, IP_SYSTEM_DEFAULT, IP_V4_ONLY, IP_V6_ONLY, IP_V4_PREFERRED, IP_V6_PREFERRED, STRING_TYPES -from .exceptions import LDAPInvalidServerError, LDAPDefinitionError, LDAPInvalidPortError, LDAPInvalidTlsSpecificationError, LDAPSocketOpenError +from .exceptions import LDAPInvalidServerError, LDAPDefinitionError, LDAPInvalidPortError, LDAPInvalidTlsSpecificationError, LDAPSocketOpenError, LDAPInfoError from ..protocol.formatters.standard import format_attribute_values from ..protocol.rfc4511 import LDAP_MAX_INT from ..protocol.rfc4512 import SchemaInfo, DsaInfo @@ -69,7 +69,6 @@ _message_counter = 0 _message_id_lock = Lock() # global lock for message_id shared by all Server objects - def __init__(self, host, port=None, @@ -570,3 +569,34 @@ for candidate in candidates: log(BASIC, 'obtained candidate address for <%s>: <%r> with mode %s', self, candidate[:-2], self.mode) return candidates + + def _check_info_property(self, kind, name): + if not self._dsa_info: + raise LDAPInfoError('server info not loaded') + + if kind == 'control': + properties = self.info.supported_controls + elif kind == 'extension': + properties = self.info.supported_extensions + elif kind == 'feature': + properties = self.info.supported_features + else: + raise LDAPInfoError('invalid info category') + + for prop in properties: + if name == prop[0] or (prop[2] and name.lower() == prop[2].lower()): # checks oid and description + return True + + return False + + def has_control(self, control): + return self._check_info_property('control', control) + + def has_extension(self, extension): + return self._check_info_property('extension', extension) + + def has_feature(self, feature): + return self._check_info_property('feature', feature) + + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/ldap3/protocol/convert.py new/ldap3-2.6/ldap3/protocol/convert.py --- old/ldap3-2.5.2/ldap3/protocol/convert.py 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/ldap3/protocol/convert.py 2019-03-23 16:43:44.000000000 +0100 @@ -37,6 +37,7 @@ except PyAsn1Error: # invalid encoding, return bytes value return {'type': str(attribute['type']), 'values': [bytes(val) for val in attribute['vals']]} + def attributes_to_dict(attributes): attributes_dict = dict() for attribute in attributes: @@ -93,6 +94,7 @@ except Exception: return {'attribute': str(ava['attributeDesc']), 'value': bytes(ava['assertionValue'])} + def substring_to_dict(substring): return {'initial': substring['initial'] if substring['initial'] else '', 'any': [middle for middle in substring['any']] if substring['any'] else '', 'final': substring['final'] if substring['final'] else ''} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/ldap3/protocol/formatters/formatters.py new/ldap3-2.6/ldap3/protocol/formatters/formatters.py --- old/ldap3-2.5.2/ldap3/protocol/formatters/formatters.py 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/ldap3/protocol/formatters/formatters.py 2019-03-23 16:43:44.000000000 +0100 @@ -32,6 +32,7 @@ from ...core.timezone import OffsetTzInfo + def format_unicode(raw_value): try: if str is not bytes: # Python 3 @@ -108,16 +109,17 @@ try: timestamp = int(raw_value) if timestamp < 0: # ad timestamp cannot be negative - return raw_value + timestamp = timestamp * -1 except Exception: return raw_value try: - return datetime.fromtimestamp(timestamp / 10000000.0 - 11644473600, tz=OffsetTzInfo(0, 'UTC')) # forces true division in python 2 + return datetime.fromtimestamp(timestamp / 10000000.0 - 11644473600, + tz=OffsetTzInfo(0, 'UTC')) # forces true division in python 2 except (OSError, OverflowError, ValueError): # on Windows backwards timestamps are not allowed try: unix_epoch = datetime.fromtimestamp(0, tz=OffsetTzInfo(0, 'UTC')) - diff_seconds = timedelta(seconds=timestamp/10000000.0 - 11644473600) + diff_seconds = timedelta(seconds=timestamp / 10000000.0 - 11644473600) return unix_epoch + diff_seconds except Exception: pass @@ -129,6 +131,7 @@ try: # uses regular expressions and the timezone class (python3.2 and later) from datetime import timezone + time_format = re.compile( r''' ^ @@ -158,6 +161,7 @@ re.VERBOSE ) + def format_time(raw_value): try: match = time_format.fullmatch(to_unicode(raw_value)) @@ -218,12 +222,12 @@ representing a date and time. The LDAP-specific encoding of a value of this syntax is a restriction of the format defined in [ISO8601], and is described by the following ABNF: - + GeneralizedTime = century year month day hour [ minute [ second / leap-second ] ] [ fraction ] g-time-zone - + century = 2(%x30-39) ; "00" to "99" year = 2(%x30-39) ; "00" to "99" month = ( %x30 %x31-39 ) ; "01" (January) to "09" @@ -242,7 +246,9 @@ MINUS = %x2D ; minus sign ("-") """ - if len(raw_value) < 10 or not all((c in b'0123456789+-,.Z' for c in raw_value)) or (b'Z' in raw_value and not raw_value.endswith(b'Z')): # first ten characters are mandatory and must be numeric or timezone or fraction + if len(raw_value) < 10 or not all((c in b'0123456789+-,.Z' for c in raw_value)) or ( + b'Z' in raw_value and not raw_value.endswith( + b'Z')): # first ten characters are mandatory and must be numeric or timezone or fraction return raw_value # sets position for fixed values @@ -305,9 +311,11 @@ return raw_value if str is not bytes: # Python 3 - timezone = OffsetTzInfo((timezone_hour * 60 + timezone_minute) * (1 if sep == b'+' else -1), 'UTC' + str(sep + offset, encoding='utf-8')) + timezone = OffsetTzInfo((timezone_hour * 60 + timezone_minute) * (1 if sep == b'+' else -1), + 'UTC' + str(sep + offset, encoding='utf-8')) else: # Python 2 - timezone = OffsetTzInfo((timezone_hour * 60 + timezone_minute) * (1 if sep == b'+' else -1), unicode('UTC' + sep + offset, encoding='utf-8')) + timezone = OffsetTzInfo((timezone_hour * 60 + timezone_minute) * (1 if sep == b'+' else -1), + unicode('UTC' + sep + offset, encoding='utf-8')) try: return datetime(year=year, @@ -334,7 +342,7 @@ # positive, we can reuse format_ad_timestamp to get a datetime object. # Afterwards, we can subtract a datetime representing 0 hour on January 1, # 1601 from the returned datetime to get the timedelta. - return format_ad_timestamp(raw_value * -1) - format_ad_timestamp(0) + return format_ad_timestamp(raw_value) - format_ad_timestamp(0) def format_time_with_0_year(raw_value): @@ -399,7 +407,8 @@ sub_authority = '' i = 0 while i < sub_authority_count: - sub_authority += '-' + str(int.from_bytes(raw_value[8 + (i * 4): 12 + (i * 4)], byteorder='little')) # little endian + sub_authority += '-' + str( + int.from_bytes(raw_value[8 + (i * 4): 12 + (i * 4)], byteorder='little')) # little endian i += 1 else: # Python 2 revision = int(ord(raw_value[0])) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/ldap3/protocol/formatters/standard.py new/ldap3-2.6/ldap3/protocol/formatters/standard.py --- old/ldap3-2.5.2/ldap3/protocol/formatters/standard.py 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/ldap3/protocol/formatters/standard.py 2019-03-23 16:43:44.000000000 +0100 @@ -124,6 +124,7 @@ '1.2.840.113556.1.4.51': (format_ad_timestamp, validate_ad_timestamp), # lastLogoff (Microsoft) '1.2.840.113556.1.4.52': (format_ad_timestamp, validate_ad_timestamp), # lastLogon (Microsoft) '1.2.840.113556.1.4.60': (format_ad_timedelta, validate_ad_timedelta), # lockoutDuration (Microsoft) + '1.2.840.113556.1.4.61': (format_ad_timedelta, validate_ad_timedelta), # lockOutObservationWindow (Microsoft) '1.2.840.113556.1.4.74': (format_ad_timedelta, validate_ad_timedelta), # maxPwdAge (Microsoft) '1.2.840.113556.1.4.78': (format_ad_timedelta, validate_ad_timedelta), # minPwdAge (Microsoft) '1.2.840.113556.1.4.96': (format_ad_timestamp, validate_zero_and_minus_one_and_positive_int), # pwdLastSet (Microsoft, can be set to -1 only) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/ldap3/protocol/formatters/validators.py new/ldap3-2.6/ldap3/protocol/formatters/validators.py --- old/ldap3-2.5.2/ldap3/protocol/formatters/validators.py 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/ldap3/protocol/formatters/validators.py 2019-03-23 16:43:44.000000000 +0100 @@ -31,7 +31,7 @@ from ... import SEQUENCE_TYPES, STRING_TYPES, NUMERIC_TYPES, INTEGER_TYPES from .formatters import format_time, format_ad_timestamp -from ...utils.conv import to_raw, to_unicode, ldap_escape_to_bytes +from ...utils.conv import to_raw, to_unicode, ldap_escape_to_bytes, escape_bytes # Validators return True if value is valid, False if value is not valid, # or a value different from True and False that is a valid value to substitute to the input value @@ -97,7 +97,7 @@ valid_values = [] # builds a list of valid int values from decimal import Decimal, InvalidOperation for element in input_value: - try: # try to convert any type to int, an invalid conversion raise TypeError or ValueError, doublecheck with Decimal type, if both are valid and equal then then int() value is used + try: #try to convert any type to int, an invalid conversion raise TypeError or ValueError, doublecheck with Decimal type, if both are valid and equal then then int() value is used value = to_unicode(element) if isinstance(element, bytes) else element decimal_value = Decimal(value) int_value = int(value) @@ -258,6 +258,7 @@ else: return True + def validate_ad_timedelta(input_value): """ Should be validated like an AD timestamp except that since it is a time @@ -267,6 +268,7 @@ return False return validate_ad_timestamp(input_value * -1) + def validate_guid(input_value): """ object guid in uuid format (Novell eDirectory) @@ -309,6 +311,7 @@ else: return True + def validate_uuid(input_value): """ object entryUUID in uuid format @@ -386,7 +389,9 @@ error = True elif '\\' in element: try: - valid_values.append(UUID(bytes_le=ldap_escape_to_bytes(element)).bytes_le) # byte representation, value in little endian + uuid = UUID(bytes_le=ldap_escape_to_bytes(element)).bytes_le + uuid = escape_bytes(uuid) + valid_values.append(uuid) # byte representation, value in little endian changed = True except ValueError: error = True @@ -398,7 +403,7 @@ error = True if error and str == bytes: # python2 only assume value is bytes and valid valid_values.append(element) # value is untouched, must be in little endian - elif isinstance(element, (bytes, bytearray)) : # assumes bytes are valid uuid + elif isinstance(element, (bytes, bytearray)): # assumes bytes are valid uuid valid_values.append(element) # value is untouched, must be in little endian else: return False diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/ldap3/protocol/sasl/digestMd5.py new/ldap3-2.6/ldap3/protocol/sasl/digestMd5.py --- old/ldap3-2.5.2/ldap3/protocol/sasl/digestMd5.py 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/ldap3/protocol/sasl/digestMd5.py 2019-03-23 16:43:44.000000000 +0100 @@ -66,7 +66,7 @@ if not isinstance(s, bytes): s = s.encode() - return hmac.new(k, s).hexdigest() + return hmac.new(k, s, digestmod=hashlib.md5).hexdigest() def sasl_digest_md5(connection, controls): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/ldap3/utils/conv.py new/ldap3-2.6/ldap3/utils/conv.py --- old/ldap3-2.5.2/ldap3/utils/conv.py 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/ldap3/utils/conv.py 2019-03-23 16:43:44.000000000 +0100 @@ -146,6 +146,7 @@ else: # Python 2 return value.decode() + def json_encode_b64(obj): try: return dict(encoding='base64', encoded=b64encode(obj)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/ldap3/utils/dn.py new/ldap3-2.6/ldap3/utils/dn.py --- old/ldap3-2.5.2/ldap3/utils/dn.py 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/ldap3/utils/dn.py 2019-03-23 16:43:44.000000000 +0100 @@ -319,7 +319,7 @@ if dn.startswith('<GUID=') and dn.endswith('>'): # Active Directory allows looking up objects by putting its GUID in a specially-formatted DN (e.g. '<GUID=7b95f0d5-a3ed-486c-919c-077b8c9731f2>') escaped_dn = dn - elif '@' not in dn and '\\' not in dn: # active directory UPN (User Principal Name) consist of an account, the at sign (@) and a domain, or the domain level logn name domain\username + elif '@' not in dn: # active directory UPN (User Principal Name) consist of an account, the at sign (@) and a domain, or the domain level logn name domain\username for component in parse_dn(dn, escape=True): if decompose: escaped_dn.append((component[0], component[1], component[2])) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/ldap3/utils/ntlm.py new/ldap3-2.6/ldap3/utils/ntlm.py --- old/ldap3-2.5.2/ldap3/utils/ntlm.py 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/ldap3/utils/ntlm.py 2019-03-23 16:43:44.000000000 +0100 @@ -483,7 +483,7 @@ temp += self.server_target_info_raw temp += pack('<I', 0) # Z(4) response_key_nt = self.ntowf_v2() - nt_proof_str = hmac.new(response_key_nt, self.server_challenge + temp).digest() + nt_proof_str = hmac.new(response_key_nt, self.server_challenge + temp, digestmod=hashlib.md5).digest() nt_challenge_response = nt_proof_str + temp return nt_challenge_response @@ -494,4 +494,4 @@ password_digest = binascii.unhexlify(passparts[1]) else: password_digest = hashlib.new('MD4', self._password.encode('utf-16-le')).digest() - return hmac.new(password_digest, (self.user_name.upper() + self.user_domain).encode('utf-16-le')).digest() + return hmac.new(password_digest, (self.user_name.upper() + self.user_domain).encode('utf-16-le'), digestmod=hashlib.md5).digest() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/ldap3/version.py new/ldap3-2.6/ldap3/version.py --- old/ldap3-2.5.2/ldap3/version.py 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/ldap3/version.py 2019-03-23 16:43:44.000000000 +0100 @@ -1,6 +1,6 @@ # THIS FILE IS AUTO-GENERATED. PLEASE DO NOT MODIFY# version file for ldap3 -# generated on 2018-12-07 23:55:26.075512 -# on system uname_result(system='Windows', node='ELITE10GC', release='10', version='10.0.17134', machine='AMD64', processor='Intel64 Family 6 Model 58 Stepping 9, GenuineIntel') +# generated on 2018-12-28 22:18:22.295577 +# on system uname_result(system='Windows', node='ELITE10GC', release='10', version='10.0.17763', machine='AMD64', processor='Intel64 Family 6 Model 58 Stepping 9, GenuineIntel') # with Python 3.7.1 - ('v3.7.1:260ec2c36a', 'Oct 20 2018 14:57:15') - MSC v.1915 64 bit (AMD64) # __version__ = '2.5.2' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/test/config.py new/ldap3-2.6/test/config.py --- old/ldap3-2.5.2/test/config.py 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/test/config.py 2019-03-23 16:43:44.000000000 +0100 @@ -38,7 +38,7 @@ from ldap3 import __version__ as ldap3_version from pyasn1 import __version__ as pyasn1_version -test_strategy = SYNC # possible choices: SYNC, ASYNC, RESTARTABLE, REUSABLE, MOCK_SYNC (not used on TRAVIS - look at .travis.yml) +test_strategy = SYNC # possible choices: SYNC, ASYNC, RESTARTABLE, REUSABLE, MOCK_SYNC, MOCK_ASYNC (not used on TRAVIS - look at .travis.yml) test_server_type = 'EDIR' # possible choices: EDIR (Novell eDirectory), AD (Microsoft Active Directory), SLAPD (OpenLDAP) test_pool_size = 5 @@ -58,7 +58,7 @@ test_receive_timeout = None test_auto_escape = True test_auto_encode = True -test_lazy_connection = False +test_lazy_connection = True test_user_password = 'Rc2597pfop' # default password for users created in tests test_validator = {} @@ -182,7 +182,7 @@ # test notepbook - eDirectory (EDIR) # test_server = ['edir1.hyperv', # 'edir2.hyperv'] # ldap server where tests are executed, if a list is given a pool will be created - test_server = 'edir1.hyperv' + test_server = 'edir4.hyperv' test_server_type = 'EDIR' test_root_partition = '' test_base = 'ou=fixtures,o=test' # base context where test objects are created @@ -192,7 +192,7 @@ test_multivalued_attribute = 'givenname' test_singlevalued_attribute = 'generationQualifier' test_server_context = 'o=resources' # used in novell eDirectory extended operations - test_server_edir_name = 'edir1' # used in novell eDirectory extended operations + test_server_edir_name = 'edir4' # used in novell eDirectory extended operations test_user = 'cn=test_admin_user,ou=bind,o=test' # the user that performs the tests test_password = 'password1' # user password test_secondary_user = 'cn=test_bind_user,ou=bind,o=test' @@ -365,6 +365,7 @@ print('Logging:', 'False' if not test_logging else test_logging_filename, '- Log detail:', (get_detail_level_name(test_log_detail) if test_logging else 'None') + ' - Internal decoder: ', test_internal_decoder, ' - Response waiting timeout:', get_config_parameter('RESPONSE_WAITING_TIMEOUT')) print() + def random_id(): return str(SystemRandom().random())[-5:] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/test/testFormatters.py new/ldap3-2.6/test/testFormatters.py --- old/ldap3-2.5.2/test/testFormatters.py 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/test/testFormatters.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,12 +0,0 @@ -import unittest -from datetime import timedelta - -from ldap3.protocol.formatters.formatters import format_ad_timedelta - - -class TestFormatters(unittest.TestCase): - def test_format_ad_timedelta_thirty_mins(self): - self.assertEqual(format_ad_timedelta(-18000000000), timedelta(minutes=30)) - - def test_format_ad_timedelta_one_day(self): - self.assertEqual(format_ad_timedelta(-864000000000), timedelta(days=1)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/test/testValidators.py new/ldap3-2.6/test/testValidators.py --- old/ldap3-2.5.2/test/testValidators.py 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/test/testValidators.py 2019-03-23 16:43:44.000000000 +0100 @@ -1,7 +1,7 @@ import unittest from datetime import datetime -from ldap3.protocol.formatters.validators import validate_integer, validate_boolean, validate_bytes, validate_generic_single_value, validate_time, validate_zero_and_minus_one_and_positive_int, validate_ad_timedelta +from ldap3.protocol.formatters.validators import validate_integer, validate_boolean, validate_bytes, validate_generic_single_value, validate_time, validate_zero_and_minus_one_and_positive_int from ldap3.core.timezone import OffsetTzInfo class Test(unittest.TestCase): @@ -202,9 +202,3 @@ self.assertTrue(validated) validated = validate_zero_and_minus_one_and_positive_int('-2') self.assertFalse(validated) - - def test_validate_ad_timedelta_valid(self): - self.assertTrue(validate_ad_timedelta(-36288000000000)) - - def test_validate_ad_timedelta_invalid(self): - self.assertFalse(validate_ad_timedelta(123)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ldap3-2.5.2/upload-to-pypi.cmd new/ldap3-2.6/upload-to-pypi.cmd --- old/ldap3-2.5.2/upload-to-pypi.cmd 2018-12-23 09:49:04.000000000 +0100 +++ new/ldap3-2.6/upload-to-pypi.cmd 2019-03-23 16:43:44.000000000 +0100 @@ -1 +1 @@ -\Python\Python36\Scripts\twine upload dist/* +\Python\Python37\Scripts\twine upload dist/*
