[Zope-CVS] SVN: ldappas/trunk/ Updated and cleaned the pacakge to
work with the latest PAU. Moved all
Stephan Richter
srichter at cosmos.phy.tufts.edu
Thu May 19 15:52:14 EDT 2005
Log message for revision 30424:
Updated and cleaned the pacakge to work with the latest PAU. Moved all
tests to README.txt and applied some more modern coding styles. Thanks a
lot to Florent for the great FakeLDAPAdapter code that made it very easy
to test the code! Oh yeah, I added an integration test with PAU in the
README.txt fiel as well.
Changed:
U ldappas/trunk/README.txt
U ldappas/trunk/__init__.py
U ldappas/trunk/authentication.py
U ldappas/trunk/configure.zcml
U ldappas/trunk/interfaces.py
D ldappas/trunk/tests/
A ldappas/trunk/tests.py
-=-
Modified: ldappas/trunk/README.txt
===================================================================
--- ldappas/trunk/README.txt 2005-05-19 19:45:54 UTC (rev 30423)
+++ ldappas/trunk/README.txt 2005-05-19 19:52:14 UTC (rev 30424)
@@ -1,23 +1,214 @@
-LDAP PAS Plugin
-===============
+==========================
+LDAP Authentication Plugin
+==========================
-This is a plugins for PAS to deal with LDAP. It depends on the
-`ldapadapter` module (which itself depends on `python-ldap`).
+This is a plugin for the pluggable authentication utility (located at
+``zope.app.authentication``) to deal with LDAP principal sources. It depends
+on the ``ldapadapter`` module (which itself depends on `python-ldap`).
Authentication and Search
-------------------------
-This plugin allows one to authenticate and make searches. It is
-configured with:
+This plugin allows one to authenticate and make searches. It is configured
+with:
-- LDAP adapter to use.
+- A LDAP adapter to use.
- The search base and scope.
- The attributes for principal login, id and title (which means you can
have a login different than the id used by zope to represent the
- principal), for instance the login attribute can be 'cn' while the id
- attribute can be 'uid'.
+ principal), for instance the login attribute can be `cn` while the id
+ attribute can be `uid`.
- The prefix to add to the principal id (so that each authentication
source can have a different namespace for its ids).
+
+The authentication utility is located in
+
+ >>> import ldappas.authentication
+
+As mentioned before, we need a LDAP Adatper. To avoid needing to connect to a
+real LDAP server for these tests, a fake LDAP adapter was developed and has
+already been registered under the name `fake_ldap_adapter`.
+
+Now that the LDAP adapter is regsitered, we can instanticate the LDAP
+authentication:
+
+ >>> auth = ldappas.authentication.LDAPAuthentication()
+ >>> auth.adapterName = 'fake_ldap_adapter'
+ >>> auth.searchBase = 'dc=test'
+ >>> auth.searchScope = 'sub'
+ >>> auth.loginAttribute = 'cn'
+ >>> auth.principalIdPrefix = ''
+ >>> auth.idAttribute = 'uid'
+ >>> auth.titleAttribute = 'sn'
+ >>> da = auth.getLDAPAdapter()
+
+The first task is to authenticate a set of credentials. Incorrect credentials
+types are rejected.
+
+ >>> auth.authenticateCredentials(123) is None
+ True
+ >>> auth.authenticateCredentials({'glop': 'bzz'}) is None
+ True
+
+You cannot authenticate if the search returns several results.
+
+ >>> len(da.connect().search('dc=test', 'sub', '(cn=many)')) > 1
+ True
+ >>> auth.authenticateCredentials({'login': 'many', 'password': 'p'}) is None
+ True
+
+You cannot authenticate if the search returns nothing.
+
+ >>> conn = da.connect()
+ >>> len(conn.search('dc=test', 'sub', '(cn=none)')) == 0
+ True
+ >>> auth.authenticateCredentials({'login': 'none', 'password': 'p'}) is None
+ True
+
+You cannot authenticate with the wrong password.
+
+ >>> auth.authenticateCredentials({'login': 'ok', 'password': 'hm'}) is None
+ True
+
+Authentication succeeds if you provide the correct password.
+
+ >>> principal = auth.authenticateCredentials({'login': 'ok',
+ ... 'password': '42pw'})
+ >>> principal, principal.login, principal.title, principal.description
+ (PrincipalInfo(u'42'), u'ok', u'the question', u'the question')
+
+The id returned comes from a configurable attribute, and can be prefixed so
+that it is unique.
+
+ >>> auth.principalIdPrefix = 'ldap.'
+ >>> auth.idAttribute = 'cn'
+ >>> auth.authenticateCredentials({'login': 'ok', 'password': '42pw'})
+ PrincipalInfo(u'ldap.ok')
+
+The id attribute `dn` can be specified to use the full dn as id.
+
+ >>> auth.idAttribute = 'dn'
+ >>> auth.authenticateCredentials({'login': 'ok', 'password': '42pw'})
+ PrincipalInfo(u'ldap.uid=42,dc=test')
+
+If the id attribute returns several values, the first one is used.
+
+ >>> auth.idAttribute = 'mult'
+ >>> conn.search('dc=test', 'sub', '(cn=ok)')[0][1]['mult']
+ [u'm1', u'm2']
+ >>> auth.authenticateCredentials({'login': 'ok', 'password': '42pw'})
+ PrincipalInfo(u'ldap.m1')
+
+Authentication fails if the id attribute is not present:
+
+ >>> auth.idAttribute = 'nonesuch'
+ >>> conn.search('dc=test', 'sub', '(cn=ok)')[0][1]['nonesuch']
+ Traceback (most recent call last):
+ ...
+ KeyError: 'nonesuch'
+ >>> auth.authenticateCredentials({'login': 'ok', 'password': '42pw'}) is None
+ True
+
+You cannot authenticate if the server to which the adapter connects is down.
+
+ >>> da._isDown = True
+ >>> auth.authenticateCredentials({'login': 'ok', 'password': '42pw'}) is None
+ True
+ >>> da._isDown = False
+
+You cannot authenticate if the plugin has a bad configuration.
+
+ >>> auth.searchBase = 'dc=bzzt'
+ >>> auth.authenticateCredentials({'login': 'ok', 'password': '42pw'}) is None
+ True
+
+In user interfaces, you commonly want to search through the available
+principals for managment purposes. The authentication plugin provides an API
+for searching through the principals. An empty search returns everything.
+
+ >>> auth.idAttribute = 'uid'
+ >>> auth.searchBase = 'dc=test'
+ >>> auth.search({})
+ [u'ldap.1', u'ldap.2', u'ldap.42']
+
+A search for a specific entry returns it.
+
+ >>> auth.search({'cn': 'many'})
+ [u'ldap.1', u'ldap.2']
+
+You can have multiple search criteria, they are ANDed.
+
+ >>> auth.search({'cn': 'many', 'sn': 'mr2'})
+ [u'ldap.2']
+
+Batching can be used to restrict the result range.
+
+ >>> auth.search({}, start=1)
+ [u'ldap.2', u'ldap.42']
+ >>> auth.search({}, start=1, batch_size=1)
+ [u'ldap.2']
+ >>> auth.search({}, batch_size=2)
+ [u'ldap.1', u'ldap.2']
+
+
+Integration with the Pluggable Authenitcation Utility
+-----------------------------------------------------
+
+Now that we have see how the LDAP authenication plugin behaves autonomously,
+let's have a brief look on how the plugin behaves inside the authentication
+utility. The first step is to register the LDAP authentication plugin as an
+authenticator utility:
+
+ >>> from zope.component import provideUtility
+ >>> from zope.app.authentication.interfaces import IAuthenticatorPlugin
+ >>> provideUtility(auth, provides=IAuthenticatorPlugin,
+ ... name='ldap-authenticator')
+
+We also need a credentials plugin that will extract the credentials from the
+request:
+
+ >>> import zope.interface
+ >>> from zope.app.authentication.interfaces import ICredentialsPlugin
+
+ >>> class MyCredentialsPlugin:
+ ...
+ ... zope.interface.implements(ICredentialsPlugin)
+ ...
+ ... def extractCredentials(self, request):
+ ... return request.get('credentials')
+ ...
+ ... def challenge(self, request):
+ ... pass # challenge is a no-op for this plugin
+ ...
+ ... def logout(request):
+ ... pass # logout is a no-op for this plugin
+
+ >>> provideUtility(MyCredentialsPlugin(), name='simple-creds')
+
+Now, as we have seen the authenticator is only responsible for providing
+principal information, but not to generate the principals itself. Thus we have
+to register an adapter that can create principals from principal infos:
+
+ >>> from zope.component import provideAdapter
+ >>> from zope.app.authentication import principalfolder
+ >>> provideAdapter(principalfolder.AuthenticatedPrincipalFactory)
+
+We are finally ready to create a pluggable authentication utility and register
+the two plugins with it:
+
+ >>> from zope.app import authentication
+ >>> pau = authentication.PluggableAuthentication()
+ >>> pau.credentialsPlugins = ('simple-creds', )
+ >>> pau.authenticatorPlugins = ('ldap-authenticator', )
+
+And now we can just authenticate a user using LDAP:
+
+ >>> auth.idAttribute = 'cn'
+ >>> from zope.publisher.browser import TestRequest
+ >>> request = TestRequest(credentials={'login': 'ok', 'password': '42pw'})
+ >>> principal = pau.authenticate(request)
+ >>> principal
+ Principal(u'ldap.ok')
Modified: ldappas/trunk/__init__.py
===================================================================
--- ldappas/trunk/__init__.py 2005-05-19 19:45:54 UTC (rev 30423)
+++ ldappas/trunk/__init__.py 2005-05-19 19:52:14 UTC (rev 30424)
@@ -1,17 +1 @@
-##############################################################################
-#
-# Copyright (c) 2004 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
-#
-##############################################################################
-"""LDAP PAS Plugins packages.
-
-$Id$
-"""
+# Make a package.
Modified: ldappas/trunk/authentication.py
===================================================================
--- ldappas/trunk/authentication.py 2005-05-19 19:45:54 UTC (rev 30423)
+++ ldappas/trunk/authentication.py 2005-05-19 19:52:14 UTC (rev 30424)
@@ -15,25 +15,56 @@
$Id$
"""
+import zope.schema
+import zope.interface
+from persistent import Persistent
from zope.app import zapi
-from persistent import Persistent
+from zope.app import authentication
from zope.app.container.contained import Contained
-from zope.interface import implements
-from zope.interface import Interface
-from zope.schema import TextLine
-from zope.app.pas.interfaces import IAuthenticationPlugin
-from zope.app.pas.interfaces import IQuerySchemaSearch
+from ldap.filter import filter_format
+from ldapadapter.interfaces import ServerDown
+from ldapadapter.interfaces import InvalidCredentials
+from ldapadapter.interfaces import NoSuchObject
from ldapadapter.interfaces import ILDAPAdapter
-from interfaces import ILDAPAuthentication
+from ldappas.interfaces import ILDAPAuthentication
-from ldap.filter import filter_format
-from ldapadapter.exceptions import ServerDown
-from ldapadapter.exceptions import InvalidCredentials
-from ldapadapter.exceptions import NoSuchObject
+class ILDAPSearchSchema(zope.interface.Interface):
+ """A LDAP-specific schema for searching for principals."""
+ uid = zope.schema.TextLine(
+ title=u'uid',
+ required=False)
+
+ cn = zope.schema.TextLine(
+ title=u'cn',
+ required=False)
+
+ givenName = zope.schema.TextLine(
+ title=u'givenName',
+ required=False)
+
+ sn = zope.schema.TextLine(
+ title=u'sn',
+ required=False)
+
+
+class PrincipalInfo:
+ """An implementation of IPrincipalInfo used by the principal folder."""
+ zope.interface.implements(authentication.interfaces.IPrincipalInfo)
+
+ def __init__(self, id, login='', title='', description=''):
+ self.id = id
+ self.login = login
+ self.title = title
+ self.description = description
+
+ def __repr__(self):
+ return 'PrincipalInfo(%r)' % self.id
+
+
class LDAPAuthentication(Persistent, Contained):
"""A Persistent LDAP Authentication plugin for PAS.
@@ -42,7 +73,11 @@
information, and additional authentication-specific informations.
"""
- implements(ILDAPAuthentication, IAuthenticationPlugin, IQuerySchemaSearch)
+ zope.interface.implements(
+ ILDAPAuthentication,
+ authentication.interfaces.IAuthenticatorPlugin,
+ authentication.interfaces.IQueriableAuthenticator,
+ authentication.interfaces.IQuerySchemaSearch)
adapterName = ''
searchBase = ''
@@ -52,8 +87,7 @@
idAttribute = ''
titleAttribute = ''
- def __init__(self):
- pass
+ schema = ILDAPSearchSchema
def getLDAPAdapter(self):
"""Get the LDAP adapter according to our configuration.
@@ -64,103 +98,8 @@
return da
def authenticateCredentials(self, credentials):
- r"""See zope.app.pas.interfaces.IAuthenticationPlugin.
+ """See zope.app.authentication.interfaces.IAuthenticationPlugin."""
- An LDAP Adapter has to be registered, we'll use a fake one
- (registered by the test framework).
-
- >>> auth = LDAPAuthentication()
- >>> auth.adapterName = 'fake_ldap_adapter'
- >>> auth.searchBase = 'dc=test'
- >>> auth.searchScope = 'sub'
- >>> auth.loginAttribute = 'cn'
- >>> auth.principalIdPrefix = ''
- >>> auth.idAttribute = 'uid'
- >>> auth.titleAttribute = 'sn'
- >>> da = auth.getLDAPAdapter()
- >>> authCreds = auth.authenticateCredentials
-
- Incorrect credentials types are rejected.
-
- >>> authCreds(123) is None
- True
- >>> authCreds({'glop': 'bzz'}) is None
- True
-
- You cannot authenticate if the search returns several results.
-
- >>> len(da.connect().search('dc=test', 'sub', '(cn=many)')) > 1
- True
- >>> authCreds({'login': 'many', 'password': 'p'}) is None
- True
-
- You cannot authenticate if the search returns nothing.
-
- >>> conn = da.connect()
- >>> len(conn.search('dc=test', 'sub', '(cn=none)')) == 0
- True
- >>> authCreds({'login': 'none', 'password': 'p'}) is None
- True
-
- You cannot authenticate with the wrong password.
-
- >>> authCreds({'login': 'ok', 'password': 'hm'}) is None
- True
-
- Authentication succeeds if you provide the correct password.
-
- >>> id, info = authCreds({'login': 'ok', 'password': '42pw'})
- >>> id, info['login'], info['title'], info['description']
- (u'42', u'ok', u'the question', u'the question')
-
- The id returned comes from a configurable attribute, and can be
- prefixed so that it is unique.
-
- >>> auth.principalIdPrefix = 'ldap.'
- >>> auth.idAttribute = 'cn'
- >>> authCreds({'login': 'ok', 'password': '42pw'})[0]
- u'ldap.ok'
-
- The id attribute 'dn' can be specified to use the full dn as id.
-
- >>> auth.idAttribute = 'dn'
- >>> authCreds({'login': 'ok', 'password': '42pw'})[0]
- u'ldap.uid=42,dc=test'
-
- If the id attribute returns several values, the first one is
- used.
-
- >>> auth.idAttribute = 'mult'
- >>> conn.search('dc=test', 'sub', '(cn=ok)')[0][1]['mult']
- [u'm1', u'm2']
- >>> authCreds({'login': 'ok', 'password': '42pw'})[0]
- u'ldap.m1'
-
- Authentication fails if the id attribute is not present:
-
- >>> auth.idAttribute = 'nonesuch'
- >>> conn.search('dc=test', 'sub', '(cn=ok)')[0][1]['nonesuch']
- Traceback (most recent call last):
- ...
- KeyError: 'nonesuch'
- >>> authCreds({'login': 'ok', 'password': '42pw'}) is None
- True
-
- You cannot authenticate if the server to which the adapter
- connects is down.
-
- >>> da._isDown = True
- >>> authCreds({'login': 'ok', 'password': '42pw'}) is None
- True
- >>> da._isDown = False
-
- You cannot authenticate if the plugin has a bad configuration.
-
- >>> auth.searchBase = 'dc=bzzt'
- >>> authCreds({'login': 'ok', 'password': '42pw'}) is None
- True
- """
-
if not isinstance(credentials, dict):
return None
if not ('login' in credentials and 'password' in credentials):
@@ -204,7 +143,7 @@
except (ServerDown, InvalidCredentials):
return None
- return id, self.getInfoFromEntry(dn, entry)
+ return PrincipalInfo(id, **self.getInfoFromEntry(dn, entry))
def getInfoFromEntry(self, dn, entry):
try:
@@ -216,104 +155,8 @@
'description': title,
}
- def get(self, id):
- """See zope.app.pas.interfaces.IPrincipalSearchPlugin.
-
- >>> auth = LDAPAuthentication()
- >>> auth.adapterName = 'fake_ldap_adapter'
- >>> auth.loginAttribute = 'cn'
- >>> auth.principalIdPrefix = 'ldap.'
- >>> auth.idAttribute = 'uid'
- >>> auth.titleAttribute = 'sn'
-
- If the id is not in this plugin, return nothing.
-
- >>> auth.get('42') is None
- True
-
- Otherwise return the info if we have it.
-
- >>> auth.get('ldap.123') is None
- True
- >>> info = auth.get('ldap.42')
- >>> info['login'], info['title'], info['description']
- (u'ok', u'the question', u'the question')
- """
- if not id.startswith(self.principalIdPrefix):
- return None
- id = id[len(self.principalIdPrefix):]
-
- da = self.getLDAPAdapter()
- if da is None:
- return None
- try:
- conn = da.connect()
- except ServerDown:
- return None
-
- filter = filter_format('(%s=%s)', (self.idAttribute, id))
- try:
- res = conn.search(self.searchBase, self.searchScope,
- filter=filter)
- except NoSuchObject:
- return None
-
- if len(res) != 1:
- # Search returned no result or too many.
- return None
- dn, entry = res[0]
-
- return self.getInfoFromEntry(dn, entry)
-
- class schema(Interface):
- """See of zope.app.pas.interfaces.IQuerySchemaSearch.
- """
- uid = TextLine(
- title=u'uid',
- required=False)
- cn = TextLine(
- title=u'cn',
- required=False)
- givenName = TextLine(
- title=u'givenName',
- required=False)
- sn = TextLine(
- title=u'sn',
- required=False)
-
def search(self, query, start=None, batch_size=None):
- """See zope.app.pas.interfaces.IQuerySchemaSearch.
-
- >>> auth = LDAPAuthentication()
- >>> auth.adapterName = 'fake_ldap_adapter'
- >>> auth.loginAttribute = 'cn'
- >>> auth.principalIdPrefix = 'ldap.'
- >>> auth.idAttribute = 'uid'
-
- An empty search returns everything.
-
- >>> auth.search({})
- [u'ldap.1', u'ldap.2', u'ldap.42']
-
- A search for a specific entry returns it.
-
- >>> auth.search({'cn': 'many'})
- [u'ldap.1', u'ldap.2']
-
- You can have multiple search criteria, they are ANDed.
-
- >>> auth.search({'cn': 'many', 'sn': 'mr2'})
- [u'ldap.2']
-
- Batching can be used to restrict the result range.
-
- >>> auth.search({}, start=1)
- [u'ldap.2', u'ldap.42']
- >>> auth.search({}, start=1, batch_size=1)
- [u'ldap.2']
- >>> auth.search({}, batch_size=2)
- [u'ldap.1', u'ldap.2']
- """
+ """See zope.app.authentication.interfaces.IQuerySchemaSearch."""
da = self.getLDAPAdapter()
if da is None:
return ()
Modified: ldappas/trunk/configure.zcml
===================================================================
--- ldappas/trunk/configure.zcml 2005-05-19 19:45:54 UTC (rev 30423)
+++ ldappas/trunk/configure.zcml 2005-05-19 19:52:14 UTC (rev 30424)
@@ -9,46 +9,51 @@
<implements
interface="zope.app.annotation.interfaces.IAttributeAnnotatable"
/>
-
- <implements
- interface="zope.app.pas.interfaces.ISearchableAuthenticationPlugin"
- />
-
<require
- permission="zope.ManageServices"
- interface="zope.app.pas.interfaces.IAuthenticationPlugin"
- />
-
- <require
- permission="zope.ManageServices"
+ permission="zope.ManageSite"
interface="ldappas.interfaces.ILDAPAuthentication"
set_schema="ldappas.interfaces.ILDAPAuthentication"
/>
</localUtility>
- <browser:addMenuItem
- title="PAS LDAP Authentication Plugin"
- description="A PAS LDAP Authentication Plugin"
- class=".authentication.LDAPAuthentication"
- permission="zope.ManageServices"
- view="addPASLDAPAuthenticationPlugin"
- />
-
<browser:addform
schema="ldappas.interfaces.ILDAPAuthentication"
- label="Add a PAS LDAP Authentication Plugin"
+ label="Add LDAP Authentication Plugin"
content_factory=".authentication.LDAPAuthentication"
- name="addPASLDAPAuthenticationPlugin"
- permission="zope.ManageServices"
+ name="addLDAPAuthentication.html"
+ permission="zope.ManageSite"
/>
+ <browser:addMenuItem
+ title="LDAP Authentication"
+ description="A LDAP Authentication Plugin"
+ class=".authentication.LDAPAuthentication"
+ permission="zope.ManageSite"
+ view="addLDAPAuthentication.html"
+ />
+
<browser:editform
schema="ldappas.interfaces.ILDAPAuthentication"
name="edit.html"
+ title="Edit"
+ permission="zope.ManageSite"
menu="zmi_views"
- title="Edit"
- permission="zope.ManageServices"
/>
+ <!-- Registering documentation with API doc -->
+ <configure
+ xmlns:apidoc="http://namespaces.zope.org/apidoc"
+ xmlns:zcml="http://namespaces.zope.org/zcml"
+ zcml:condition="have apidoc">
+
+ <apidoc:bookchapter
+ id="ldapauth"
+ title="LDAP Authentication"
+ doc_path="README.txt"
+ parent="security/authentication"
+ />
+
+ </configure>
+
</configure>
Modified: ldappas/trunk/interfaces.py
===================================================================
--- ldappas/trunk/interfaces.py 2005-05-19 19:45:54 UTC (rev 30423)
+++ ldappas/trunk/interfaces.py 2005-05-19 19:52:14 UTC (rev 30424)
@@ -11,50 +11,57 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""LDAP PAS Plugin interfaces
+"""LDAP Pluggable Authentication Plugin interfaces
$Id$
"""
+import re
+import zope.interface
+import zope.schema
-import re
from zope.app.i18n import ZopeMessageIDFactory as _
-from zope.interface import Interface
-from zope.schema import Choice
-from zope.schema import TextLine
-class ILDAPAuthentication(Interface):
- adapterName = Choice(
+
+class ILDAPAuthentication(zope.interface.Interface):
+ """LDAP-specifc Autentication Plugin for the Pluggable Authentication."""
+
+ adapterName = zope.schema.Choice(
title=_(u"LDAP Adapter Name"),
description=_(u"The LDAP adapter name for the connection to be used."),
vocabulary="LDAP Adapter Names",
required=True,
)
- searchBase = TextLine(
+
+ searchBase = zope.schema.TextLine(
title=_("Search base"),
description=_(u"The LDAP search base where principals are found."),
default=u'dc=example,dc=org',
required=True,
)
- searchScope = TextLine(
+
+ searchScope = zope.schema.TextLine(
title=_("Search scope"),
description=_(u"The LDAP search scope used to find principals."),
default=u'sub',
required=True,
)
- loginAttribute = TextLine(
+
+ loginAttribute = zope.schema.TextLine(
title=_("Login attribute"),
description=_(u"The LDAP attribute used to find principals."),
constraint=re.compile("[a-zA-Z][-a-zA-Z0-9]*$").match,
default=u'uid',
required=True,
)
- principalIdPrefix = TextLine(
+
+ principalIdPrefix = zope.schema.TextLine(
title=_("Principal id prefix"),
description=_(u"The prefix to add to all principal ids."),
default=u'ldap.',
required=False,
)
- idAttribute = TextLine(
+
+ idAttribute = zope.schema.TextLine(
title=_("Id attribute"),
description=_(
u"The LDAP attribute used to determine a principal's id."),
@@ -62,7 +69,8 @@
default=u'uid',
required=True,
)
- titleAttribute = TextLine(
+
+ titleAttribute = zope.schema.TextLine(
title=_("Title attribute"),
description=_(
u"The LDAP attribute used to determine a principal's title."),
@@ -70,4 +78,5 @@
default=u'cn',
required=True,
)
- #searchObjectClasses
+
+ # searchObjectClasses
Copied: ldappas/trunk/tests.py (from rev 30417, ldappas/trunk/tests/test_authentication.py)
===================================================================
--- ldappas/trunk/tests/test_authentication.py 2005-05-19 11:16:24 UTC (rev 30417)
+++ ldappas/trunk/tests.py 2005-05-19 19:52:14 UTC (rev 30424)
@@ -0,0 +1,90 @@
+##############################################################################
+#
+# Copyright (c) 2004 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.
+#
+##############################################################################
+"""LDAP PAS Plugins tests
+
+$Id$
+"""
+import unittest
+
+import zope.interface
+from zope.testing import doctest, doctestunit
+from zope.app import zapi
+from zope.app.testing import setup
+
+import ldapadapter.interfaces
+
+class FakeLDAPAdapter:
+ zope.interface.implements(ldapadapter.interfaces.ILDAPAdapter)
+ _isDown = False
+ def connect(self, dn=None, password=None):
+ if self._isDown:
+ raise ldapadapter.interfaces.ServerDown
+ if not dn and not password:
+ return FakeLDAPConnection()
+ if dn == 'uid=42,dc=test' and password == '42pw':
+ return FakeLDAPConnection()
+ raise ldapadapter.interfaces.InvalidCredentials
+
+class FakeLDAPConnection:
+ def search(self, base, scope='sub', filter='(objectClass=*)', attrs=[]):
+ dn1 = u'uid=1,dc=test'
+ entry1 = {'cn': [u'many'],
+ 'uid': [u'1'],
+ 'sn': [u'mr1'],
+ }
+ dn2 = u'uid=2,dc=test'
+ entry2 = {'cn': [u'many'],
+ 'uid': [u'2'],
+ 'sn': [u'mr2'],
+ }
+ dn42 = u'uid=42,dc=test'
+ entry42 = {'cn': [u'ok'],
+ 'uid': [u'42'],
+ 'sn': [u'the question'],
+ 'mult': [u'm1', u'm2'],
+ }
+ if base.endswith('dc=bzzt'):
+ raise ldapadapter.interfaces.NoSuchObject
+ if filter == '(cn=none)':
+ return []
+ if filter in ('(cn=many)', '(cn=*many*)'):
+ return [(dn1, entry1), (dn2, entry2)]
+ if filter == '(cn=ok)' or filter == '(uid=42)':
+ return [(dn42, entry42)]
+ if filter in ('(&(sn=*mr2*)(cn=*many*))', '(&(cn=*many*)(sn=*mr2*))'):
+ return [(dn2, entry2)]
+ if filter == '(objectClass=*)':
+ return [(dn1, entry1), (dn2, entry2), (dn42, entry42)]
+ return []
+
+
+def setUp(test):
+ root = setup.placefulSetUp(site=True)
+ sm = root.getSiteManager()
+ setup.addUtility(sm, 'fake_ldap_adapter',
+ ldapadapter.interfaces.ILDAPAdapter, FakeLDAPAdapter())
+
+def tearDown(test):
+ setup.placefulTearDown()
+
+def test_suite():
+ return unittest.TestSuite((
+ doctest.DocFileSuite('README.txt',
+ setUp=setUp, tearDown=tearDown,
+ globs={'pprint': doctestunit.pprint},
+ optionflags=doctest.NORMALIZE_WHITESPACE),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
More information about the Zope-CVS
mailing list