[Zope3-checkins] SVN: Zope3/trunk/src/zope/app/authentication/ Added support for unauthenticated principals.

Jim Fulton jim at zope.com
Thu Feb 3 18:22:37 EST 2005


Log message for revision 29031:
  Added support for unauthenticated principals.
  

Changed:
  U   Zope3/trunk/src/zope/app/authentication/README.txt
  U   Zope3/trunk/src/zope/app/authentication/authentication.py
  U   Zope3/trunk/src/zope/app/authentication/interfaces.py

-=-
Modified: Zope3/trunk/src/zope/app/authentication/README.txt
===================================================================
--- Zope3/trunk/src/zope/app/authentication/README.txt	2005-02-03 23:06:30 UTC (rev 29030)
+++ Zope3/trunk/src/zope/app/authentication/README.txt	2005-02-03 23:22:37 UTC (rev 29031)
@@ -42,34 +42,32 @@
 Let's look at an example. We create a simple plugin that provides credential
 extraction:
 
-  >>> import zope.interface
+  >>> from zope import interface, component
   >>> from zope.app.authentication import interfaces
 
   >>> class MyExtractor:
   ...
-  ...     zope.interface.implements(interfaces.IExtractionPlugin)
+  ...     interface.implements(interfaces.IExtractionPlugin)
   ...
   ...     def extractCredentials(self, request):
   ...         return request.get('credentials')
 
 We need to register this as a utility. Normally, we'd do this in ZCML. For the
-example here, we'll use the `provideUtility()` function from
-`zope.app.tests.ztapi`:
+example here, we'll use the `provideUtility()`:
 
-  >>> from zope.app.tests.ztapi import provideUtility
-  >>> provideUtility(interfaces.IExtractionPlugin, MyExtractor(), name='emy')
+  >>> component.provideUtility(MyExtractor(), name='emy')
 
 Now we also create an authenticator plugin that knows about object 42:
 
   >>> class Auth42:
   ...
-  ...     zope.interface.implements(interfaces.IAuthenticationPlugin)
+  ...     interface.implements(interfaces.IAuthenticationPlugin)
   ...
   ...     def authenticateCredentials(self, credentials):
   ...         if credentials == 42:
   ...             return '42', {'domain': 42}
 
-  >>> provideUtility(interfaces.IAuthenticationPlugin, Auth42(), name='a42')
+  >>> component.provideUtility(Auth42(), name='a42')
 
 We provide a principal factory plugin:
 
@@ -81,12 +79,13 @@
   ...         self.id = id
   ...
   ...     def __repr__(self):
-  ...         return 'Principal(%r, %r)' % (self.id, self.title)
+  ...         return '%s(%r, %r)' % (self.__class__.__name__, 
+  ...                                self.id, self.title)
 
   >>> from zope.event import notify
   >>> class PrincipalFactory:
   ...
-  ...     zope.interface.implements(interfaces.IPrincipalFactoryPlugin)
+  ...     interface.implements(interfaces.IPrincipalFactoryPlugin)
   ...
   ...     def createAuthenticatedPrincipal(self, id, info, request):
   ...         principal = Principal(id)
@@ -99,8 +98,7 @@
   ...         notify(interfaces.FoundPrincipalCreated(principal, info))
   ...         return principal
 
-  >>> provideUtility(interfaces.IPrincipalFactoryPlugin, PrincipalFactory(),
-  ...                name='pf')
+  >>> component.provideUtility(PrincipalFactory(), name='pf')
 
 Finally, we create a pluggable-authentication utility instance:
 
@@ -166,13 +164,13 @@
 
   >>> class AuthInt:
   ...
-  ...     zope.interface.implements(interfaces.IAuthenticationPlugin)
+  ...     interface.implements(interfaces.IAuthenticationPlugin)
   ...
   ...     def authenticateCredentials(self, credentials):
   ...         if isinstance(credentials, int):
   ...             return str(credentials), {'int': credentials}
 
-  >>> provideUtility(interfaces.IAuthenticationPlugin, AuthInt(), name='aint')
+  >>> component.provideUtility(AuthInt(), name='aint')
 
 If we put it before the original authenticator:
 
@@ -199,14 +197,14 @@
 
   >>> class OddExtractor:
   ...
-  ...     zope.interface.implements(interfaces.IExtractionPlugin)
+  ...     interface.implements(interfaces.IExtractionPlugin)
   ...
   ...     def extractCredentials(self, request):
   ...         credentials = request.get('credentials')
   ...         if isinstance(credentials, int) and (credentials%2):
   ...             return 1
 
-  >>> provideUtility(interfaces.IExtractionPlugin, OddExtractor(), name='eodd')
+  >>> component.provideUtility(OddExtractor(), name='eodd')
   >>> auth.extractors = 'eodd', 'emy'
 
   >>> request = TestRequest(credentials=41)
@@ -226,7 +224,7 @@
 
   >>> class OddFactory:
   ...
-  ...     zope.interface.implements(interfaces.IPrincipalFactoryPlugin)
+  ...     interface.implements(interfaces.IPrincipalFactoryPlugin)
   ...
   ...     def createAuthenticatedPrincipal(self, id, info, request):
   ...         i = info.get('int')
@@ -246,8 +244,7 @@
   ...                     principal, info))
   ...         return principal
 
-  >>> provideUtility(interfaces.IPrincipalFactoryPlugin, OddFactory(),
-  ...                name='oddf')
+  >>> component.provideUtility(OddFactory(), name='oddf')
 
   >>> auth.factories = 'oddf', 'pf'
 
@@ -277,18 +274,17 @@
 
   >>> class Search42:
   ...
-  ...     zope.interface.implements(interfaces.IPrincipalSearchPlugin)
+  ...     interface.implements(interfaces.IPrincipalSearchPlugin)
   ...
   ...     def principalInfo(self, principal_id):
   ...         if principal_id == '42':
   ...             return {'domain': 42}
 
-  >>> provideUtility(interfaces.IPrincipalSearchPlugin, Search42(),
-  ...                name='s42')
+  >>> component.provideUtility(Search42(), name='s42')
 
   >>> class IntSearch:
   ...
-  ...     zope.interface.implements(interfaces.IPrincipalSearchPlugin)
+  ...     interface.implements(interfaces.IPrincipalSearchPlugin)
   ...
   ...     def principalInfo(self, principal_id):
   ...         try:
@@ -298,8 +294,7 @@
   ...         if (i >= 0 and i < 100):
   ...             return {'int': i}
 
-  >>> provideUtility(interfaces.IPrincipalSearchPlugin, IntSearch(),
-  ...                name='sint')
+  >>> component.provideUtility(IntSearch(), name='sint')
 
   >>> auth.searchers = 's42', 'sint'
 
@@ -328,7 +323,7 @@
 
   >>> class FakeAuthUtility:
   ...
-  ...     zope.interface.implements(IAuthentication)
+  ...     interface.implements(IAuthentication)
   ...
   ...     lastGetPrincipalCall = lastUnauthorizedCall = None
   ...
@@ -368,13 +363,13 @@
 
   >>> class Challenge:
   ...
-  ...     zope.interface.implements(interfaces.IChallengePlugin)
+  ...     interface.implements(interfaces.IChallengePlugin)
   ...
   ...     def challenge(self, requests, response):
   ...         response.setHeader('X-Unauthorized', 'True')
   ...         return True
 
-  >>> provideUtility(interfaces.IChallengePlugin, Challenge(), name='c')
+  >>> component.provideUtility(Challenge(), name='c')
   >>> auth.challengers = ('c', )
 
 Now if we call unauthorized:
@@ -422,7 +417,7 @@
 add challenges to a X-Challenges headers:
 
   >>> class ColorChallenge:
-  ...     zope.interface.implements(interfaces.IChallengePlugin)
+  ...     interface.implements(interfaces.IChallengePlugin)
   ...
   ...     protocol = 'bridge'
   ...
@@ -432,11 +427,11 @@
   ...                            challenge + 'favorite color? ')
   ...         return True
 
-  >>> provideUtility(interfaces.IChallengePlugin, ColorChallenge(), name='cc')
+  >>> component.provideUtility(ColorChallenge(), name='cc')
   >>> auth.challengers = 'cc, ', 'c'
 
   >>> class BirdChallenge:
-  ...     zope.interface.implements(interfaces.IChallengePlugin)
+  ...     interface.implements(interfaces.IChallengePlugin)
   ...
   ...     protocol = 'bridge'
   ...
@@ -446,7 +441,7 @@
   ...                            challenge + 'swallow air speed? ')
   ...         return True
 
-  >>> provideUtility(interfaces.IChallengePlugin, BirdChallenge(), name='bc')
+  >>> component.provideUtility(BirdChallenge(), name='bc')
   >>> auth.challengers = 'cc', 'c', 'bc'
 
 Now if we call unauthorized:
@@ -550,6 +545,43 @@
   ...  for (id, queriable) in auth.getQueriables()]
   ['Search42', 'IntSearch']
 
+Unauthenticated principals
+==========================
+
+Normally, the pluggable-authentication utility returns None when asked
+for an unauthenticated principal:
+
+  >>> auth.unauthenticatedPrincipal()
+
+However, if an IUnauthenticatedPrincipalFactoryPlugin utility is
+defined. then it will be used to create an IUnauthenticatedPrincipal:
+
+  >>> import zope.app.security.interfaces
+  >>> class UnauthenticatedPrincipal(Principal):
+  ...     interface.implements(
+  ...         zope.app.security.interfaces.IUnauthenticatedPrincipal)
+
+  >>> class UnauthenticatedPrincipalFactoryPlugin:
+  ...     interface.implements(
+  ...         interfaces.IUnauthenticatedPrincipalFactoryPlugin)
+  ...
+  ...     def createUnauthenticatedPrincipal(self):
+  ...         principal = UnauthenticatedPrincipal('u')
+  ...         notify(interfaces.UnauthenticatedPrincipalCreated(principal))
+  ...         return principal
+  
+  >>> component.provideUtility(UnauthenticatedPrincipalFactoryPlugin())
+
+  >>> clearEvents()
+  >>> prin = auth.unauthenticatedPrincipal()
+  >>> prin
+  UnauthenticatedPrincipal('u', '{}')
+
+  >>> [event] = getEvents(interfaces.IUnauthenticatedPrincipalCreated)
+  >>> event.principal is prin
+  True
+
+
 Design Notes
 ============
 

Modified: Zope3/trunk/src/zope/app/authentication/authentication.py
===================================================================
--- Zope3/trunk/src/zope/app/authentication/authentication.py	2005-02-03 23:06:30 UTC (rev 29030)
+++ Zope3/trunk/src/zope/app/authentication/authentication.py	2005-02-03 23:22:37 UTC (rev 29031)
@@ -23,7 +23,7 @@
 
 from zope.schema.interfaces import ISourceQueriables
 
-from zope.app import zapi
+from zope import component
 
 from zope.app.security.interfaces import IAuthentication
 from zope.app.utility.utility import queryNextUtility
@@ -35,6 +35,8 @@
 from zope.app.authentication.interfaces import IAuthenticationPlugin
 from zope.app.authentication.interfaces import IChallengePlugin
 from zope.app.authentication.interfaces import IPrincipalFactoryPlugin
+from zope.app.authentication.interfaces \
+     import IUnauthenticatedPrincipalFactoryPlugin
 from zope.app.authentication.interfaces import IPrincipalSearchPlugin
 from zope.app.authentication.interfaces import IPluggableAuthentication
 
@@ -49,10 +51,10 @@
         self.prefix = prefix
 
     def authenticate(self, request):
-        authenticators = [zapi.queryUtility(IAuthenticationPlugin, name)
+        authenticators = [component.queryUtility(IAuthenticationPlugin, name)
                           for name in self.authenticators]
         for extractor in self.extractors:
-            extractor = zapi.queryUtility(IExtractionPlugin, extractor)
+            extractor = component.queryUtility(IExtractionPlugin, extractor)
             if extractor is None:
                 continue
             credentials = extractor.extractCredentials(request)
@@ -72,8 +74,8 @@
     def _create(self, meth, *args):
         # We got some data, lets create a user
         for factory in self.factories:
-            factory = zapi.queryUtility(IPrincipalFactoryPlugin,
-                                        factory)
+            factory = component.queryUtility(IPrincipalFactoryPlugin,
+                                             factory)
             if factory is None:
                 continue
 
@@ -89,7 +91,7 @@
         id = id[len(self.prefix):]
 
         for searcher in self.searchers:
-            searcher = zapi.queryUtility(IPrincipalSearchPlugin, searcher)
+            searcher = component.queryUtility(IPrincipalSearchPlugin, searcher)
             if searcher is None:
                 continue
 
@@ -103,18 +105,23 @@
 
     def getQueriables(self):
         for searcher_id in self.searchers:
-            searcher = zapi.queryUtility(IPrincipalSearchPlugin, searcher_id)
+            searcher = component.queryUtility(IPrincipalSearchPlugin,
+                                              searcher_id)
             yield searcher_id, searcher
         
 
     def unauthenticatedPrincipal(self):
+        factory = component.queryUtility(
+            IUnauthenticatedPrincipalFactoryPlugin)
+        if factory is not None:
+            return factory.createUnauthenticatedPrincipal()
         return None
 
     def unauthorized(self, id, request):
         protocol = None
 
         for challenger in self.challengers:
-            challenger = zapi.queryUtility(IChallengePlugin, challenger)
+            challenger = component.queryUtility(IChallengePlugin, challenger)
             if challenger is None:
                 continue # skip non-existant challengers
 

Modified: Zope3/trunk/src/zope/app/authentication/interfaces.py
===================================================================
--- Zope3/trunk/src/zope/app/authentication/interfaces.py	2005-02-03 23:06:30 UTC (rev 29030)
+++ Zope3/trunk/src/zope/app/authentication/interfaces.py	2005-02-03 23:22:37 UTC (rev 29031)
@@ -92,6 +92,21 @@
         self.info = info
         self.request = request
 
+class IUnauthenticatedPrincipalCreated(IPrincipalCreated):
+    """An authenticated principal object has been created
+
+    This event is generated when a principal has been created by
+    authenticating a request.
+    """
+
+class UnauthenticatedPrincipalCreated:
+
+    zope.interface.implements(IUnauthenticatedPrincipalCreated)
+
+    def __init__(self, principal):
+        self.principal = principal
+        self.info = {}
+
 class IFoundPrincipalCreated(IPrincipalCreated):
     """Event indicating that a principal was created based on a search
     """
@@ -193,6 +208,14 @@
         principal is created, return None.
         """
 
+class IUnauthenticatedPrincipalFactoryPlugin(IPlugin):
+    """Create an unauthenticated principal
+    """
+
+    def createUnauthenticatedPrincipal():
+        """Create an unauthenticated principal
+        """
+ 
 class IPrincipalSearchPlugin(IPrincipalIdAwarePlugin):
     """Find principals.
 



More information about the Zope3-Checkins mailing list