[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