[Zope3-checkins] SVN: Zope3/trunk/src/zope/app/pas/ Added quiet a bit of plugins that almost make PAS work. We just need a

Stephan Richter srichter at cosmos.phy.tufts.edu
Mon Oct 11 03:18:18 EDT 2004


Log message for revision 27940:
  Added quiet a bit of plugins that almost make PAS work. We just need a 
  screen to add principals to a persistent storage now.
  
  Also refactored the ZCML quiet a bit and did some renaming.
  


Changed:
  A   Zope3/trunk/src/zope/app/pas/authenticationplugins.zcml
  A   Zope3/trunk/src/zope/app/pas/challengeplugins.zcml
  U   Zope3/trunk/src/zope/app/pas/configure.zcml
  A   Zope3/trunk/src/zope/app/pas/extractionplugins.zcml
  D   Zope3/trunk/src/zope/app/pas/httpplugin.py
  A   Zope3/trunk/src/zope/app/pas/httpplugins.py
  A   Zope3/trunk/src/zope/app/pas/principalplugins.py
  A   Zope3/trunk/src/zope/app/pas/principalplugins.zcml
  U   Zope3/trunk/src/zope/app/pas/tests.py
  A   Zope3/trunk/src/zope/app/pas/zodb.py


-=-
Added: Zope3/trunk/src/zope/app/pas/authenticationplugins.zcml
===================================================================
--- Zope3/trunk/src/zope/app/pas/authenticationplugins.zcml	2004-10-10 20:15:59 UTC (rev 27939)
+++ Zope3/trunk/src/zope/app/pas/authenticationplugins.zcml	2004-10-11 07:18:18 UTC (rev 27940)
@@ -0,0 +1,37 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    i18n_domain="zope"
+    >
+
+  <localUtility class=".zodb.PersistentPrincipalStorage">
+
+    <implements
+        interface="zope.app.annotation.interfaces.IAttributeAnnotatable" />
+
+    <require
+        permission="zope.ManageContent"
+        interface="zope.app.container.interfaces.IContainer" />
+
+    <require
+        permission="zope.ManageContent"
+        interface=".interfaces.IAuthenticationPlugin" />
+
+  </localUtility>
+
+
+  <browser:addMenuItem
+      title="PAS Authentication Plugin"
+      description="A PAS Authentication Plugin"
+      class="zope.app.pas.zodb.PersistentPrincipalStorage"
+      permission="zope.ManageContent"
+      />
+
+  <browser:tool
+      interface=".interfaces.IAuthenticationPlugin"
+      title="PAS Authentication Plugin"
+      description="PAS Authentication Plugin"
+      />
+
+
+</configure>

Added: Zope3/trunk/src/zope/app/pas/challengeplugins.zcml
===================================================================
--- Zope3/trunk/src/zope/app/pas/challengeplugins.zcml	2004-10-10 20:15:59 UTC (rev 27939)
+++ Zope3/trunk/src/zope/app/pas/challengeplugins.zcml	2004-10-11 07:18:18 UTC (rev 27940)
@@ -0,0 +1,30 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    i18n_domain="zope">
+
+  <localUtility class=".httpplugins.HTTPBasicAuthChallenger">
+
+    <implements
+        interface="zope.app.annotation.interfaces.IAttributeAnnotatable" />
+
+    <require
+        permission="zope.ManageContent"
+        interface=".interfaces.IChallengePlugin" />
+
+  </localUtility>
+  
+  <browser:tool
+      interface=".interfaces.IChallengePlugin"
+      title="PAS Challenge Plugin"
+      description="PAS Challenge Plugin"
+      />
+  
+  <browser:addMenuItem
+      title="PAS Challenge Plugin"
+      description="A PAS Challenge Plugin"
+      class="zope.app.pas.httpplugins.HTTPBasicAuthChallenger"
+      permission="zope.ManageContent"
+      />
+
+</configure>

Modified: Zope3/trunk/src/zope/app/pas/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/pas/configure.zcml	2004-10-10 20:15:59 UTC (rev 27939)
+++ Zope3/trunk/src/zope/app/pas/configure.zcml	2004-10-11 07:18:18 UTC (rev 27940)
@@ -30,12 +30,6 @@
       menu="zmi_views" title="Edit"
       permission="zope.ManageServices" />
 
-  <interface interface="zope.app.pas.interfaces.IExtractionPlugin" />
-  <interface interface="zope.app.pas.interfaces.IAuthenticationPlugin" />
-  <interface interface="zope.app.pas.interfaces.IChallengePlugin" />
-  <interface interface="zope.app.pas.interfaces.IPrincipalFactoryPlugin" />
-  <interface interface="zope.app.pas.interfaces.IPrincipalSearchPlugin" />
-
   <vocabulary
     name="ExtractionPlugins"
     factory="zope.app.utility.vocabulary.UtilityVocabulary"
@@ -71,52 +65,9 @@
     nameOnly="True"
    />
 
-  <localUtility class=".httpplugin.HTTPBasicAuthExtractor">
-
-    <implements
-        interface="zope.app.annotation.interfaces.IAttributeAnnotatable" />
-
-    <require
-        permission="zope.ManageContent"
-        interface=".interfaces.IExtractionPlugin" />
-
-  </localUtility>
-
-  <localUtility class=".httpplugin.HTTPBasicAuthChallenger">
-
-    <implements
-        interface="zope.app.annotation.interfaces.IAttributeAnnotatable" />
-
-    <require
-        permission="zope.ManageContent"
-        interface=".interfaces.IExtractionPlugin" />
-
-  </localUtility>
-
-  <browser:tool
-      interface=".interfaces.IExtractionPlugin"
-      title="PAS Extraction Plugin"
-      description="PAS Extraction Plugin"
-      />
+  <include file="extractionplugins.zcml" />
+  <include file="challengeplugins.zcml" />
+  <include file="principalplugins.zcml" />
+  <include file="authenticationplugins.zcml" />
   
-  <browser:tool
-      interface=".interfaces.IChallengePlugin"
-      title="PAS Challenge Plugin"
-      description="PAS Challenge Plugin"
-      />
-
-  <browser:addMenuItem
-      title="PAS Extraction Plugin"
-      description="A PAS Extraction Plugin"
-      class="zope.app.pas.httpplugin.HTTPBasicAuthExtractor"
-      permission="zope.ManageContent"
-      />
-  
-  <browser:addMenuItem
-      title="PAS Challenge Plugin"
-      description="A PAS Challenge Plugin"
-      class="zope.app.pas.httpplugin.HTTPBasicAuthChallenger"
-      permission="zope.ManageContent"
-      />
-  
 </configure>

Added: Zope3/trunk/src/zope/app/pas/extractionplugins.zcml
===================================================================
--- Zope3/trunk/src/zope/app/pas/extractionplugins.zcml	2004-10-10 20:15:59 UTC (rev 27939)
+++ Zope3/trunk/src/zope/app/pas/extractionplugins.zcml	2004-10-11 07:18:18 UTC (rev 27940)
@@ -0,0 +1,30 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    i18n_domain="zope">
+
+  <localUtility class=".httpplugins.HTTPBasicAuthExtractor">
+
+    <implements
+        interface="zope.app.annotation.interfaces.IAttributeAnnotatable" />
+
+    <require
+        permission="zope.ManageContent"
+        interface=".interfaces.IExtractionPlugin" />
+
+  </localUtility>
+
+  <browser:tool
+      interface=".interfaces.IExtractionPlugin"
+      title="PAS Extraction Plugin"
+      description="PAS Extraction Plugin"
+      />
+
+  <browser:addMenuItem
+      title="PAS Extraction Plugin"
+      description="A PAS Extraction Plugin"
+      class="zope.app.pas.httpplugins.HTTPBasicAuthExtractor"
+      permission="zope.ManageContent"
+      />
+
+</configure>

Deleted: Zope3/trunk/src/zope/app/pas/httpplugin.py
===================================================================
--- Zope3/trunk/src/zope/app/pas/httpplugin.py	2004-10-10 20:15:59 UTC (rev 27939)
+++ Zope3/trunk/src/zope/app/pas/httpplugin.py	2004-10-11 07:18:18 UTC (rev 27940)
@@ -1,76 +0,0 @@
-##############################################################################
-#
-# 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.
-#
-##############################################################################
-"""PAS plugins related to HTTP
-
-$Id$
-"""
-__docformat__ = "reStructuredText"
-import base64
-from persistent import Persistent
-from zope.interface import implements
-
-from zope.app.container.contained import Contained
-from interfaces import IExtractionPlugin, IChallengePlugin
-
-
-class HTTPBasicAuthExtractor(Persistent, Contained):
-    """A Basic HTTP Authentication Crendentials Extraction Plugin
-
-    First we need to create a request that contains some credentials.
-    
-    >>> from zope.publisher.browser import TestRequest
-    >>> request = TestRequest(
-    ...     environ={'HTTP_AUTHORIZATION': u'Basic bWdyOm1ncnB3'})
-
-    Now create the extraction plugin and get the credentials.
-
-    >>> extractor = HTTPBasicAuthExtractor()
-    >>> extractor.extractCredentials(request)
-    (u'mgr', u'mgrpw')
-
-    Make sure we return `None`, if no authentication header has been
-    specified.
-
-    >>> extractor.extractCredentials(TestRequest()) is None
-    True
-
-    Also, this extractor can *only* hadle basic authentication.
-
-    >>> request = TestRequest({'HTTP_AUTHORIZATION': 'foo bar'})
-    >>> extractor.extractCredentials(TestRequest()) is None
-    True
-    """
-    implements(IExtractionPlugin)
-
-    def extractCredentials(self, request):
-        if request._auth:
-            if request._auth.lower().startswith(u'basic '):
-                credentials = request._auth.split()[-1] 
-                username, password = base64.decodestring(credentials).split(':')
-                return username.decode('utf-8'), password.decode('utf-8')
-
-
-class HTTPBasicAuthChallenger(Persistent, Contained):
-    """A Basic HTTP Authentication Challenge Plugin
-
-    """
-    implements(IChallengePlugin)
-
-    realm = 'Zope 3'
-    
-    def challenge(self, requests, response):
-        response.setHeader("WWW-Authenticate", "basic realm=%s" %self.realm,
-                           True)
-        response.setStatus(401)
-        return True

Added: Zope3/trunk/src/zope/app/pas/httpplugins.py
===================================================================
--- Zope3/trunk/src/zope/app/pas/httpplugins.py	2004-10-10 20:15:59 UTC (rev 27939)
+++ Zope3/trunk/src/zope/app/pas/httpplugins.py	2004-10-11 07:18:18 UTC (rev 27940)
@@ -0,0 +1,99 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""PAS plugins related to HTTP
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import base64
+from persistent import Persistent
+from zope.interface import implements
+from zope.publisher.interfaces.http import IHTTPRequest
+
+from zope.app.container.contained import Contained
+from interfaces import IExtractionPlugin, IChallengePlugin
+
+
+class HTTPBasicAuthExtractor(Persistent, Contained):
+    """A Basic HTTP Authentication Crendentials Extraction Plugin
+
+    First we need to create a request that contains some credentials.
+    
+    >>> from zope.publisher.browser import TestRequest
+    >>> request = TestRequest(
+    ...     environ={'HTTP_AUTHORIZATION': u'Basic bWdyOm1ncnB3'})
+
+    Now create the extraction plugin and get the credentials.
+
+    >>> extractor = HTTPBasicAuthExtractor()
+    >>> extractor.extractCredentials(request)
+    {'login': u'mgr', 'password': u'mgrpw'}
+
+    Make sure we return `None`, if no authentication header has been
+    specified.
+
+    >>> extractor.extractCredentials(TestRequest()) is None
+    True
+
+    Also, this extractor can *only* hadle basic authentication.
+
+    >>> request = TestRequest({'HTTP_AUTHORIZATION': 'foo bar'})
+    >>> extractor.extractCredentials(TestRequest()) is None
+    True
+    """
+    implements(IExtractionPlugin)
+
+    def extractCredentials(self, request):
+        if request._auth:
+            if request._auth.lower().startswith(u'basic '):
+                credentials = request._auth.split()[-1] 
+                username, password = base64.decodestring(credentials).split(':')
+                return {'login': username.decode('utf-8'),
+                        'password': password.decode('utf-8')}
+
+
+class HTTPBasicAuthChallenger(Persistent, Contained):
+    """A Basic HTTP Authentication Challenge Plugin
+
+    >>> challenger = HTTPBasicAuthChallenger()
+
+    >>> from zope.publisher.browser import TestRequest
+    >>> request = TestRequest()
+    >>> response = request.response
+    >>> challenger.challenge(request, response)
+    True
+    >>> response._status
+    401
+    >>> response.getHeader('WWW-Authenticate', literal=True)
+    'basic realm=Zope3'
+
+    >>> from zope.publisher.base import TestRequest
+    >>> request = TestRequest('/')
+    >>> response = request.response
+    >>> challenger.challenge(request, response) is None
+    True
+    """
+    implements(IChallengePlugin)
+
+    realm = 'Zope3'
+
+    protocol = 'http auth'
+    
+    def challenge(self, request, response):
+        if not IHTTPRequest.providedBy(request):
+            return None
+        response.setHeader("WWW-Authenticate", "basic realm=%s" %self.realm,
+                           True)
+        response.setStatus(401)
+        return True

Added: Zope3/trunk/src/zope/app/pas/principalplugins.py
===================================================================
--- Zope3/trunk/src/zope/app/pas/principalplugins.py	2004-10-10 20:15:59 UTC (rev 27939)
+++ Zope3/trunk/src/zope/app/pas/principalplugins.py	2004-10-11 07:18:18 UTC (rev 27940)
@@ -0,0 +1,100 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Principal Factory Plugin
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+from persistent import Persistent
+
+from zope.event import notify
+from zope.interface import implements
+
+from zope.app.container.contained import Contained
+import interfaces
+
+class Principal:
+    """A simple Principal
+
+    >>> p = Principal(1)
+    >>> p
+    Principal(1)
+    >>> p.id
+    1
+
+    >>> p = Principal('foo')
+    >>> p
+    Principal('foo')
+    >>> p.id
+    'foo'
+    """
+    
+    def __init__(self, id):
+        self.id = id
+
+    def __repr__(self):
+        return 'Principal(%r)' %self.id
+
+
+class PrincipalFactory(Persistent, Contained):
+    """A simple principal factory.
+
+    First we need to register a simple subscriber that records all events.
+
+    >>> events = []
+    >>> import zope.event
+    >>> zope.event.subscribers.append(events.append)
+
+    Now we create a principal factory and try to create the principals.
+
+    >>> from zope.publisher.browser import TestRequest
+    >>> pf = PrincipalFactory()
+
+    >>> principal = pf.createAuthenticatedPrincipal(1, {}, TestRequest())
+    >>> principal.id
+    1
+    >>> event = events[0]
+    >>> isinstance(event, interfaces.AuthenticatedPrincipalCreated)
+    True
+    >>> event.principal is principal
+    True
+    >>> event.info
+    {}
+
+    >>> principal = pf.createFoundPrincipal(2, {})
+    >>> principal.id
+    2
+    >>> event = events[1]
+    >>> isinstance(event, interfaces.FoundPrincipalCreated)
+    True
+    >>> event.principal is principal
+    True
+    >>> event.info
+    {}
+    """
+    implements(interfaces.IPrincipalFactoryPlugin)           
+
+    def createAuthenticatedPrincipal(self, id, info, request):
+        """See zope.app.pas.interfaces.IPrincipalFactoryPlugin"""
+        principal = Principal(id)
+        notify(interfaces.AuthenticatedPrincipalCreated(principal,
+                                                        info, request))
+        return principal
+
+
+    def createFoundPrincipal(self, id, info):
+        """See zope.app.pas.interfaces.IPrincipalFactoryPlugin"""
+        principal = Principal(id)
+        notify(interfaces.FoundPrincipalCreated(principal, info))
+        return principal

Added: Zope3/trunk/src/zope/app/pas/principalplugins.zcml
===================================================================
--- Zope3/trunk/src/zope/app/pas/principalplugins.zcml	2004-10-10 20:15:59 UTC (rev 27939)
+++ Zope3/trunk/src/zope/app/pas/principalplugins.zcml	2004-10-11 07:18:18 UTC (rev 27940)
@@ -0,0 +1,33 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    i18n_domain="zope"
+    >
+
+  <localUtility class=".principalplugin.PrincipalFactory">
+
+    <implements
+        interface="zope.app.annotation.interfaces.IAttributeAnnotatable" />
+
+    <require
+        permission="zope.ManageContent"
+        interface=".interfaces.IPrincipalFactoryPlugin" />
+
+  </localUtility>
+
+
+  <browser:addMenuItem
+      title="PAS Principal Factory Plugin"
+      description="A PAS Principal Factory Plugin"
+      class=".principalplugin.PrincipalFactory"
+      permission="zope.ManageContent"
+      />
+
+  <browser:tool
+      interface=".interfaces.IPrincipalFactoryPlugin"
+      title="PAS Principal Factory Plugin"
+      description="PAS Principal Factory Plugin"
+      />
+
+
+</configure>

Modified: Zope3/trunk/src/zope/app/pas/tests.py
===================================================================
--- Zope3/trunk/src/zope/app/pas/tests.py	2004-10-10 20:15:59 UTC (rev 27939)
+++ Zope3/trunk/src/zope/app/pas/tests.py	2004-10-11 07:18:18 UTC (rev 27940)
@@ -52,16 +52,18 @@
 
 def test_suite():
     return unittest.TestSuite((
-        doctest.DocTestSuite('zope.app.pas.httpplugin'),
+        doctest.DocTestSuite('zope.app.pas.httpplugins'),
+        doctest.DocTestSuite('zope.app.pas.zodb'),
+        doctest.DocTestSuite('zope.app.pas.principalplugins'),
+        doctest.DocTestSuite('zope.app.pas.browserplugins',
+                             setUp=formAuthSetUp,
+                             tearDown=formAuthTearDown),
         doctest.DocFileSuite('README.txt',
                              setUp=placelesssetup.setUp,
                              tearDown=placelesssetup.tearDown,
                              globs={'provideUtility': ztapi.provideUtility,
                                     'getEvents': getEvents,
                                     }),
-        doctest.DocTestSuite('zope.app.pas.browserplugins',
-                             setUp=formAuthSetUp,
-                             tearDown=formAuthTearDown),
         ))
 
 if __name__ == '__main__':

Added: Zope3/trunk/src/zope/app/pas/zodb.py
===================================================================
--- Zope3/trunk/src/zope/app/pas/zodb.py	2004-10-10 20:15:59 UTC (rev 27939)
+++ Zope3/trunk/src/zope/app/pas/zodb.py	2004-10-11 07:18:18 UTC (rev 27940)
@@ -0,0 +1,226 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""ZODB-based Authentication Source
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+from persistent import Persistent
+from BTrees.IOBTree import IOBTree
+from BTrees.OIBTree import OIBTree
+
+from zope.interface import implements
+
+from zope.app.container.interfaces import IContainer
+from zope.app.container.contained import Contained
+
+import interfaces
+
+
+class PersistentPrincipalStorage(Persistent, Contained):
+    """A Persistent Principal Storage and Authentication plugin
+
+    Whenever the following code refers to `principal`, we mean a tuple of the
+    form (login, password). Since we try not to expose the password, password
+    is always `None` in any output.
+    """
+    implements(interfaces.IAuthenticationPlugin, IContainer)           
+
+    def __init__(self):
+        self._principal_by_id = IOBTree()
+        self._id_by_login = OIBTree()
+
+    def __setitem__(self, id, principal):
+        """ See `IContainerNamesContainer`
+
+        >>> pps = PersistentPrincipalStorage()
+        >>> pps[1] = ('foo', 'bar')
+        >>> pps._principal_by_id[1]
+        ('foo', 'bar')
+        >>> pps._id_by_login['foo']
+        1
+        """
+        self._principal_by_id[id] = principal
+        self._id_by_login[principal[0]] = id
+
+    def __delitem__(self, id):
+        """ See `IContainer`.
+
+        >>> pps = PersistentPrincipalStorage()
+        >>> pps[1] = ('foo', 'bar')
+        >>> del pps[1]
+        >>> pps[1]
+        Traceback (most recent call last):
+        ...
+        KeyError: 1
+        """
+        login = self._principal_by_id[id][0]
+        del self._principal_by_id[id]
+        del self._id_by_login[login]
+
+    def keys(self):
+        """ See `IContainer`.
+
+        >>> pps = PersistentPrincipalStorage()
+        >>> list(pps.keys())
+        []
+        >>> pps[1] = ('foo', 'bar')
+        >>> list(pps.keys())
+        [1]
+        >>> del pps[1]
+        >>> list(pps.keys())
+        []
+        """
+        return self._principal_by_id.keys()
+
+    def __iter__(self):
+        """ See `IContainer`.
+
+        >>> pps = PersistentPrincipalStorage()
+        >>> list(pps.keys())
+        []
+        >>> pps[1] = ('foo', 'bar')
+        >>> pps[2] = ('blah', 'baz')
+        >>> ids = [i for i in pps]
+        >>> ids.sort()
+        >>> ids
+        [1, 2]
+        """
+        return iter(self.keys())
+
+    def __getitem__(self, id):
+        """ See `IContainer`
+
+        >>> pps = PersistentPrincipalStorage()
+        >>> pps[1] = ('foo', 'bar')
+
+        Never expose the password!
+        
+        >>> pps[1]
+        ('foo', None)
+        """
+        try:
+            return self._principal_by_id[id][0], None
+        except TypeError:
+            raise KeyError, id
+
+    def get(self, id, default=None):
+        """ See `IContainer`
+
+        >>> pps = PersistentPrincipalStorage()
+        >>> marker = object()
+        >>> pps.get(1, default=marker) is marker
+        True
+        >>> pps[1] = ('foo', 'bar')
+
+        Never expose the password!
+        
+        >>> pps.get(1)
+        ('foo', None)
+        """
+        try:
+            return self[id]
+        except KeyError:
+            return default
+
+    def values(self):
+        """ See `IContainer`.
+
+        >>> pps = PersistentPrincipalStorage()
+        >>> pps.values()
+        []
+        >>> pps[1] = ('foo', 'bar')
+        >>> pps.values()
+        [('foo', None)]
+        """
+        return [self[id] for id in self]
+
+    def __len__(self):
+        """ See `IContainer`
+
+        >>> pps = PersistentPrincipalStorage()
+        >>> len(pps)
+        0
+        >>> pps[1] = ('foo', 'bar')
+        >>> len(pps)
+        1
+        """
+        return len(self._id_by_login)
+
+    def items(self):
+        """ See `IContainer`.
+
+        >>> pps = PersistentPrincipalStorage()
+        >>> pps.items()
+        []
+        >>> pps[1] = ('foo', 'bar')
+        >>> pps.items()
+        [(1, ('foo', None))]
+        """
+        return [(id, self[id]) for id in self]
+
+    def __contains__(self, id):
+        """ See `IContainer`.
+
+        >>> pps = PersistentPrincipalStorage()
+        >>> 1 in pps
+        False
+        >>> pps[1] = ('foo', 'bar')
+        >>> 1 in pps
+        True
+        """
+        return id in self.keys()
+
+    has_key = __contains__
+
+
+    def authenticateCredentials(self, credentials):
+        """See zope.app.pas.interfaces.IAuthenticationPlugin
+
+        Create an authentication plugin and add a principal to it.
+        
+        >>> pps = PersistentPrincipalStorage()
+        >>> pps[1] = ('foo', 'bar')
+
+        >>> pps.authenticateCredentials(1) is None
+        True
+        >>> pps.authenticateCredentials({'blah': 2}) is None
+        True
+        >>> pps.authenticateCredentials({'login': 'foo'}) is None
+        True
+        >>> pps.authenticateCredentials({'password': 'bar'}) is None
+        True
+        >>> pps.authenticateCredentials({'login': 'foo1',
+        ...                              'password': 'bar'}) is None
+        True
+        >>> pps.authenticateCredentials({'login': 'foo',
+        ...                              'password': 'bar1'}) is None
+        True
+        >>> pps.authenticateCredentials({'login': 'foo', 'password': 'bar'})
+        ('1', {'login': 'foo'})
+        """
+        if not isinstance(credentials, dict):
+            return None
+        
+        if not ('login' in credentials and 'password' in credentials):
+            return None
+
+        id = self._id_by_login.get(credentials['login'])
+        if id is None:
+            return None
+
+        if self._principal_by_id[id][1] != credentials['password']:
+            return None
+
+        return str(id), {'login': credentials['login']}



More information about the Zope3-Checkins mailing list