[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