Skip to content

More bytesmode #152

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Doc/reference/ldap.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1068,7 +1068,10 @@ and wait for and return with the server's result, or with
or :py:meth:`search_ext_s()` (client-side search limit). If non-zero
not more than *sizelimit* results are returned by the server.

.. versionchanged:: 3.0

``filterstr=None`` is equivalent to ``filterstr='(objectClass=*)'``.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good; the only nitpick I found is to say equivalent instead of equal here.


.. py:method:: LDAPObject.start_tls_s() -> None

Expand Down
78 changes: 58 additions & 20 deletions Lib/ldap/ldapobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@ def result4(self,msgid=ldap.RES_ANY,all=1,timeout=None,add_ctrls=0,add_intermedi
resp_data = self._bytesify_results(resp_data, with_ctrls=add_ctrls)
return resp_type, resp_data, resp_msgid, decoded_resp_ctrls, resp_name, resp_value

def search_ext(self,base,scope,filterstr='(objectClass=*)',attrlist=None,attrsonly=0,serverctrls=None,clientctrls=None,timeout=-1,sizelimit=0):
def search_ext(self,base,scope,filterstr=None,attrlist=None,attrsonly=0,serverctrls=None,clientctrls=None,timeout=-1,sizelimit=0):
"""
search(base, scope [,filterstr='(objectClass=*)' [,attrlist=None [,attrsonly=0]]]) -> int
search_s(base, scope [,filterstr='(objectClass=*)' [,attrlist=None [,attrsonly=0]]])
Expand Down Expand Up @@ -793,12 +793,24 @@ def search_ext(self,base,scope,filterstr='(objectClass=*)',attrlist=None,attrson
The amount of search results retrieved can be limited with the
sizelimit parameter if non-zero.
"""

if PY2:
base = self._bytesify_input('base', base)
filterstr = self._bytesify_input('filterstr', filterstr)
if filterstr is None:
# workaround for default argument,
# see https://github.com/python-ldap/python-ldap/issues/147
if self.bytes_mode:
filterstr = b'(objectClass=*)'
else:
filterstr = u'(objectClass=*)'
else:
filterstr = self._bytesify_input('filterstr', filterstr)
if attrlist is not None:
attrlist = tuple(self._bytesify_input('attrlist', a)
for a in attrlist)
else:
if filterstr is None:
filterstr = '(objectClass=*)'
return self._ldap_call(
self._l.search_ext,
base,scope,filterstr,
Expand All @@ -808,17 +820,17 @@ def search_ext(self,base,scope,filterstr='(objectClass=*)',attrlist=None,attrson
timeout,sizelimit,
)

def search_ext_s(self,base,scope,filterstr='(objectClass=*)',attrlist=None,attrsonly=0,serverctrls=None,clientctrls=None,timeout=-1,sizelimit=0):
def search_ext_s(self,base,scope,filterstr=None,attrlist=None,attrsonly=0,serverctrls=None,clientctrls=None,timeout=-1,sizelimit=0):
msgid = self.search_ext(base,scope,filterstr,attrlist,attrsonly,serverctrls,clientctrls,timeout,sizelimit)
return self.result(msgid,all=1,timeout=timeout)[1]

def search(self,base,scope,filterstr='(objectClass=*)',attrlist=None,attrsonly=0):
def search(self,base,scope,filterstr=None,attrlist=None,attrsonly=0):
return self.search_ext(base,scope,filterstr,attrlist,attrsonly,None,None)

def search_s(self,base,scope,filterstr='(objectClass=*)',attrlist=None,attrsonly=0):
def search_s(self,base,scope,filterstr=None,attrlist=None,attrsonly=0):
return self.search_ext_s(base,scope,filterstr,attrlist,attrsonly,None,None,timeout=self.timeout)

def search_st(self,base,scope,filterstr='(objectClass=*)',attrlist=None,attrsonly=0,timeout=-1):
def search_st(self,base,scope,filterstr=None,attrlist=None,attrsonly=0,timeout=-1):
return self.search_ext_s(base,scope,filterstr,attrlist,attrsonly,None,None,timeout)

def start_tls_s(self):
Expand Down Expand Up @@ -885,7 +897,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.
Expand All @@ -895,9 +907,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,None,[attrname]
)
except (ldap.NO_SUCH_OBJECT,ldap.NO_SUCH_ATTRIBUTE,ldap.INSUFFICIENT_ACCESS):
r = []
Expand All @@ -906,11 +926,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
Expand All @@ -930,7 +950,7 @@ def read_s(self,dn,filterstr=None,attrlist=None,serverctrls=None,clientctrls=Non
r = self.search_ext_s(
dn,
ldap.SCOPE_BASE,
filterstr or '(objectClass=*)',
filterstr,
attrlist=attrlist,
serverctrls=serverctrls,
clientctrls=clientctrls,
Expand All @@ -945,26 +965,34 @@ 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
else:
return subschemasubentry

def find_unique_entry(self,base,scope=ldap.SCOPE_SUBTREE,filterstr='(objectClass=*)',attrlist=None,attrsonly=0,serverctrls=None,clientctrls=None,timeout=-1):
def find_unique_entry(self,base,scope=ldap.SCOPE_SUBTREE,filterstr=None,attrlist=None,attrsonly=0,serverctrls=None,clientctrls=None,timeout=-1):
"""
Returns a unique entry, raises exception if not unique
"""
r = self.search_ext_s(
base,
scope,
filterstr,
attrlist=attrlist or ['*'],
attrlist=attrlist,
attrsonly=attrsonly,
serverctrls=serverctrls,
clientctrls=clientctrls,
Expand All @@ -975,14 +1003,20 @@ def find_unique_entry(self,base,scope=ldap.SCOPE_SUBTREE,filterstr='(objectClass
raise NO_UNIQUE_ENTRY('No or non-unique search result for %s' % (repr(filterstr)))
return r[0]

def read_rootdse_s(self, filterstr='(objectClass=*)', attrlist=None):
def read_rootdse_s(self, filterstr=None, 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()

Expand All @@ -991,9 +1025,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):
Expand Down
16 changes: 8 additions & 8 deletions Lib/ldap/schema/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ class ObjectClass(SchemaElement):
This list of strings contains NAMEs or OIDs of object classes
this object class is derived from
"""
schema_attribute = 'objectClasses'
schema_attribute = u'objectClasses'
token_defaults = {
'NAME':(()),
'DESC':(None,),
Expand Down Expand Up @@ -225,7 +225,7 @@ class AttributeType(SchemaElement):
This list of strings contains NAMEs or OIDs of attribute types
this attribute type is derived from
"""
schema_attribute = 'attributeTypes'
schema_attribute = u'attributeTypes'
token_defaults = {
'NAME':(()),
'DESC':(None,),
Expand Down Expand Up @@ -319,7 +319,7 @@ class LDAPSyntax(SchemaElement):
Integer flag (0 or 1) indicating whether the attribute type is marked
as not human-readable (X-NOT-HUMAN-READABLE)
"""
schema_attribute = 'ldapSyntaxes'
schema_attribute = u'ldapSyntaxes'
token_defaults = {
'DESC':(None,),
'X-NOT-HUMAN-READABLE':(None,),
Expand Down Expand Up @@ -367,7 +367,7 @@ class MatchingRule(SchemaElement):
syntax
String contains OID of the LDAP syntax this matching rule is usable with
"""
schema_attribute = 'matchingRules'
schema_attribute = u'matchingRules'
token_defaults = {
'NAME':(()),
'DESC':(None,),
Expand Down Expand Up @@ -413,7 +413,7 @@ class MatchingRuleUse(SchemaElement):
This list of strings contains NAMEs or OIDs of attribute types
for which this matching rule is used
"""
schema_attribute = 'matchingRuleUse'
schema_attribute = u'matchingRuleUse'
token_defaults = {
'NAME':(()),
'DESC':(None,),
Expand Down Expand Up @@ -470,7 +470,7 @@ class DITContentRule(SchemaElement):
This list of strings contains NAMEs or OIDs of attributes which
may not be present in an entry of the object class
"""
schema_attribute = 'dITContentRules'
schema_attribute = u'dITContentRules'
token_defaults = {
'NAME':(()),
'DESC':(None,),
Expand Down Expand Up @@ -527,7 +527,7 @@ class DITStructureRule(SchemaElement):
List of strings with NAMEs or OIDs of allowed structural object classes
of superior entries in the DIT
"""
schema_attribute = 'dITStructureRules'
schema_attribute = u'dITStructureRules'

token_defaults = {
'NAME':(()),
Expand Down Expand Up @@ -591,7 +591,7 @@ class NameForm(SchemaElement):
This list of strings contains NAMEs or OIDs of additional attributes
an RDN may contain
"""
schema_attribute = 'nameForms'
schema_attribute = u'nameForms'
token_defaults = {
'NAME':(()),
'DESC':(None,),
Expand Down
Loading