[Checkins] SVN: ldappas/trunk/ We've added minimal groups support.
Martijn Faassen
faassen at infrae.com
Fri Oct 27 09:02:46 EDT 2006
Log message for revision 70932:
We've added minimal groups support.
Changed:
U ldappas/trunk/CHANGES.txt
U ldappas/trunk/src/ldappas/README.txt
U ldappas/trunk/src/ldappas/authentication.py
U ldappas/trunk/src/ldappas/interfaces.py
U ldappas/trunk/src/ldappas/tests.py
-=-
Modified: ldappas/trunk/CHANGES.txt
===================================================================
--- ldappas/trunk/CHANGES.txt 2006-10-27 12:39:24 UTC (rev 70931)
+++ ldappas/trunk/CHANGES.txt 2006-10-27 13:02:45 UTC (rev 70932)
@@ -10,6 +10,13 @@
* Fixed Zope 3.3 induced deprecation warnings.
+* principalInfo will try to look up a group if it cannot find a
+ user. This is to make ldappas support groups in a minimal way. It is
+ still the responsibility of the application to add LDAP-based groups
+ to the principal (for instance by subscribing to the
+ IAuthenticatedPrincipalCreated).
+
+
Bugs fixed
----------
Modified: ldappas/trunk/src/ldappas/README.txt
===================================================================
--- ldappas/trunk/src/ldappas/README.txt 2006-10-27 12:39:24 UTC (rev 70931)
+++ ldappas/trunk/src/ldappas/README.txt 2006-10-27 13:02:45 UTC (rev 70932)
@@ -40,10 +40,14 @@
>>> auth.adapterName = 'fake_ldap_adapter'
>>> auth.searchBase = 'dc=test'
>>> auth.searchScope = 'sub'
+ >>> auth.groupsSearchBase = 'ou=groups'
+ >>> auth.groupsSearchScope = 'sub'
>>> auth.loginAttribute = 'cn'
>>> auth.principalIdPrefix = ''
>>> auth.idAttribute = 'uid'
>>> auth.titleAttribute = 'sn'
+ >>> auth.groupsAttribute = 'ou'
+ >>> auth.groupIdAttribute = 'cn'
>>> da = auth.getLDAPAdapter()
The first task is to authenticate a set of credentials. Incorrect credentials
@@ -145,10 +149,23 @@
>>> info, info.login, info.title, info.description
(PrincipalInfo('ldap.42'), u'ok', u'the question', u'the question')
+If the principal we want information for is actually a group, we will
+also get info:
+
+ >>> info = auth.principalInfo('ldap.mygroup')
+ >>> info.id
+ 'ldap.mygroup'
+
+Although the group exists, we cannot authenticate with it directly:
+
+ >>> auth.authenticateCredentials({'login': 'mygroup',
+ ... 'password': 'something'}) is None
+ True
+
In user interfaces, you commonly want to search through the available
principals for management purposes. The authentication plugin provides
an API for searching through the principals. An empty search returns
-everything.
+everything, except groups.
>>> auth.search({})
[u'ldap.1', u'ldap.2', u'ldap.42']
@@ -173,6 +190,25 @@
[u'ldap.1', u'ldap.2']
+If any of the groupsSearchBase, groupsSearchScope or groupIdAttribute
+are not set (they're not required), we can still get principalInfo:
+
+ >>> auth.groupsSearchBase = ''
+ >>> auth.idAttribute = 'uid'
+ >>> auth.searchBase = 'dc=test'
+ >>> auth.principalInfo('ldap.44') is None
+ True
+
+ >>> auth.groupsSearchBase = 'ou=groups'
+ >>> auth.groupsSearchScope = ''
+ >>> auth.principalInfo('ldap.44') is None
+ True
+
+ >>> auth.groupsSearchScope = 'sub'
+ >>> auth.groupIdAttribute = ''
+ >>> auth.principalInfo('ldap.44') is None
+ True
+
Integration with the Pluggable Authentication Utility
-----------------------------------------------------
Modified: ldappas/trunk/src/ldappas/authentication.py
===================================================================
--- ldappas/trunk/src/ldappas/authentication.py 2006-10-27 12:39:24 UTC (rev 70931)
+++ ldappas/trunk/src/ldappas/authentication.py 2006-10-27 13:02:45 UTC (rev 70932)
@@ -82,11 +82,14 @@
adapterName = ''
searchBase = ''
searchScope = ''
+ groupsSearchBase = ''
+ groupsSearchScope = ''
loginAttribute = ''
principalIdPrefix = ''
idAttribute = ''
titleAttribute = ''
-
+ groupIdAttribute = ''
+
schema = ILDAPSearchSchema
def getLDAPAdapter(self):
@@ -164,14 +167,32 @@
try:
res = conn.search(self.searchBase, self.searchScope, filter=filter)
except NoSuchObject:
- return None
+ res = []
if len(res) != 1:
# Search returned no result or too many.
- return None
+ return self._groupPrincipalInfo(conn, id, internal_id)
dn, entry = res[0]
return PrincipalInfo(id, **self.getInfoFromEntry(dn, entry))
+ def _groupPrincipalInfo(self, conn, id, internal_id):
+ """Return PrincipalInfo for a group, if it exists.
+ """
+ if (not self.groupsSearchBase or
+ not self.groupsSearchScope or
+ not self.groupIdAttribute):
+ return None
+ filter = filter_format('(%s=%s)', (self.groupIdAttribute, internal_id))
+ try:
+ res = conn.search(self.groupsSearchBase, self.groupsSearchScope,
+ filter=filter)
+ except NoSuchObject:
+ return None
+ if len(res) != 1:
+ return None
+ dn, entry = res[0]
+ return PrincipalInfo(id)
+
def getInfoFromEntry(self, dn, entry):
try:
title = entry[self.titleAttribute][0]
Modified: ldappas/trunk/src/ldappas/interfaces.py
===================================================================
--- ldappas/trunk/src/ldappas/interfaces.py 2006-10-27 12:39:24 UTC (rev 70931)
+++ ldappas/trunk/src/ldappas/interfaces.py 2006-10-27 13:02:45 UTC (rev 70932)
@@ -46,6 +46,18 @@
required=True,
)
+ groupsSearchBase = zope.schema.TextLine(
+ title=_("Group search base"),
+ description=_(u"The LDAP search base where groups are found."),
+ required=False,
+ )
+
+ groupsSearchScope = zope.schema.TextLine(
+ title=_("Group search scope"),
+ description=_(u"THe LDAP search scope used to find groups."),
+ required=False,
+ )
+
loginAttribute = zope.schema.TextLine(
title=_("Login attribute"),
description=_(u"The LDAP attribute used to find principals."),
@@ -79,4 +91,14 @@
required=True,
)
+ groupIdAttribute = zope.schema.TextLine(
+ title=_("Group Id attribute"),
+ description=_(
+ u"The LDAP attribute (on a group entry) used to determine the "
+ "group's id."),
+ constraint=re.compile("[a-zA-Z][-a-zA-Z0-9]*$").match,
+ default=u'cn',
+ required=False,
+ )
+
# searchObjectClasses
Modified: ldappas/trunk/src/ldappas/tests.py
===================================================================
--- ldappas/trunk/src/ldappas/tests.py 2006-10-27 12:39:24 UTC (rev 70931)
+++ ldappas/trunk/src/ldappas/tests.py 2006-10-27 13:02:45 UTC (rev 70932)
@@ -38,6 +38,13 @@
class FakeLDAPConnection:
def search(self, base, scope='sub', filter='(objectClass=*)', attrs=[]):
+ if not base:
+ raise ValueError("No base supplied")
+ if not scope:
+ raise ValueError("No scope supplied")
+
+ if base == 'ou=groups':
+ return self._groupSearch(filter, attrs)
dn1 = u'uid=1,dc=test'
entry1 = {'cn': [u'many'],
'uid': [u'1'],
@@ -68,7 +75,13 @@
return [(dn1, entry1), (dn2, entry2), (dn42, entry42)]
return []
-
+ def _groupSearch(self, filter, attrs):
+ if filter.startswith('(='):
+ raise ValueError("Bad filter")
+ if filter == '(cn=mygroup)':
+ return [('uid=74,ou=group', {'cn': [u'mygroup']})]
+ return []
+
def setUp(test):
root = setup.placefulSetUp(site=True)
sm = root.getSiteManager()
More information about the Checkins
mailing list