twisted / ldaptor

LDAP server, client and utilities, using Twisted Python
MIT License
158 stars 54 forks source link

builtins.TypeError: startswith first arg must be str or a tuple of str, not bytes #156

Open TencentSZ opened 5 years ago

TencentSZ commented 5 years ago

I read the tutorial https://ldaptor.readthedocs.io/en/latest/quickstart.html and learned how to load LDAP entries from a static LDIF. Since I want to load contact from SQL database, I raised a question and get help from a kind response here https://github.com/twisted/ldaptor/issues/154

I tried the code below, and sent a query from Microsoft Outlook, but my program raised an error

import sys

from ldaptor.inmemory import ReadOnlyInMemoryLDAPEntry
from ldaptor.inmemory import fromLDIFFile
from ldaptor.interfaces import IConnectedLDAPEntry
from ldaptor.protocols.ldap.ldapserver import LDAPServer

from twisted.application import service
from twisted.internet.endpoints import serverFromString
from twisted.internet import reactor
from twisted.internet.protocol import ServerFactory
from twisted.python.components import registerAdapter
from twisted.python import log

class LDAPServerFactory(ServerFactory):
    protocol = LDAPServer

    def __init__(self, db_engine= None):
        self.root = None
        self.reload_tree()

    def reload_tree(self):
        """
        Building LDAP tree.
        Call this method if you need to reload data from the database.
        """
        com_tree = ReadOnlyInMemoryLDAPEntry('dc=org')
        example_tree = com_tree.addChild('dc=example', {})
        people_tree = example_tree.addChild('ou=people', {})
        sales_tree = people_tree.addChild('ou=sales', {})

        sales_tree.addChild('cn=bob', {
            'cn': 'bob',
            'gn': 'Bob',
            'mail': 'bob@example.org',
            'sn': 'Roberts'
        })

        self.root = com_tree

    def buildProtocol(self, addr):
        proto = self.protocol()
        proto.debug = self.debug
        proto.factory = self
        return proto

if __name__ == '__main__':

    log.startLogging(sys.stderr)

    registerAdapter(lambda x: x.root, LDAPServerFactory, IConnectedLDAPEntry)
    factory = LDAPServerFactory()
    factory.debug = True
    application = service.Application("ldaptor-server")
    myService = service.IServiceCollection(application)
    serverEndpointStr = "tcp:{0}".format(389)
    e = serverFromString(reactor, serverEndpointStr)
    d = e.listen(factory)
    reactor.run()

The error information is

          File "d:\code_python\LDAP\ldaptor\entryhelpers.py", line 172, in <listcomp>
            if x.lower().startswith(filter.substrings[0].value.lower())
        builtins.TypeError: startswith first arg must be str or a tuple of str, not bytes

here x is a plain string while the filter values are byte.

the-glu commented 2 years ago

Hello,

We're having the exact same issue.

We fixed with via this patch, but I'm not sure it's the correct way to do it.

--- /tmp/entryhelpers.py        2021-11-24 10:07:06.132309580 +0100
+++ entryhelpers.py     2021-11-24 10:06:47.395604502 +0100
@@ -166,6 +166,10 @@
                 return False
             possibleMatches = self[filter.type]

+            for substring in filter.substrings:
+                if isinstance(substring.value, bytes):
+                    substring.value = substring.value.decode("utf-8")
+
             substrings = filter.substrings[:]

             if substrings and isinstance(

I can create a PR if that the correct way to fix it or if pointer in the right direction :)

Thanks,