Hello community, here is the log from the commit of package python-slapdsock for openSUSE:Factory checked in at 2017-11-12 18:03:42 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-slapdsock (Old) and /work/SRC/openSUSE:Factory/.python-slapdsock.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-slapdsock" Sun Nov 12 18:03:42 2017 rev:6 rq:540771 version:0.7.6 Changes: -------- --- /work/SRC/openSUSE:Factory/python-slapdsock/python-slapdsock.changes 2017-09-11 16:17:51.906208778 +0200 +++ /work/SRC/openSUSE:Factory/.python-slapdsock.new/python-slapdsock.changes 2017-11-12 18:03:43.773796014 +0100 @@ -1,0 +2,7 @@ +Sat Nov 11 17:56:58 UTC 2017 - [email protected] + +- update to upstream release 0.7.6 + * more message classes + * minor bug fixes + +------------------------------------------------------------------- Old: ---- slapdsock-0.6.0.tar.gz slapdsock-0.6.0.tar.gz.asc New: ---- slapdsock-0.7.6.tar.gz slapdsock-0.7.6.tar.gz.asc ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-slapdsock.spec ++++++ --- /var/tmp/diff_new_pack.c39L1R/_old 2017-11-12 18:03:45.725724916 +0100 +++ /var/tmp/diff_new_pack.c39L1R/_new 2017-11-12 18:03:45.725724916 +0100 @@ -17,7 +17,7 @@ Name: python-slapdsock -Version: 0.6.0 +Version: 0.7.6 Release: 0 Summary: Python module for slapd-sock listeners License: Apache-2.0 ++++++ slapdsock-0.6.0.tar.gz -> slapdsock-0.7.6.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slapdsock-0.6.0/PKG-INFO new/slapdsock-0.7.6/PKG-INFO --- old/slapdsock-0.6.0/PKG-INFO 2017-09-06 10:44:43.000000000 +0200 +++ new/slapdsock-0.7.6/PKG-INFO 2017-11-11 18:54:29.000000000 +0100 @@ -1,11 +1,12 @@ Metadata-Version: 1.1 Name: slapdsock -Version: 0.6.0 +Version: 0.7.6 Summary: Module package for back-sock listeners for OpenLDAP Home-page: https://www.stroeder.com/slapdsock.html Author: Michael Stroeder Author-email: [email protected] License: Apache License, Version 2.0 +Description-Content-Type: UNKNOWN Description: Module package for implementing back-sock listeners for the OpenLDAP server either working as full backend or overlay. Binary files old/slapdsock-0.6.0/examples/openldap/accesslog/data.mdb and new/slapdsock-0.7.6/examples/openldap/accesslog/data.mdb differ Binary files old/slapdsock-0.6.0/examples/openldap/accesslog/lock.mdb and new/slapdsock-0.7.6/examples/openldap/accesslog/lock.mdb differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slapdsock-0.6.0/examples/openldap/realdb.conf new/slapdsock-0.7.6/examples/openldap/realdb.conf --- old/slapdsock-0.6.0/examples/openldap/realdb.conf 2017-09-06 10:44:25.000000000 +0200 +++ new/slapdsock-0.7.6/examples/openldap/realdb.conf 2017-11-06 23:26:57.000000000 +0100 @@ -16,13 +16,9 @@ overlay sock extensions binddn peername ssf connid -socketpath /tmp/modify-listener -sockops modify - -overlay sock -extensions binddn peername ssf connid -socketpath /tmp/bind-listener -sockops bind +socketpath /tmp/noop-listener +#sockdnpat "^uid=[a-z0-9]+,ou=data,dc=example,dc=org$" +sockops compare extended access to dn.subtree="ou=data,dc=example,dc=org" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slapdsock-0.6.0/examples/passmod.py new/slapdsock-0.7.6/examples/passmod.py --- old/slapdsock-0.6.0/examples/passmod.py 2017-09-06 10:44:25.000000000 +0200 +++ new/slapdsock-0.7.6/examples/passmod.py 2017-09-12 14:23:19.000000000 +0200 @@ -123,6 +123,18 @@ # Classes and functions #----------------------------------------------------------------------- +def unicode_pwd(password): + """ + returns password or random generated password as properly encoded + 'unicodePwd' value for MS AD + + see also: + https://msdn.microsoft.com/en-us/library/cc223248.aspx + https://support.microsoft.com/en-us/help/269190/how-to-change-a-windows-active-directory-and-lds-user-password-through-ldap + """ + return u'"{}"'.format(password).encode('utf-16-le') + + class DictQueue(Queue.Queue): """ modified Queue class which internally stores items in a dict @@ -146,14 +158,12 @@ """ Thread class for the password synchronization worker """ - interval = 1.0 + passwd_update_delay = 1.0 source_id_attr = 'uid' target_filter_format = '({0}={1})' target_id_attr = 'uid' target_password_attr = 'userPassword' target_password_encoding = 'utf-8' - # MS AD - #target_password_attr = 'unicodePwd' def __init__( self, @@ -173,19 +183,56 @@ self._queue = queue threading.Thread.__init__(self, name=self.__class__.__module__+self.__class__.__name__) LocalLDAPConn.__init__(self, self.logger) - # open connection to target LDAP server - self.target_conn = MyLDAPObject( - target_ldap_url.initializeUrl(), - trace_level=PYLDAP_TRACELEVEL, - trace_file=LoggerFileobj(self.logger, logging.DEBUG), - retry_max=LDAP_MAXRETRYCOUNT, - retry_delay=LDAP_RETRYDELAY, - who=target_ldap_url.who or '', - cred=target_ldap_url.cred or '', - cache_time=LDAP_CACHE_TTL, + self._target_conn = None + self._target_conn_lock = ldap.LDAPLock( + desc='target_conn() in %s' % (repr(self.__class__)) ) # end of PWSyncWorker.__init__() + def target_conn(self): + """ + open and cache target connection + """ + if isinstance(self._target_conn, MyLDAPObject): + self.logger.debug( + 'Existing LDAP connection to %s (%s)', + repr(self._target_conn._uri), + repr(self._target_conn), + ) + return self._target_conn + try: + self._target_conn_lock.acquire() + try: + self._target_conn = MyLDAPObject( + self._target_ldap_url.initializeUrl(), + trace_level=PYLDAP_TRACELEVEL, + trace_file=LoggerFileobj(self.logger, logging.DEBUG), + retry_max=LDAP_MAXRETRYCOUNT, + retry_delay=LDAP_RETRYDELAY, + who=self._target_ldap_url.who or '', + cred=self._target_ldap_url.cred or '', + cache_time=LDAP_CACHE_TTL, + ) + except ldap.LDAPError, ldap_error: + self._target_conn = None + self.logger.error( + 'LDAPError during connecting to %s: %s', + repr(self.ldapi_uri), + str(ldap_error), + ) + raise ldap_error + else: + self._target_conn.authz_id = self._target_conn.whoami_s() + self.logger.info( + 'Successfully bound to %s as %s (%s)', + repr(self.ldapi_uri), + repr(self._target_conn.authz_id), + repr(self._target_conn), + ) + finally: + self._target_conn_lock.release() + return self._target_conn # get_ldapi_conn() + def _check_password(self, user_dn, new_passwd): password_correct = False self.logger.debug('Check password of %r', user_dn) @@ -205,7 +252,6 @@ cache_time=LDAP_CACHE_TTL, ) except ldap.INVALID_CREDENTIALS: - self.logger.warn('Ignoring wrong password for %r', user_dn) password_correct = False else: password_correct = True @@ -229,7 +275,7 @@ ) return None self.logger.debug('Extracted %s=%r from source_dn=%r', self.source_id_attr, uid, source_dn) - target_conn = self.target_conn + target_conn = self.target_conn() target_filter = self.target_filter_format.format(self.target_id_attr, uid) ldap_result = target_conn.search_ext_s( self._target_ldap_url.dn, @@ -246,11 +292,6 @@ ] self.logger.debug('ldap_result=%r', ldap_result) if len(ldap_result) != 1: - self.logger.warn( - 'No unique ID found with %r => ignore password change of %r', - target_filter, - source_dn, - ) return None target_id = ldap_result[0][0] return target_id # end of PWSyncWorker.get_target_id() @@ -259,13 +300,18 @@ """ encode argument password for target system """ - return password.decode('utf-8').encode(self.target_password_encoding) + pwu = password.decode('utf-8') + if self.target_password_attr.lower() == 'unicodepwd': + result = unicode_pwd(pwu) + else: + result = pwu.encode(self.target_password_encoding) + return result def update_target_password(self, target_id, old_passwd, new_passwd, req_time): """ write new password to target """ - target_conn = self.target_conn + target_conn = self.target_conn() modlist = [( ldap.MOD_REPLACE, self.target_password_attr, @@ -290,13 +336,27 @@ ldap_strf_secs(req_time), ) try: + sleep_time = max( + 0, + time.time()-req_time+self.passwd_update_delay + ) + self.logger.debug( + 'Deferring syncing password for %r for %f secs', + user_dn, + sleep_time, + ) + time.sleep(sleep_time) if not self._check_password(user_dn, new_passwd): # simply ignore wrong passwords - self._queue.put((user_dn, (old_passwd, new_passwd, req_time))) + self.logger.warn('Ignoring wrong password for %r', user_dn) continue target_id = self.get_target_id(user_dn) if target_id is None: # simply ignore non-existent targets + self.logger.warn( + 'No target ID found for %r => ignore password change', + user_dn, + ) continue self.logger.debug('Try to sync password for %r to %r', user_dn, target_id) self.update_target_password(target_id, old_passwd, new_passwd, req_time) @@ -306,7 +366,6 @@ user_dn, exc_info=True, ) - #self._queue.put((user_dn, (old_passwd, new_passwd, req_time))) else: self.logger.info('Synced password for %r to %r', user_dn, target_id) self._queue.task_done() @@ -481,12 +540,16 @@ socket_path = sys.argv[1] local_ldap_uri = sys.argv[2] target_ldap_url = sys.argv[3] + target_password_filename = sys.argv[4] except IndexError: my_logger.error('Not enough arguments => abort') sys.exit(1) local_ldap_uri_obj = MyLDAPUrl(local_ldap_uri) target_ldap_url_obj = MyLDAPUrl(target_ldap_url) + # read target password from file + with open(target_password_filename, 'rb') as target_password_file: + target_ldap_url_obj.cred = target_password_file.read() # initialize password sync consumer thread pwsync_worker = PWSyncWorker( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slapdsock-0.6.0/examples/test.py new/slapdsock-0.7.6/examples/test.py --- old/slapdsock-0.6.0/examples/test.py 1970-01-01 01:00:00.000000000 +0100 +++ new/slapdsock-0.7.6/examples/test.py 2017-09-04 17:03:57.000000000 +0200 @@ -0,0 +1,7 @@ +import ldap + +l = ldap.initialize('ldapi://%2Fhome%2Fmichael%2FProj%2Fpython-slapdsockd%2Fexamples%2Fopenldap%2Fldapi') + +l.sasl_external_bind_s() + +l.passwd_s('uid=test2,ou=data,dc=example,dc=org', None, '\x00') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slapdsock-0.6.0/slapdsock/handler.py new/slapdsock-0.7.6/slapdsock/handler.py --- old/slapdsock-0.6.0/slapdsock/handler.py 2017-09-06 10:44:25.000000000 +0200 +++ new/slapdsock-0.7.6/slapdsock/handler.py 2017-11-10 14:20:43.000000000 +0100 @@ -17,14 +17,20 @@ #----------------------------------------------------------------------- # from Python's standard lib -import sys, pwd, struct +import sys +import pwd +import struct import time -import socket, SocketServer -import logging, inspect +import socket +import SocketServer +import logging +import inspect +import datetime # internal import from slapsock import slapdsock.message from slapdsock.message import ENTRYResponse, RESULTResponse, InternalErrorResponse +from slapdsock.ldaphelper import ldap_datetime_str #----------------------------------------------------------------------- # Constants @@ -110,6 +116,9 @@ def __init__(self, *args, **kwargs): self._logged_vars = set() + # We need current time in GeneralizedTime syntax later + self.now_dt = datetime.datetime.utcnow() + self.now_str = ldap_datetime_str(self.now_dt) SocketServer.BaseRequestHandler.__init__(self, *args, **kwargs) def _get_peer_cred(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slapdsock-0.6.0/slapdsock/ldaphelper.py new/slapdsock-0.7.6/slapdsock/ldaphelper.py --- old/slapdsock-0.6.0/slapdsock/ldaphelper.py 2017-09-06 10:44:25.000000000 +0200 +++ new/slapdsock-0.7.6/slapdsock/ldaphelper.py 2017-11-10 17:04:48.000000000 +0100 @@ -431,6 +431,7 @@ ldapi_authz_id = '' ldap_retry_max = 4 ldap_retry_delay = 1.0 + ldap_timeout = LDAP_TIMEOUT ldap_cache_ttl = 0.0 ldap_trace_level = 0 @@ -480,6 +481,7 @@ trace_file=self._logger_fileobj, retry_max=self.ldap_retry_max, retry_delay=self.ldap_retry_delay, + timeout=self.ldap_timeout, cache_time=self.ldap_cache_ttl, ) self._ldapi_conn.sasl_external_bind_s( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slapdsock-0.6.0/slapdsock/message.py new/slapdsock-0.7.6/slapdsock/message.py --- old/slapdsock-0.6.0/slapdsock/message.py 2017-09-06 10:44:25.000000000 +0200 +++ new/slapdsock-0.7.6/slapdsock/message.py 2017-11-11 18:52:55.000000000 +0100 @@ -7,6 +7,7 @@ """ __all__ = [ + 'CONTINUE_RESPONSE', 'ListFile', 'SockRequest', 'ADDRequest', @@ -22,6 +23,14 @@ 'SockResponse', 'RESULTResponse', 'ENTRYResponse', + 'CompareFalseResponse', + 'CompareTrueResponse', + 'NoSuchObjectResponse', + 'InvalidCredentialsResponse', + 'UnwillingToPerformResponse', + 'SuccessResponse', + 'InternalErrorResponse', + 'InvalidAttributeSyntaxResponse', ] #----------------------------------------------------------------------- @@ -45,6 +54,13 @@ from slapdsock.ldaphelper import RESULT_CODE #----------------------------------------------------------------------- +# Constants +#----------------------------------------------------------------------- + +CONTINUE_RESPONSE = 'CONTINUE\n' + + +#----------------------------------------------------------------------- # Classes and functions #----------------------------------------------------------------------- @@ -66,7 +82,6 @@ class ListFile(object): - """ File-like object with readline method returning lines from a list of strings @@ -193,8 +208,9 @@ def _get_attrs(self): SockRequest._get_attrs(self) - self.dn, self.entry = self._parse_ldif( + dn, self.entry = self._parse_ldif( self._linecount, max_entries=1)[0] + self.dn = dn.decode('utf-8') class BINDRequest(SockRequest): @@ -280,7 +296,7 @@ SockRequest._get_attrs(self) -class COMPARERequest(SockRequest): +class COMPARERequest(ADDRequest): """ COMPARE @@ -297,15 +313,28 @@ 'ssf': int, 'connid': int, 'suffix': ldap_str, - 'dn': ldap_str, } cache_key_attrs = ( 'binddn', 'ssf', 'suffix', 'dn', + 'atype', + 'avalue', ) + def _get_attrs(self): + SockRequest._get_attrs(self) + self.dn, entry = self._parse_ldif(self._linecount, max_entries=1)[0] + assert len(entry) == 1, ValueError( + 'Only one assertion type allowed but, was: %r' % entry + ) + self.atype = entry.keys()[0].decode('utf-8') + assert len(entry[self.atype]) == 1, ValueError( + 'Only one assertion value allowed, but was: %r' % entry[self.atype] + ) + self.avalue = entry[self.atype][0] + class DELETERequest(SockRequest): @@ -355,8 +384,9 @@ def _get_attrs(self): SockRequest._get_attrs(self) - self.dn, self.modops, _ = self._parse_ldif( + dn, self.modops, _ = self._parse_ldif( self._linecount, max_entries=1)[0] + self.dn = dn.decode('utf-8') class MODRDNRequest(SockRequest): @@ -559,8 +589,7 @@ """ def __init__(self, msgid, dn, entry): - resp_lines = [ - ] + resp_lines = [] self._dn = dn self._entry = entry SockResponse.__init__(self, 'ENTRY', resp_lines) @@ -577,31 +606,135 @@ )) +class SuccessResponse(RESULTResponse): + """ + Convenience wrapper class for returning success(0) + """ + + def __init__(self, msgid, info=None): + RESULTResponse.__init__( + self, + msgid, + code=0, + matched=None, + info=info + ) + + +class CompareFalseResponse(RESULTResponse): + """ + Convenience wrapper class for returning compareFalse(5) + """ + + def __init__(self, msgid, info=None): + RESULTResponse.__init__( + self, + msgid, + code=5, + matched=None, + info=info + ) + + +class CompareTrueResponse(RESULTResponse): + """ + Convenience wrapper class for returning compareTrue(6) + """ + + def __init__(self, msgid, info=None): + RESULTResponse.__init__( + self, + msgid, + code=6, + matched=None, + info=info + ) + + +class InvalidAttributeSyntaxResponse(RESULTResponse): + """ + Convenience wrapper class for returning invalidAttributeSyntax(21) + """ + + def __init__(self, msgid, info=None): + RESULTResponse.__init__( + self, + msgid, + code=21, + matched=None, + info=info + ) + + +class ConstraintViolationResponse(RESULTResponse): + """ + Convenience wrapper class for returning constraintViolation(19) + """ + + def __init__(self, msgid, info=None): + RESULTResponse.__init__( + self, + msgid, + code=19, + matched=None, + info=info + ) + + +class NoSuchObjectResponse(RESULTResponse): + """ + Convenience wrapper class for returning noSuchObject(32) + """ + + def __init__(self, msgid, info=None, matched=None): + RESULTResponse.__init__( + self, + msgid, + code=32, + matched=None, + info=info + ) + + class InvalidCredentialsResponse(RESULTResponse): """ - Convenience wrapper class for returning invalidCredentials + Convenience wrapper class for returning invalidCredentials(49) """ def __init__(self, msgid, info=None): RESULTResponse.__init__( self, msgid, - code='invalidCredentials', + code=49, matched=None, info=info ) -class InternalErrorResponse(RESULTResponse): +class UnwillingToPerformResponse(RESULTResponse): """ - Convenience wrapper class for returning unwillingToPerform and - diagnostic message 'internal error' + Convenience wrapper class for returning unwillingToPerform(53) """ def __init__(self, msgid, info=None): RESULTResponse.__init__( self, msgid, - code='unwillingToPerform', + code=53, + matched=None, + info=info + ) + + +class InternalErrorResponse(UnwillingToPerformResponse): + """ + Convenience wrapper class for returning unwillingToPerform(53) and + diagnostic message 'internal error' + """ + + def __init__(self, msgid, info=None): + UnwillingToPerformResponse.__init__( + self, + msgid, info=info or 'internal error' ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slapdsock-0.6.0/slapdsock/pkginfo.py new/slapdsock-0.7.6/slapdsock/pkginfo.py --- old/slapdsock-0.6.0/slapdsock/pkginfo.py 2017-09-06 10:44:25.000000000 +0200 +++ new/slapdsock-0.7.6/slapdsock/pkginfo.py 2017-11-11 18:54:17.000000000 +0100 @@ -2,6 +2,6 @@ """ meta attributes for packaging which does not import any dependencies """ -__version__ = '0.6.0' +__version__ = '0.7.6' __author__ = u'Michael Ströder <[email protected]>' __license__ = 'Apache License, Version 2.0' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slapdsock-0.6.0/slapdsock/test.py new/slapdsock-0.7.6/slapdsock/test.py --- old/slapdsock-0.6.0/slapdsock/test.py 1970-01-01 01:00:00.000000000 +0100 +++ new/slapdsock-0.7.6/slapdsock/test.py 2017-11-09 09:13:52.000000000 +0100 @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- +""" +aedir.test - base classes for unit tests +""" + +# from Python's standard lib +import logging +import os + +# from python-ldap +import slapdtest + +__all__ = [ + 'SlapdObject', + 'SlapdSockTest', +] + + +# a template string for generating simple slapd.conf file +SLAPD_CONF_TEMPLATE = r""" +serverID %(serverid)s +moduleload back_%(database)s +include "%(schema_include)s" +loglevel %(loglevel)s +allow bind_v2 + +authz-regexp + "gidnumber=%(root_gid)s\\+uidnumber=%(root_uid)s,cn=peercred,cn=external,cn=auth" + "%(rootdn)s" + +database %(database)s +directory "%(directory)s" +suffix "%(suffix)s" +rootdn "%(rootdn)s" +rootpw "%(rootpw)s" +""" + + +class SlapdObject(slapdtest.SlapdObject): + """ + run test slapd process + """ + database = 'sock' + slapd_conf_template = SLAPD_CONF_TEMPLATE + suffix = 'dc=slapdsock,dc=stroeder,dc=com' + + +class SlapdSockTest(slapdtest.SlapdTestCase): + """ + test class which initializes an slapd with back-sock + """ + + server_class = SlapdObject + slapdsock_server_class = + slapdsock_handler_class = + init_ldif_file = None + + @classmethod + def setUpClass(cls): + cls.server = cls.server_class() + cls.server.start() + cls.server = cls.server + + @classmethod + def tearDownClass(cls): + cls.server.stop() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slapdsock-0.6.0/slapdsock.egg-info/PKG-INFO new/slapdsock-0.7.6/slapdsock.egg-info/PKG-INFO --- old/slapdsock-0.6.0/slapdsock.egg-info/PKG-INFO 2017-09-06 10:44:43.000000000 +0200 +++ new/slapdsock-0.7.6/slapdsock.egg-info/PKG-INFO 2017-11-11 18:54:29.000000000 +0100 @@ -1,11 +1,12 @@ Metadata-Version: 1.1 Name: slapdsock -Version: 0.6.0 +Version: 0.7.6 Summary: Module package for back-sock listeners for OpenLDAP Home-page: https://www.stroeder.com/slapdsock.html Author: Michael Stroeder Author-email: [email protected] License: Apache License, Version 2.0 +Description-Content-Type: UNKNOWN Description: Module package for implementing back-sock listeners for the OpenLDAP server either working as full backend or overlay. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slapdsock-0.6.0/slapdsock.egg-info/SOURCES.txt new/slapdsock-0.7.6/slapdsock.egg-info/SOURCES.txt --- old/slapdsock-0.6.0/slapdsock.egg-info/SOURCES.txt 2017-09-06 10:44:43.000000000 +0200 +++ new/slapdsock-0.7.6/slapdsock.egg-info/SOURCES.txt 2017-11-11 18:54:29.000000000 +0100 @@ -7,12 +7,15 @@ examples/noop_logger.py examples/passmod.py examples/simple_bind_demo.py +examples/test.py examples/openldap/realdb.conf examples/openldap/realdb.ldif examples/openldap/slapd.conf examples/openldap/sockdb.conf examples/openldap/start-slapd.sh examples/openldap/accesslog/.gitignore +examples/openldap/accesslog/data.mdb +examples/openldap/accesslog/lock.mdb examples/openldap/realdb/.gitignore slapdsock/.gitignore slapdsock/__init__.py @@ -23,6 +26,7 @@ slapdsock/message.py slapdsock/pkginfo.py slapdsock/service.py +slapdsock/test.py slapdsock.egg-info/PKG-INFO slapdsock.egg-info/SOURCES.txt slapdsock.egg-info/dependency_links.txt diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slapdsock-0.6.0/tests/t_message.py new/slapdsock-0.7.6/tests/t_message.py --- old/slapdsock-0.6.0/tests/t_message.py 2017-09-06 10:44:25.000000000 +0200 +++ new/slapdsock-0.7.6/tests/t_message.py 2017-11-06 23:25:07.000000000 +0100 @@ -17,7 +17,7 @@ # from python-slapdsock from slapdsock.message import ldap_str, ldap_attrs -from slapdsock.message import BINDRequest, MODIFYRequest, EXTENDEDRequest, RESULTResponse +from slapdsock.message import BINDRequest, COMPARERequest, MODIFYRequest, EXTENDEDRequest, RESULTResponse #----------------------------------------------------------------------- # Test slapdsock.message.BINDRequest @@ -87,6 +87,30 @@ """ +compare_message_simple = """COMPARE +msgid: 129 +binddn: cn=root,ou=realdb,dc=example,dc=org +peername: PATH=/tmp/slapd_sockd/examples/openldap/ldapi +ssf: 71 +connid: 1004 +suffix: ou=realdb,dc=example,dc=org +dn: [email protected],ou=Testing,dc=example,dc=org +mail: [email protected] + +""" + +compare_message_utf8 = """COMPARE +msgid: 129 +binddn: cn=root,ou=realdb,dc=example,dc=org +peername: PATH=/tmp/slapd_sockd/examples/openldap/ldapi +ssf: 71 +connid: 1004 +suffix: ou=realdb,dc=example,dc=org +dn: cn=Michael Str\xc3\xb6der,ou=Testing,dc=example,dc=org +cn:: TWljaGFlbCBTdHLDtmRlcg== + +""" + modify_message_userpassword = """MODIFY msgid: 2 binddn: cn=root,ou=realdb,dc=example,dc=org @@ -244,6 +268,36 @@ self.assertEquals(req.cred, '\x00\x01\x00\n\x01\x00\x01\x00\x01') +class TestCOMPARERequest(TestRequestMessage): + """ + Test various cases for COMPARERequest + """ + + def test_simple(self): + req = COMPARERequest(self.prepare_request_msg(compare_message_simple)) + self.assertEquals(req.reqtype, u'COMPARE') + self.assertEquals(req.msgid, 129) + self.assertEquals(req.binddn, u'cn=root,ou=realdb,dc=example,dc=org') + self.assertEquals(req.peername, u'PATH=/tmp/slapd_sockd/examples/openldap/ldapi') + self.assertEquals(req.ssf, 71) + self.assertEquals(req.connid, 1004) + self.assertEquals(req.dn, u'[email protected],ou=Testing,dc=example,dc=org') + self.assertEquals(req.atype, u'mail') + self.assertEquals(req.avalue, '[email protected]') + + def test_utf8(self): + req = COMPARERequest(self.prepare_request_msg(compare_message_utf8)) + self.assertEquals(req.reqtype, u'COMPARE') + self.assertEquals(req.msgid, 129) + self.assertEquals(req.binddn, u'cn=root,ou=realdb,dc=example,dc=org') + self.assertEquals(req.peername, u'PATH=/tmp/slapd_sockd/examples/openldap/ldapi') + self.assertEquals(req.ssf, 71) + self.assertEquals(req.connid, 1004) + self.assertEquals(req.dn, 'cn=Michael Str\xc3\xb6der,ou=Testing,dc=example,dc=org') + self.assertEquals(req.atype, u'cn') + self.assertEquals(req.avalue, 'Michael Str\xc3\xb6der') + + class TestMODIFYRequest(TestRequestMessage): """ Test various cases for MODIFYRequest
