[Zope-CVS] SVN: ldapauth/trunk/ Added initial source code, documentation and onlinehelp text. Many thanks to Nicolas ?\195?\137vrard for the initial source code and starting this subproject

Roger Ineichen roger at projekt01.ch
Sat Jul 3 20:11:04 EDT 2004


Log message for revision 26098:
Added initial source code, documentation and onlinehelp text. Many thanks to Nicolas ?\195?\137vrard for the initial source code and starting this subproject


-=-
Added: ldapauth/trunk/INSTALLATION.txt
===================================================================
--- ldapauth/trunk/INSTALLATION.txt	2004-07-04 00:02:58 UTC (rev 26097)
+++ ldapauth/trunk/INSTALLATION.txt	2004-07-04 00:11:04 UTC (rev 26098)
@@ -0,0 +1,3 @@
+INSTALLATION
+
+  For more information see in help/ldapauth.stx


Property changes on: ldapauth/trunk/INSTALLATION.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: ldapauth/trunk/README.txt
===================================================================
--- ldapauth/trunk/README.txt	2004-07-04 00:02:58 UTC (rev 26097)
+++ ldapauth/trunk/README.txt	2004-07-04 00:11:04 UTC (rev 26098)
@@ -0,0 +1,35 @@
+README
+
+  Under development!
+  
+  Plugable LDAP authentication module
+  
+    The ldapauth package is a plugable auth module for the "plugable 
+  authentication service" which supports authentication on LDAP.
+
+  Requirements
+  
+    python-ldap
+
+      You have to install the python-ldap package. This package is 
+    available from 
+    "python-ldap.sourceforge.net":http://python-ldap.sourceforge.net/
+
+    There is a documentation for the ldap-python package available
+    as "HTML":http://python-ldap.sourceforge.net/doc/python-ldap/index.html
+    or as "PDF":http://python-ldap.sourceforge.net/doc/python-ldap.pdf
+
+    LDAP Server
+  
+      XXX more info about LDAP server? config? 
+  
+  Protocoll
+
+    XXX supported versions?
+
+  Tests
+
+    You have to install a local LDAP server for to run the tests.
+    XXX Add LDAP server configuration sample for to run the tests.
+  
+  
\ No newline at end of file


Property changes on: ldapauth/trunk/README.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: ldapauth/trunk/TODO.txt
===================================================================
--- ldapauth/trunk/TODO.txt	2004-07-04 00:02:58 UTC (rev 26097)
+++ ldapauth/trunk/TODO.txt	2004-07-04 00:11:04 UTC (rev 26098)
@@ -0,0 +1,46 @@
+TODO
+
+  What's implemented:
+
+    - IPrincipalSource's methods and ILoginPasswordPrincipalSource's
+      methods.
+    
+    - as I said earlier it will play nicely with the pluggableauth
+      service only if some class in this service are patched (namely the
+      SimplePrincipal class, and IBTreePrincipalSourceContained class).
+
+      This is quite a problem, should I re-implement a SimpleUser
+      (that's ugly) or should I change the one there is actually (but
+      then the ldapsource is viewed as a container (why not)).
+
+  What's missing :
+
+    - The method to use the source as a container (but I still don't
+      know if this is a good way to view the ldapsource).
+
+    - Adding, deleting, modifying a user
+
+    - Caching the users
+
+    - An adapter to provide the information contained in the ldap server
+
+    - SSL support (should be easy I thinka : just use ldaps instead of
+      ldap in the connection string).
+
+    - A more decent way to add the principalsource, for now you must add
+      it then edit it.
+
+    - Add LDAP server configuration sample for to run tests and
+      describe how to setup a test environment.
+
+    - Add links to availabel LDAP servers for linux and windows
+
+    - Add a documentation for to use ldapauth with ms active directory
+
+    - Check the INSTALLATION.txt if it's consitent.
+
+    - Clean up the README.txt, INSTALLATION.txt
+
+    - Add more onlinehelp text in ./help/ldapauth.stx
+
+    - correct license header?


Property changes on: ldapauth/trunk/TODO.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: ldapauth/trunk/__init__.py
===================================================================
--- ldapauth/trunk/__init__.py	2004-07-04 00:02:58 UTC (rev 26097)
+++ ldapauth/trunk/__init__.py	2004-07-04 00:11:04 UTC (rev 26098)
@@ -13,7 +13,7 @@
 ##############################################################################
 """A plugable authentication module for LDAP.
 
-$Id: $
+$Id:
 """
 
 from principalsource import LDAPPrincipalSource

Added: ldapauth/trunk/configure.zcml
===================================================================
--- ldapauth/trunk/configure.zcml	2004-07-04 00:02:58 UTC (rev 26097)
+++ ldapauth/trunk/configure.zcml	2004-07-04 00:11:04 UTC (rev 26098)
@@ -0,0 +1,41 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    xmlns:help="http://namespaces.zope.org/help"
+    i18n_domain="ldapauth"
+    >
+
+    <content class=".LDAPPrincipalSource">
+        <factory
+            id="zope.products.ldapauth.LDAPPrincipalSource"/>
+        <allow interface=".interfaces.ILDAPBasedPrincipalSource"/>
+        <require
+            permission="zope.ManageContent"
+            set_schema=".interfaces.ILDAPBasedPrincipalSource"/>
+    </content>
+
+    <browser:addMenuItem
+        title="Add LDAP Principal Source"
+        class=".LDAPPrincipalSource"
+        permission="zope.ManageServices" />
+
+    <browser:addform
+        schema=".interfaces.ILDAPBasedPrincipalSource" 
+        label="Add LDAP-based Principal Source" 
+        name="AddLDAPPrincipalSourceForm" 
+        permission="zope.ManageContent" /> 
+
+    <browser:editform 
+        schema=".interfaces.ILDAPBasedPrincipalSource" 
+        label="Edit LDAP-based Principal Source" 
+        name="edit.html"        
+        menu="zmi_views" title="Edit" 
+        permission="zope.ManageContent" /> 
+
+    <!-- add onlinehelp text -->
+    <help:register
+        id="ldapauth"
+        title="LDAP Auth"
+        doc_path="./help/ldapauth.stx" />
+
+</configure>

Added: ldapauth/trunk/help/ldapauth.stx
===================================================================
--- ldapauth/trunk/help/ldapauth.stx	2004-07-04 00:02:58 UTC (rev 26097)
+++ ldapauth/trunk/help/ldapauth.stx	2004-07-04 00:11:04 UTC (rev 26098)
@@ -0,0 +1,41 @@
+Overview
+
+  XXX what's ldapauth?
+
+Requirements
+
+  XXX add description
+
+Installation
+
+  Download the python package python-ldap from
+  <a href="http://python-ldap.sourceforge.net/download.shtml" target="_blank">
+  http://python-ldap.sourceforge.net/download.shtml</a>
+  
+  Install the downloaded package python-ldap like described in the
+  download. You can find additional information abaout the installation
+  of this package under 
+  <a href="http://python-ldap.sourceforge.net" target="_blank">http://python-ldap.sourceforge.net</a> 
+  
+  Copy this package "ldapauth" to the "src" folder of your
+  Zope installation.
+  
+  Add a file with the name "ldapauth-configure.zcml" to the
+  package-includes folder of your installation and add the following
+  content
+  
+  ::
+
+    <include package="ldapauth"/>
+
+  Make shure there is a LDAP server available
+  
+  Add a local "Authentication Service" in ++etc++site
+  
+  Add a LDAP Principal Source to the auth service
+  
+  Now it's time to make shure you havea LDAP server available 
+  XXX more description how to install or where to find a LDAP server
+  
+  Go to the added ldap authentication source and edit the configuration.
+  You can find the edit view under the tab "edit".
\ No newline at end of file


Property changes on: ldapauth/trunk/help/ldapauth.stx
___________________________________________________________________
Name: svn:eol-style
   + native

Added: ldapauth/trunk/interfaces.py
===================================================================
--- ldapauth/trunk/interfaces.py	2004-07-04 00:02:58 UTC (rev 26097)
+++ ldapauth/trunk/interfaces.py	2004-07-04 00:11:04 UTC (rev 26098)
@@ -0,0 +1,50 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""A plugable authentication module for LDAP.
+
+$Id:
+"""
+
+from zope.schema import TextLine, Int, List, Password
+from zope.app.i18n import ZopeMessageIDFactory as _
+from zope.app.pluggableauth.interfaces import IPrincipalSource
+
+class ILDAPBasedPrincipalSource(IPrincipalSource):
+    """Describe LDAP-based authentication sources."""
+    host = TextLine(
+            title = _(u'Hostname'),
+            description = _(u'LDAP Server location'),
+            default = u'localhost')
+
+    port = Int(
+            title = _(u'Port'),
+            description = _(u'LDAP Server Port'),
+            default = 389)
+
+    basedn = TextLine(
+            title = _(u'Base DN'),
+            description = _(u'Base of the distinguished name'))
+
+    login_attribute = TextLine(
+            title = _(u'Login attribut name'),
+            description = _(u'LDAP attribute used as login name'))
+
+    manager_dn = TextLine(
+            title = _(u'Manager DN'),
+            description = _(u'Manager DN used to bind to the server'))
+
+    manager_passwd = Password(
+            title = _(u'Manager password'),
+            description = _(u"Manager's password"))
+

Added: ldapauth/trunk/principalsource.py
===================================================================
--- ldapauth/trunk/principalsource.py	2004-07-04 00:02:58 UTC (rev 26097)
+++ ldapauth/trunk/principalsource.py	2004-07-04 00:11:04 UTC (rev 26098)
@@ -0,0 +1,144 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""A plugable authentication module for LDAP.
+
+$Id:
+"""
+
+import ldap
+from persistent import Persistent
+from zope.app.container.contained import Contained
+from zope.app.pluggableauth.interfaces import \
+        ILoginPasswordPrincipalSource, IContainerPrincipalSource
+from zope.app.location import locate
+from zope.app.pluggableauth import SimplePrincipal
+from zope.exceptions import NotFoundError
+from zope.interface import implements
+
+from interfaces import ILDAPBasedPrincipalSource
+
+class LDAPPrincipalSource(Contained, Persistent):
+    """A Principal source using LDAP"""
+    implements(ILoginPasswordPrincipalSource, ILDAPBasedPrincipalSource,
+            IContainerPrincipalSource)
+
+    def __init__(self, server=u'', port=389, basedn=u'',
+            login_attribute=u'',
+            manager_dn=u'', manager_passwd=u''):
+        self.host = server
+        self.port = port
+        self.basedn = basedn
+        self.login_attribute = login_attribute
+        self.manager_dn = manager_dn
+        self.manager_passwd = manager_passwd
+    
+    ### IContainer-related methods
+
+    def __delitem__(self, login):
+        pass
+
+    # XXX We should use setitem from zope.app.container.contained
+    # Would allow events and so on. This is just a test.
+    # This way of registering the principal is somehow stupid since we must
+    # use it each time a new principal is created. This is UGLY.
+    def __setitem__(self, login, obj):
+        obj.id = login
+        obj.__parent__ = self
+
+    def keys(self):
+        pass
+
+    def __iter__(self):
+        pass
+
+    def __getitem__(self):
+        pass
+
+    def get(self, key, default=None):
+        pass
+
+    def values(self):
+        pass
+
+    def __len__(self):
+        pass
+    
+    def items(self):
+        pass
+
+    def __contains__(self):
+        pass
+    
+    ### IPrincipalSource methods
+    
+    def getPrincipal(self, id):
+        uid = id.split('\t')[2]
+        l = self.__connect()
+        l.simple_bind_s(self.manager_dn, self.manager_passwd)
+        lsearch = l.search_s(self.basedn, ldap.SCOPE_ONELEVEL,
+                '(%s=%s)' % (self.login_attribute, uid))
+        if lsearch:
+            uid_dn, uid_dict = lsearch[0]
+            principal = SimplePrincipal(
+                    login = uid_dict[self.login_attribute][0],
+                    password = uid_dict['userPassword'][0])
+            self.__setitem__(principal.login, principal)
+            return principal
+        else:
+            raise NotFoundError, id
+
+    def getPrincipals(self, name):
+        if name == '' :
+            search = '(%s=*)' % self.login_attribute
+        else:
+            search = '(%s=*%s*)' % (self.login_attribute, name)
+        l = self.__connect()
+        l.simple_bind_s(self.manager_dn, self.manager_passwd)
+        lsearch = l.search_s(self.basedn, ldap.SCOPE_ONELEVEL, search)
+        
+        principals = []
+        for userinfo in lsearch:
+            uid_dn, uid_dict = userinfo
+            principal = SimplePrincipal(
+                    login = uid_dict[self.login_attribute][0],
+                    password = uid_dict['userPassword'][0])
+            self.__setitem__(principal.login, principal)
+            principals.append(principal)
+
+        return principals
+
+    def authenticate(self, uid, password):
+        if password:
+            l = self.__connect()
+            dn = '%s=%s,' % (self.login_attribute, uid) + self.basedn
+            try:
+                l.simple_bind_s(dn, password)
+                principal = SimplePrincipal(login = uid, password = password)
+                self.__setitem__(uid, principal)
+                return principal
+            except ldap.INVALID_CREDENTIALS:
+                return None
+        else:
+            return None
+
+    def __connect(self):
+        conn = getattr(self, '_v_conn', None)
+        if not conn:
+            connectstring = 'ldap://%s:%s' % (self.host, self.port)
+            connection = ldap.initialize(connectstring)
+            self._v_conn = connection
+            return connection
+        else:
+            return conn
+            

Added: ldapauth/trunk/tests/FakeLDAP.py
===================================================================
--- ldapauth/trunk/tests/FakeLDAP.py	2004-07-04 00:02:58 UTC (rev 26097)
+++ ldapauth/trunk/tests/FakeLDAP.py	2004-07-04 00:11:04 UTC (rev 26098)
@@ -0,0 +1,286 @@
+#####################################################################
+#
+# FakeLDAP      Fake LDAP interface to test LDAP functionality
+#               independently of a running LDAP server
+#
+# This software is governed by a license (ZPL v2.1).
+# (c) Jens Vagelpohl
+#
+#####################################################################
+__version__='$Revision: 1.7 $'[11:-2]
+
+import ldap, sha, base64, copy
+
+# Module-level stuff
+__version__ = '2.fake'
+
+SCOPE_BASE = getattr(ldap, 'SCOPE_BASE')
+SCOPE_ONELEVEL = getattr(ldap, 'SCOPE_ONELEVEL')
+SCOPE_SUBTREE = getattr(ldap, 'SCOPE_SUBTREE')
+
+MOD_ADD = getattr(ldap, 'MOD_ADD')
+MOD_REPLACE = getattr(ldap, 'MOD_REPLACE')
+MOD_DELETE = getattr(ldap, 'MOD_DELETE')
+
+OPT_PROTOCOL_VERSION = None
+OPT_REFERRALS = None
+VERSION2 = None
+VERSION3 = None
+
+class LDAPError(Exception): pass
+class SERVER_DOWN(Exception): pass
+class PROTOCOL_ERROR(Exception): pass
+class NO_SUCH_OBJECT(Exception): pass
+class INVALID_CREDENTIALS(Exception): pass
+class ALREADY_EXISTS(Exception): pass
+class SIZELIMIT_EXCEEDED(Exception): pass
+class PARTIAL_RESULTS(Exception): pass
+
+REFERRAL = None
+
+TREE = {}
+
+
+def initialize(conn_str):
+    """ Initialize a new connection """
+    return FakeLDAPConnection()
+
+def explode_dn(dn, *ign, **ignored):
+    """ Get a DN's elements """
+    return [x.strip() for x in dn.split(',')]
+
+def clearTree():
+    TREE.clear()
+
+def addTreeItems(dn):
+    """ Add structure directly to the tree given a DN """
+    elems = explode_dn(dn)
+    elems.reverse()
+    tree_pos = TREE
+
+    for elem in elems:
+        if not tree_pos.has_key(elem):
+            tree_pos[elem] = {}
+
+        tree_pos = tree_pos[elem]
+
+def sha_encode(paswd):
+    sha_pswd = sha.new(paswd)
+    sha_dig = sha_pswd.digest()
+    paswd_enc = base64.encodestring(sha_dig).strip()
+    return '{SHA}%s' % paswd_enc
+
+class FakeLDAPConnection:
+    
+    def __init__(self):
+        pass
+
+    def set_option(self, option, value):
+        pass
+
+    def simple_bind_s(self, binduid, bindpwd):
+        if binduid.find('Manager') != -1:
+            return 1
+
+        if bindpwd == '':
+            # Emulate LDAP mis-behavior
+            return 1
+
+        enc_bindpwd = bindpwd
+        rec = self.search_s(binduid)
+        rec_pwd = ''
+        for key, val_list in rec:
+            if key == 'userPassword':
+                rec_pwd = val_list[0]
+                break
+
+        if not rec_pwd:
+            raise INVALID_CREDENTIALS
+
+        if enc_bindpwd == rec_pwd:
+            return 1
+        else:
+            raise INVALID_CREDENTIALS
+
+
+    def search_s(self, base, scope=SCOPE_SUBTREE, query='(objectClass=*)', attrs=[]):
+        elems = explode_dn(base)
+        elems.reverse()
+        tree_pos = TREE
+
+        for elem in elems:
+            if tree_pos.has_key(elem):
+                tree_pos = tree_pos[elem]
+
+        if query == '(objectClass=*)':
+            if scope == SCOPE_BASE and tree_pos.get('dn', '') == base:
+                return (([base, tree_pos],))
+            else:
+                return tree_pos.items()
+
+        if query.find('objectClass=groupOfUniqueNames') != -1:
+            res = []
+            if query.find('uniqueMember=') == -1:
+                for key, vals in tree_pos.items():
+                    res.append(('%s,%s' % (key, base), vals))
+
+            else:
+                q_start = query.find('uniqueMember=') + 13
+                q_end = query.find(')', q_start)
+                q_val = query[q_start:q_end]
+                
+                for key, val in tree_pos.items():
+                    if ( val.has_key('uniqueMember') and 
+                         q_val in val['uniqueMember'] ):
+                        res.append(('%s,%s' % (key, base), val))
+
+            return res
+
+        elif query.find('unique') != -1:
+            res = []
+            if query.find('*') != -1:
+                for key, vals in tree_pos.items():
+                    res.append(('%s,%s' % (key, base), vals))
+            else:
+                q_start = query.lower().find('uniquemember=') + 13
+                q_end = query.find(')', q_start)
+                q_val = query[q_start:q_end]
+
+                for key, val in tree_pos.items():
+                    if ( val.has_key('uniqueMember') and
+                         q_val in val['uniqueMember'] ):
+                        res.append(('%s,%s' % (key, base), val))
+
+            return res
+ 
+
+        else:
+            res = []
+            if query.startswith('('):
+                query = query[1:]
+
+            if query.endswith(')'):
+                query = query[:-1]
+
+            if query.startswith('&'):
+               # Convoluted query, gotta take it apart
+               query = query[2:]
+               query = query[:-1]
+               query_elems = query.split(')(')
+               query = query_elems[0]
+               query_elems.remove(query)
+
+            q_key, q_val = query.split('=')
+            for key, val in tree_pos.items():
+                if val.has_key(q_key):
+                    if '*' not in q_val and q_val in val[q_key]:
+                        res.append(('%s,%s' % (key, base), val))
+                    elif '*' == q_val[0] and '*' == q_val[-1]:
+                        qval = q_val[1:-1]
+                        for value in val[q_key]:
+                            if qval in value:
+                                res.append(('%s,%s' % (key, base), val))
+                    elif '*' == q_val[0]:
+                        qval = q_val[1:]
+                        for values in val[q_key]:
+                            if value.endswith(qval):
+                                res.append(('%s,%s' % (key, base), val))
+                    elif '*' == q_val[-1]:
+                        qval = q_val[:-1]
+                        for values in val[q_key]:
+                            if value.startswith(qval):
+                                res.append(('%s,%s' % (key, base), val))
+
+            return res
+
+    def add_s(self, dn, attr_list):
+        elems = explode_dn(dn)
+        elems.reverse()
+        rdn = elems[-1]
+        base = elems[:-1]
+        tree_pos = TREE
+
+        for elem in base:
+            if tree_pos.has_key(elem):
+                tree_pos = tree_pos[elem]
+
+        if tree_pos.has_key(rdn):
+            raise ALREADY_EXISTS
+        else:
+            tree_pos[rdn] = {}
+            rec = tree_pos[rdn]
+
+            for key, val in attr_list:
+                if isinstance(val, list):
+                    rec[key] = val
+                else:
+                    rec[key] = [val]
+
+    def delete_s(self, dn):
+        elems = explode_dn(dn)
+        elems.reverse()
+        rdn = elems[-1]
+        base = elems[:-1]
+        tree_pos = TREE
+
+        for elem in base:
+            if tree_pos.has_key(elem):
+                tree_pos = tree_pos[elem]
+
+        if tree_pos.has_key(rdn):
+            del tree_pos[rdn]
+
+    def modify_s(self, dn, mod_list):
+        elems = explode_dn(dn)
+        elems.reverse()
+        rdn = elems[-1]
+        base = elems[:-1]
+        tree_pos = TREE
+
+        for elem in base:
+            if tree_pos.has_key(elem):
+                tree_pos = tree_pos[elem]
+
+        rec = copy.deepcopy(tree_pos.get(rdn))
+
+        for mod in mod_list:
+            if mod[0] == MOD_REPLACE:
+                rec[mod[1]] = mod[2]
+            elif mod[0] == MOD_ADD:
+                cur_val = rec[mod[1]]
+                cur_val.extend(mod[2])
+                rec[mod[1]] = cur_val
+            else:
+                if rec.has_key(mod[1]):
+                    cur_vals = rec[mod[1]]
+                    for removed in mod[2]:
+                        if removed in cur_vals:
+                            cur_vals.remove(removed)
+
+                    rec[mod[1]] = cur_vals
+
+        tree_pos[rdn] = rec
+
+    def modrdn_s(self, dn, new_rdn, *ign):
+        elems = explode_dn(dn)
+        elems.reverse()
+        rdn = elems[-1]
+        base = elems[:-1]
+        tree_pos = TREE
+
+        for elem in base:
+            if tree_pos.has_key(elem):
+                tree_pos = tree_pos[elem]
+
+        rec = tree_pos.get(rdn)
+        
+        del tree_pos[rdn]
+        tree_pos[new_rdn] = rec
+
+
+class ldapobject:
+    class ReconnectLDAPObject(FakeLDAPConnection):
+        def __init__(self, *ignored):
+            pass
+
+


Property changes on: ldapauth/trunk/tests/FakeLDAP.py
___________________________________________________________________
Name: svn:eol-style
   + native

Added: ldapauth/trunk/tests/__init__.py
===================================================================
--- ldapauth/trunk/tests/__init__.py	2004-07-04 00:02:58 UTC (rev 26097)
+++ ldapauth/trunk/tests/__init__.py	2004-07-04 00:11:04 UTC (rev 26098)
@@ -0,0 +1 @@
+""" duh """


Property changes on: ldapauth/trunk/tests/__init__.py
___________________________________________________________________
Name: svn:eol-style
   + native

Added: ldapauth/trunk/tests/test_ldapsource.py
===================================================================
--- ldapauth/trunk/tests/test_ldapsource.py	2004-07-04 00:02:58 UTC (rev 26097)
+++ ldapauth/trunk/tests/test_ldapsource.py	2004-07-04 00:11:04 UTC (rev 26098)
@@ -0,0 +1,75 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""A plugable authentication module for LDAP.
+
+$Id:
+"""
+
+import sys
+from unittest import TestCase, TestSuite, makeSuite, main
+
+# FakeLDAP taken from LDAPUserFolder of Jens Vagelpohl
+import FakeLDAP
+if sys.modules.has_key('_ldap'):
+    del sys.modules['_ldap']
+sys.modules['ldap'] = FakeLDAP
+
+import ldapauth
+from zope.exceptions import NotFoundError
+
+class LDAPPrincipalSourceTest(TestCase):
+    
+    def setUp(self):
+        self.source = ldapauth.LDAPPrincipalSource(
+                'localhost', 389, 'ou=people,dc=fake',
+                'uid', 'cn=Manager,dc=fake', 'root')
+
+    def test_getPrincipal(self):
+        toto = self.source.getPrincipal('\t\ttoto_l')
+        self.assertEqual(toto.password, 'toto_p')
+        self.assertEqual(toto.login, 'toto_l')
+        self.assertRaises(NotFoundError, self.source.getPrincipal, '\t\tmoo')
+
+    def test_getPrincipals(self):
+        users = self.source.getPrincipals('t')
+        self.assertEquals(len(users), 3)
+        for user in users:
+            self.assert_('t' in user.login)
+        self.assertEquals(len(self.source.getPrincipals('ta')), 1)
+
+    def test_authenticate(self):
+        self.assertEquals(self.source.authenticate('toto_l', 'toto_p').login,
+                'toto_l')
+        self.assertEquals(self.source.authenticate('toto_l', 'toto_p').password,
+                'toto_p')
+        self.assertEquals(self.source.authenticate('toto_l', 'toto'), None)
+        self.assertEquals(self.source.authenticate('toto', 'toto'), None)
+
+def test_suite():
+    return TestSuite((
+        makeSuite(LDAPPrincipalSourceTest),
+        ))
+if __name__=='__main__':
+    import ldap
+    l = ldap.initialize('ldap://localhost:389')
+    l.add_s('uid=toto_l,ou=people,dc=fake',
+            (('uid', 'toto_l'),
+             ('userPassword', 'toto_p')))
+    l.add_s('uid=tata_l,ou=people,dc=fake',
+            (('uid', 'tata_l'),
+             ('userPassword', 'tata_p')))
+    l.add_s('uid=titi_l,ou=people,dc=fake',
+            (('uid', 'titi_l'),
+             ('userPassword', 'titi_p')))
+    main(defaultTest='test_suite')



More information about the Zope-CVS mailing list