From e56f61753e6b58b32f571ba9510f4e14ea666786 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Fri, 5 Jan 2018 17:57:13 +0100 Subject: [PATCH] Add workarounds for default argument types Several default arguments are not compatible with bytes mode. Default to bytes in bytes mode. See: https://github.com/python-ldap/python-ldap/issues/147 Signed-off-by: Christian Heimes --- Lib/ldap/ldapobject.py | 55 +++++++++++++++++++++++++++++++++--------- Tests/t_ldapobject.py | 4 +-- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/Lib/ldap/ldapobject.py b/Lib/ldap/ldapobject.py index f65e09a..71d298a 100644 --- a/Lib/ldap/ldapobject.py +++ b/Lib/ldap/ldapobject.py @@ -795,7 +795,12 @@ def search_ext(self,base,scope,filterstr='(objectClass=*)',attrlist=None,attrson """ if PY2: base = self._bytesify_input('base', base) - filterstr = self._bytesify_input('filterstr', filterstr) + # workaround for default argument, + # see https://github.com/python-ldap/python-ldap/issues/147 + if self.bytes_mode and filterstr == '(objectClass=*)': + filterstr = b'(objectClass=*)' + else: + filterstr = self._bytesify_input('filterstr', filterstr) if attrlist is not None: attrlist = tuple(self._bytesify_input('attrlist', a) for a in attrlist) @@ -885,7 +890,7 @@ def set_option(self,option,invalue): invalue = RequestControlTuples(invalue) return self._ldap_call(self._l.set_option,option,invalue) - def search_subschemasubentry_s(self,dn=''): + def search_subschemasubentry_s(self,dn=None): """ Returns the distinguished name of the sub schema sub entry for a part of a DIT specified by dn. @@ -895,9 +900,17 @@ def search_subschemasubentry_s(self,dn=''): Returns: None or text/bytes depending on bytes_mode. """ + if self.bytes_mode: + empty_dn = b'' + attrname = b'subschemaSubentry' + else: + empty_dn = u'' + attrname = u'subschemaSubentry' + if dn is None: + dn = empty_dn try: r = self.search_s( - dn,ldap.SCOPE_BASE,'(objectClass=*)',['subschemaSubentry'] + dn,ldap.SCOPE_BASE,'(objectClass=*)',[attrname] ) except (ldap.NO_SUCH_OBJECT,ldap.NO_SUCH_ATTRIBUTE,ldap.INSUFFICIENT_ACCESS): r = [] @@ -906,11 +919,11 @@ def search_subschemasubentry_s(self,dn=''): try: if r: e = ldap.cidict.cidict(r[0][1]) - search_subschemasubentry_dn = e.get('subschemaSubentry',[None])[0] + search_subschemasubentry_dn = e.get(attrname,[None])[0] if search_subschemasubentry_dn is None: if dn: # Try to find sub schema sub entry in root DSE - return self.search_subschemasubentry_s(dn='') + return self.search_subschemasubentry_s(dn=empty_dn) else: # If dn was already root DSE we can return here return None @@ -945,11 +958,19 @@ def read_subschemasubentry_s(self,subschemasubentry_dn,attrs=None): """ Returns the sub schema sub entry's data """ + if self.bytes_mode: + filterstr = b'(objectClass=subschema)' + if attrs is None: + attrs = [attr.encode('utf-8') for attr in SCHEMA_ATTRS] + else: + filterstr = u'(objectClass=subschema)' + if attrs is None: + attrs = SCHEMA_ATTRS try: subschemasubentry = self.read_s( subschemasubentry_dn, - filterstr='(objectClass=subschema)', - attrlist=attrs or SCHEMA_ATTRS + filterstr=filterstr, + attrlist=attrs ) except ldap.NO_SUCH_OBJECT: return None @@ -964,7 +985,7 @@ def find_unique_entry(self,base,scope=ldap.SCOPE_SUBTREE,filterstr='(objectClass base, scope, filterstr, - attrlist=attrlist or ['*'], + attrlist=attrlist, attrsonly=attrsonly, serverctrls=serverctrls, clientctrls=clientctrls, @@ -979,10 +1000,16 @@ def read_rootdse_s(self, filterstr='(objectClass=*)', attrlist=None): """ convenience wrapper around read_s() for reading rootDSE """ + if self.bytes_mode: + base = b'' + attrlist = attrlist or [b'*', b'+'] + else: + base = u'' + attrlist = attrlist or [u'*', u'+'] ldap_rootdse = self.read_s( - '', + base, filterstr=filterstr, - attrlist=attrlist or ['*', '+'], + attrlist=attrlist, ) return ldap_rootdse # read_rootdse_s() @@ -991,9 +1018,13 @@ def get_naming_contexts(self): returns all attribute values of namingContexts in rootDSE if namingContexts is not present (not readable) then empty list is returned """ + if self.bytes_mode: + name = b'namingContexts' + else: + name = u'namingContexts' return self.read_rootdse_s( - attrlist=['namingContexts'] - ).get('namingContexts', []) + attrlist=[name] + ).get(name, []) class ReconnectLDAPObject(SimpleLDAPObject): diff --git a/Tests/t_ldapobject.py b/Tests/t_ldapobject.py index fb48011..243cd86 100644 --- a/Tests/t_ldapobject.py +++ b/Tests/t_ldapobject.py @@ -162,7 +162,6 @@ def test_bytesmode_search_results_have_bytes(self): self.assertEqual(type(value), bytes) @unittest.skipUnless(PY2, "no bytes_mode under Py3") - @unittest.expectedFailure def test_bytesmode_search_defaults(self): l = self._get_bytes_ldapobject() base = 'cn=Foo1,' + self.server.suffix @@ -335,7 +334,7 @@ def test_search_subschema(self): @unittest.skipUnless(PY2, "no bytes_mode under Py3") def test_search_subschema_have_bytes(self): - l = self._get_bytes_ldapobject(explicit=False) + l = self._get_bytes_ldapobject() dn = l.search_subschemasubentry_s() self.assertIsInstance(dn, bytes) self.assertEqual(dn, b"cn=Subschema") @@ -526,7 +525,6 @@ def test_dse(self): ) @unittest.skipUnless(PY2, "no bytes_mode under Py3") - @unittest.expectedFailure def test_dse_bytes(self): l = self._get_bytes_ldapobject() dse = l.read_rootdse_s()