[Zope3-checkins] SVN: Zope3/trunk/src/zope/app/authentication/ Added a subscriber that puts all principals authenticated by the

Jim Fulton jim at zope.com
Mon Feb 7 16:33:49 EST 2005


Log message for revision 29077:
  Added a subscriber that puts all principals authenticated by the
  pluggable-authentication utility into the authenticated and everybody
  groups, if they are defined.
  

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/browser/ftests.py
  U   Zope3/trunk/src/zope/app/authentication/browser/groupfolder.txt
  A   Zope3/trunk/src/zope/app/authentication/browser/special-groups.txt
  U   Zope3/trunk/src/zope/app/authentication/principalplugins.zcml

-=-
Modified: Zope3/trunk/src/zope/app/authentication/README.txt
===================================================================
--- Zope3/trunk/src/zope/app/authentication/README.txt	2005-02-07 21:33:47 UTC (rev 29076)
+++ Zope3/trunk/src/zope/app/authentication/README.txt	2005-02-07 21:33:49 UTC (rev 29077)
@@ -42,34 +42,34 @@
 Let's look at an example. We create a simple plugin that provides credential
 extraction:
 
-  >>> import zope.interface
+  >>> from zope import interface
   >>> 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`:
+`zope.component`:
 
-  >>> from zope.app.tests.ztapi import provideUtility
-  >>> provideUtility(interfaces.IExtractionPlugin, MyExtractor(), name='emy')
+  >>> from zope.component import provideUtility
+  >>> 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')
+  >>> provideUtility(Auth42(), name='a42')
 
 We provide a principal factory plugin:
 
@@ -86,7 +86,7 @@
   >>> 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 +99,7 @@
   ...         notify(interfaces.FoundPrincipalCreated(principal, info))
   ...         return principal
 
-  >>> provideUtility(interfaces.IPrincipalFactoryPlugin, PrincipalFactory(),
-  ...                name='pf')
+  >>> provideUtility(PrincipalFactory(), name='pf')
 
 Finally, we create a pluggable-authentication utility instance:
 
@@ -166,13 +165,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')
+  >>> provideUtility(AuthInt(), name='aint')
 
 If we put it before the original authenticator:
 
@@ -199,14 +198,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')
+  >>> provideUtility(OddExtractor(), name='eodd')
   >>> auth.extractors = 'eodd', 'emy'
 
   >>> request = TestRequest(credentials=41)
@@ -226,7 +225,7 @@
 
   >>> class OddFactory:
   ...
-  ...     zope.interface.implements(interfaces.IPrincipalFactoryPlugin)
+  ...     interface.implements(interfaces.IPrincipalFactoryPlugin)
   ...
   ...     def createAuthenticatedPrincipal(self, id, info, request):
   ...         i = info.get('int')
@@ -246,8 +245,7 @@
   ...                     principal, info))
   ...         return principal
 
-  >>> provideUtility(interfaces.IPrincipalFactoryPlugin, OddFactory(),
-  ...                name='oddf')
+  >>> provideUtility(OddFactory(), name='oddf')
 
   >>> auth.factories = 'oddf', 'pf'
 
@@ -277,18 +275,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')
+  >>> provideUtility(Search42(), name='s42')
 
   >>> class IntSearch:
   ...
-  ...     zope.interface.implements(interfaces.IPrincipalSearchPlugin)
+  ...     interface.implements(interfaces.IPrincipalSearchPlugin)
   ...
   ...     def principalInfo(self, principal_id):
   ...         try:
@@ -298,8 +295,7 @@
   ...         if (i >= 0 and i < 100):
   ...             return {'int': i}
 
-  >>> provideUtility(interfaces.IPrincipalSearchPlugin, IntSearch(),
-  ...                name='sint')
+  >>> provideUtility(IntSearch(), name='sint')
 
   >>> auth.searchers = 's42', 'sint'
 
@@ -328,7 +324,7 @@
 
   >>> class FakeAuthUtility:
   ...
-  ...     zope.interface.implements(IAuthentication)
+  ...     interface.implements(IAuthentication)
   ...
   ...     lastGetPrincipalCall = lastUnauthorizedCall = None
   ...
@@ -368,13 +364,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')
+  >>> provideUtility(Challenge(), name='c')
   >>> auth.challengers = ('c', )
 
 Now if we call unauthorized:
@@ -422,7 +418,7 @@
 add challenges to a X-Challenges headers:
 
   >>> class ColorChallenge:
-  ...     zope.interface.implements(interfaces.IChallengePlugin)
+  ...     interface.implements(interfaces.IChallengePlugin)
   ...
   ...     protocol = 'bridge'
   ...
@@ -432,11 +428,11 @@
   ...                            challenge + 'favorite color? ')
   ...         return True
 
-  >>> provideUtility(interfaces.IChallengePlugin, ColorChallenge(), name='cc')
+  >>> provideUtility(ColorChallenge(), name='cc')
   >>> auth.challengers = 'cc, ', 'c'
 
   >>> class BirdChallenge:
-  ...     zope.interface.implements(interfaces.IChallengePlugin)
+  ...     interface.implements(interfaces.IChallengePlugin)
   ...
   ...     protocol = 'bridge'
   ...
@@ -446,7 +442,7 @@
   ...                            challenge + 'swallow air speed? ')
   ...         return True
 
-  >>> provideUtility(interfaces.IChallengePlugin, BirdChallenge(), name='bc')
+  >>> provideUtility(BirdChallenge(), name='bc')
   >>> auth.challengers = 'cc', 'c', 'bc'
 
 Now if we call unauthorized:
@@ -558,3 +554,78 @@
   `ISearchableAuthenticationPlugin` and
   `IExtractionAndChallengePlugin`.
 
+Special groups
+==============
+
+Two special groups, Authenticated, and Everyone may apply to users
+created by the pluggable-authentication utility.  There is a
+subscriber, specialGroups, that will set these groups on any non-group
+principals if IAuthenticatedGroup, or IEveryoneGroup utilities are
+provided.
+
+Lets define a group-aware principal:
+
+    >>> import zope.security.interfaces
+    >>> class GroupAwarePrincipal(Principal):
+    ...     interface.implements(zope.security.interfaces.IGroupAwarePrincipal)
+    ...     def __init__(self, id):
+    ...         Principal.__init__(self, id)
+    ...         self.groups = []
+
+If we notify the subscriber with this principal, nothing will happen
+because the groups haven't been defined:
+
+    >>> prin = GroupAwarePrincipal('x')
+    >>> event = interfaces.FoundPrincipalCreated(prin, {})
+    >>> authentication.authentication.specialGroups(event)
+    >>> prin.groups
+    []
+
+Now, if we define the Everybody group:
+
+    >>> import zope.app.security.interfaces
+    >>> class EverybodyGroup(Principal):
+    ...     interface.implements(zope.app.security.interfaces.IEveryoneGroup)
+
+    >>> everybody = EverybodyGroup('all')
+    >>> provideUtility(everybody)
+    
+Then the group will be added to the principal:
+
+    >>> authentication.authentication.specialGroups(event)
+    >>> prin.groups
+    ['all']
+
+Similarly for the authenticated group:
+
+    >>> class AuthenticatedGroup(Principal):
+    ...     interface.implements(
+    ...         zope.app.security.interfaces.IAuthenticatedGroup)
+
+    >>> authenticated = AuthenticatedGroup('auth')
+    >>> provideUtility(authenticated)
+    
+Then the group will be added to the principal:
+
+    >>> prin.groups = []
+    >>> authentication.authentication.specialGroups(event)
+    >>> prin.groups.sort()
+    >>> prin.groups
+    ['all', 'auth']
+
+These groups are only added to non-group principals:
+
+    >>> prin.groups = []
+    >>> interface.directlyProvides(prin, zope.security.interfaces.IGroup)
+    >>> authentication.authentication.specialGroups(event)
+    >>> prin.groups
+    []
+
+And they are only added to group aware principals:
+
+    >>> prin = Principal('eek')
+    >>> prin.groups = []
+    >>> event = interfaces.FoundPrincipalCreated(prin, {})
+    >>> authentication.authentication.specialGroups(event)
+    >>> prin.groups
+    []

Modified: Zope3/trunk/src/zope/app/authentication/authentication.py
===================================================================
--- Zope3/trunk/src/zope/app/authentication/authentication.py	2005-02-07 21:33:47 UTC (rev 29076)
+++ Zope3/trunk/src/zope/app/authentication/authentication.py	2005-02-07 21:33:49 UTC (rev 29077)
@@ -21,11 +21,11 @@
 import zope.schema
 from persistent import Persistent
 
+from zope.component import queryUtility
 from zope.schema.interfaces import ISourceQueriables
-
-from zope.app import zapi
-
+from zope.security.interfaces import IGroupAwarePrincipal, IGroup
 from zope.app.security.interfaces import IAuthentication
+from zope.app.security.interfaces import IAuthenticatedGroup, IEveryoneGroup
 from zope.app.utility.utility import queryNextUtility
 from zope.app.container.contained import Contained
 from zope.app.utility.interfaces import ILocalUtility
@@ -49,10 +49,10 @@
         self.prefix = prefix
 
     def authenticate(self, request):
-        authenticators = [zapi.queryUtility(IAuthenticationPlugin, name)
+        authenticators = [queryUtility(IAuthenticationPlugin, name)
                           for name in self.authenticators]
         for extractor in self.extractors:
-            extractor = zapi.queryUtility(IExtractionPlugin, extractor)
+            extractor = queryUtility(IExtractionPlugin, extractor)
             if extractor is None:
                 continue
             credentials = extractor.extractCredentials(request)
@@ -72,7 +72,7 @@
     def _create(self, meth, *args):
         # We got some data, lets create a user
         for factory in self.factories:
-            factory = zapi.queryUtility(IPrincipalFactoryPlugin,
+            factory = queryUtility(IPrincipalFactoryPlugin,
                                         factory)
             if factory is None:
                 continue
@@ -89,7 +89,7 @@
         id = id[len(self.prefix):]
 
         for searcher in self.searchers:
-            searcher = zapi.queryUtility(IPrincipalSearchPlugin, searcher)
+            searcher = queryUtility(IPrincipalSearchPlugin, searcher)
             if searcher is None:
                 continue
 
@@ -103,7 +103,7 @@
 
     def getQueriables(self):
         for searcher_id in self.searchers:
-            searcher = zapi.queryUtility(IPrincipalSearchPlugin, searcher_id)
+            searcher = queryUtility(IPrincipalSearchPlugin, searcher_id)
             yield searcher_id, searcher
         
 
@@ -114,7 +114,7 @@
         protocol = None
 
         for challenger in self.challengers:
-            challenger = zapi.queryUtility(IChallengePlugin, challenger)
+            challenger = queryUtility(IChallengePlugin, challenger)
             if challenger is None:
                 continue # skip non-existant challengers
 
@@ -150,3 +150,19 @@
                                    Persistent, Contained):
     zope.interface.implements(IPluggableAuthentication,
                               ILocation, ILocalUtility)
+
+
+def specialGroups(event):
+    principal = event.principal
+    if (IGroup.providedBy(principal)
+        or not IGroupAwarePrincipal.providedBy(principal)
+        ):
+        return
+
+    everyone = queryUtility(IEveryoneGroup)
+    if everyone is not None:
+        principal.groups.append(everyone.id)
+
+    auth = queryUtility(IAuthenticatedGroup)
+    if auth is not None:
+        principal.groups.append(auth.id)

Modified: Zope3/trunk/src/zope/app/authentication/browser/ftests.py
===================================================================
--- Zope3/trunk/src/zope/app/authentication/browser/ftests.py	2005-02-07 21:33:47 UTC (rev 29076)
+++ Zope3/trunk/src/zope/app/authentication/browser/ftests.py	2005-02-07 21:33:49 UTC (rev 29077)
@@ -24,6 +24,7 @@
         functional.FunctionalDocFileSuite('groupfolder.txt'),
         functional.FunctionalDocFileSuite(
             'group_searching_with_empty_string.txt'),
+        functional.FunctionalDocFileSuite('special-groups.txt'),
         ))
 
 if __name__ == '__main__':

Modified: Zope3/trunk/src/zope/app/authentication/browser/groupfolder.txt
===================================================================
--- Zope3/trunk/src/zope/app/authentication/browser/groupfolder.txt	2005-02-07 21:33:47 UTC (rev 29076)
+++ Zope3/trunk/src/zope/app/authentication/browser/groupfolder.txt	2005-02-07 21:33:49 UTC (rev 29077)
@@ -646,10 +646,10 @@
   >>> betty = principals.getPrincipal(u'users.3')
   >>> betty.groups.sort()
   >>> betty.groups
-  [u'groups.1', u'groups.power']
+  [u'groups.1', u'groups.power', 'zope.Authenticated', 'zope.Everybody']
 
 And we'll get Bill, and see that he is only in the power-user group:
 
   >>> bill = principals.getPrincipal(u'users.2')
   >>> bill.groups
-  [u'groups.power']
+  ['zope.Everybody', 'zope.Authenticated', u'groups.power']

Added: Zope3/trunk/src/zope/app/authentication/browser/special-groups.txt
===================================================================
--- Zope3/trunk/src/zope/app/authentication/browser/special-groups.txt	2005-02-07 21:33:47 UTC (rev 29076)
+++ Zope3/trunk/src/zope/app/authentication/browser/special-groups.txt	2005-02-07 21:33:49 UTC (rev 29077)
@@ -0,0 +1,423 @@
+Granting to unauthenticated
+===========================
+
+There are 3 special groups:
+
+- Everybody, that everybody belongs to,
+
+- Unauthenticated, that unauthenticated users belong to, and
+
+- Authenticating, that authenticated users belong to.
+
+Here's an example:
+
+First, we'll set up a pluggable authentication utility containing a
+principal folder, which we'll create first.
+
+Create the principal folder:
+
+  >>> print http(r"""
+  ... POST /++etc++site/default/+/AddPrincipalFolder.html%3D HTTP/1.1
+  ... Authorization: Basic mgr:mgrpw
+  ... Content-Type: multipart/form-data; boundary=---------------------------51955270618919134971413296540
+  ... 
+  ... -----------------------------51955270618919134971413296540
+  ... Content-Disposition: form-data; name="field.prefix"
+  ... 
+  ... users.
+  ... -----------------------------51955270618919134971413296540
+  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
+  ... 
+  ... Add
+  ... -----------------------------51955270618919134971413296540
+  ... Content-Disposition: form-data; name="add_input_name"
+  ... 
+  ... 
+  ... -----------------------------51955270618919134971413296540--
+  ... """)
+  HTTP/1.1 303 See Other
+  ...
+
+Register it:
+
+  >>> print http(r"""
+  ... POST /++etc++site/default/PrincipalFolder/addRegistration.html HTTP/1.1
+  ... Authorization: Basic mgr:mgrpw
+  ... Content-Type: multipart/form-data; boundary=---------------------------1211945862063657304996683149
+  ... 
+  ... -----------------------------1211945862063657304996683149
+  ... Content-Disposition: form-data; name="field.name"
+  ... 
+  ... users
+  ... -----------------------------1211945862063657304996683149
+  ... Content-Disposition: form-data; name="field.interface"
+  ... 
+  ... zope.app.authentication.interfaces.ISearchableAuthenticationPlugin
+  ... -----------------------------1211945862063657304996683149
+  ... Content-Disposition: form-data; name="field.interface-empty-marker"
+  ... 
+  ... 1
+  ... -----------------------------1211945862063657304996683149
+  ... Content-Disposition: form-data; name="field.permission"
+  ... 
+  ... 
+  ... -----------------------------1211945862063657304996683149
+  ... Content-Disposition: form-data; name="field.permission-empty-marker"
+  ... 
+  ... 1
+  ... -----------------------------1211945862063657304996683149
+  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
+  ... 
+  ... Add
+  ... -----------------------------1211945862063657304996683149--
+  ... """)
+  HTTP/1.1 303 See Other
+  ...
+
+Add a principal to it:
+
+  >>> print http(r"""
+  ... POST /++etc++site/default/PrincipalFolder/+/AddPrincipalInformation.html%3D HTTP/1.1
+  ... Authorization: Basic mgr:mgrpw
+  ... Content-Type: multipart/form-data; boundary=---------------------------10033016405103631412002637985
+  ... 
+  ... -----------------------------10033016405103631412002637985
+  ... Content-Disposition: form-data; name="field.login"
+  ... 
+  ... bob
+  ... -----------------------------10033016405103631412002637985
+  ... Content-Disposition: form-data; name="field.password"
+  ... 
+  ... 123
+  ... -----------------------------10033016405103631412002637985
+  ... Content-Disposition: form-data; name="field.title"
+  ... 
+  ... Bob
+  ... -----------------------------10033016405103631412002637985
+  ... Content-Disposition: form-data; name="field.description"
+  ... 
+  ... 
+  ... -----------------------------10033016405103631412002637985
+  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
+  ... 
+  ... Add
+  ... -----------------------------10033016405103631412002637985
+  ... Content-Disposition: form-data; name="add_input_name"
+  ... 
+  ... 
+  ... -----------------------------10033016405103631412002637985--
+  ... """)
+  HTTP/1.1 303 See Other
+  ...
+
+Create a pluggable-authentication utility:
+
+  >>> print http(r"""
+  ... POST /++etc++site/default/@@contents.html HTTP/1.1
+  ... Authorization: Basic mgr:mgrpw
+  ... Content-Type: application/x-www-form-urlencoded
+  ... 
+  ... type_name=BrowserAdd__zope.app.authentication.authentication.LocalPluggableAuthentication&new_value=""")
+  HTTP/1.1 303 See Other
+  ...
+
+and register it:
+
+  >>> print http(r"""
+  ... POST /++etc++site/default/LocalPluggableAuthentication/addRegistration.html HTTP/1.1
+  ... Authorization: Basic mgr:mgrpw
+  ... Content-Type: multipart/form-data; boundary=---------------------------2567744622114531019698320091
+  ... Referer: http://localhost:8081/++etc++site/default/LocalPluggableAuthentication/addRegistration.html
+  ... 
+  ... -----------------------------2567744622114531019698320091
+  ... Content-Disposition: form-data; name="field.name"
+  ... 
+  ... 
+  ... -----------------------------2567744622114531019698320091
+  ... Content-Disposition: form-data; name="field.interface"
+  ... 
+  ... zope.app.security.interfaces.IAuthentication
+  ... -----------------------------2567744622114531019698320091
+  ... Content-Disposition: form-data; name="field.interface-empty-marker"
+  ... 
+  ... 1
+  ... -----------------------------2567744622114531019698320091
+  ... Content-Disposition: form-data; name="field.permission"
+  ... 
+  ... 
+  ... -----------------------------2567744622114531019698320091
+  ... Content-Disposition: form-data; name="field.permission-empty-marker"
+  ... 
+  ... 1
+  ... -----------------------------2567744622114531019698320091
+  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
+  ... 
+  ... Add
+  ... -----------------------------2567744622114531019698320091--
+  ... """)
+  HTTP/1.1 303 See Other
+  ...
+
+and configure it:
+
+  >>> print http(r"""
+  ... POST /++etc++site/default/LocalPluggableAuthentication/@@edit.html HTTP/1.1
+  ... Authorization: Basic mgr:mgrpw
+  ... Content-Type: multipart/form-data; boundary=---------------------------12424310211503201098946683515
+  ... 
+  ... -----------------------------12424310211503201098946683515
+  ... Content-Disposition: form-data; name="field.extractors.to"
+  ... 
+  ... HTTP Basic
+  ... -----------------------------12424310211503201098946683515
+  ... Content-Disposition: form-data; name="field.extractors-empty-marker"
+  ... 
+  ... 
+  ... -----------------------------12424310211503201098946683515
+  ... Content-Disposition: form-data; name="field.authenticators.to"
+  ... 
+  ... users
+  ... -----------------------------12424310211503201098946683515
+  ... Content-Disposition: form-data; name="field.authenticators-empty-marker"
+  ... 
+  ... 
+  ... -----------------------------12424310211503201098946683515
+  ... Content-Disposition: form-data; name="field.challengers.to"
+  ... 
+  ... No Challenge if Authenticated
+  ... -----------------------------12424310211503201098946683515
+  ... Content-Disposition: form-data; name="field.challengers.to"
+  ... 
+  ... Zope Realm HTTP Basic
+  ... -----------------------------12424310211503201098946683515
+  ... Content-Disposition: form-data; name="field.challengers-empty-marker"
+  ... 
+  ... 
+  ... -----------------------------12424310211503201098946683515
+  ... Content-Disposition: form-data; name="field.factories.to"
+  ... 
+  ... Default
+  ... -----------------------------12424310211503201098946683515
+  ... Content-Disposition: form-data; name="field.factories-empty-marker"
+  ... 
+  ... 
+  ... -----------------------------12424310211503201098946683515
+  ... Content-Disposition: form-data; name="field.searchers.to"
+  ... 
+  ... users
+  ... -----------------------------12424310211503201098946683515
+  ... Content-Disposition: form-data; name="field.searchers-empty-marker"
+  ... 
+  ... 
+  ... -----------------------------12424310211503201098946683515
+  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
+  ... 
+  ... Change
+  ... -----------------------------12424310211503201098946683515
+  ... Content-Disposition: form-data; name="field.extractors"
+  ... 
+  ... HTTP Basic
+  ... -----------------------------12424310211503201098946683515
+  ... Content-Disposition: form-data; name="field.authenticators"
+  ... 
+  ... users
+  ... -----------------------------12424310211503201098946683515
+  ... Content-Disposition: form-data; name="field.challengers"
+  ... 
+  ... No Challenge if Authenticated
+  ... -----------------------------12424310211503201098946683515
+  ... Content-Disposition: form-data; name="field.challengers"
+  ... 
+  ... Zope Realm HTTP Basic
+  ... -----------------------------12424310211503201098946683515
+  ... Content-Disposition: form-data; name="field.factories"
+  ... 
+  ... Default
+  ... -----------------------------12424310211503201098946683515
+  ... Content-Disposition: form-data; name="field.searchers"
+  ... 
+  ... users
+  ... -----------------------------12424310211503201098946683515--
+  ... """)
+  HTTP/1.1 200 Ok
+  ...
+
+Normally, the anonymous role has view, we'll deny it:
+
+  >>> print http(r"""
+  ... POST /++etc++site/AllRolePermissions.html HTTP/1.1
+  ... Authorization: Basic mgr:mgrpw
+  ... Content-Type: application/x-www-form-urlencoded
+  ... 
+  ... role_id=zope.Anonymous""" 
+  ... """&Deny%3Alist=zope.View""" 
+  ... """&Deny%3Alist=zope.app.dublincore.view""" 
+  ... """&SUBMIT_ROLE=Save+Changes""")
+  HTTP/1.1 200 Ok
+  ...
+
+Now, if we try to access the main page as an anonymous user, we'll be unauthorized:
+
+  >>> print http(r"""
+  ... GET / HTTP/1.1
+  ... """)
+  HTTP/1.1 401 Unauthorized
+  ...
+
+We'll even be unauthorized if we try to access it as bob:
+
+  >>> print http(r"""
+  ... GET / HTTP/1.1
+  ... Authorization: Basic bob:123
+  ... """)
+  HTTP/1.1 403 Forbidden
+  ...
+
+No, let's grant view to the authenticated group:
+
+  >>> print http(r"""
+  ... POST /@@grant.html HTTP/1.1
+  ... Authorization: Basic mgr:mgrpw
+  ... Content-Type: application/x-www-form-urlencoded
+  ... 
+  ... field.principal=em9wZS5BdXRoZW50aWNhdGVk&field.principal.displayed=y"""
+  ... """&field.em9wZS5BdXRoZW50aWNhdGVk.permission.zope.View=allow"""
+  ... """&field.em9wZS5BdXRoZW50aWNhdGVk.permission.zope.app.dublincore.view=allow"""
+  ... """&GRANT_SUBMIT=Change""")
+  HTTP/1.1 200 Ok
+  ...
+
+Now, with this, we can access the main page as bob, but not as an
+anonymous user:
+
+  >>> print http(r"""
+  ... GET / HTTP/1.1
+  ... Authorization: Basic bob:123
+  ... """)
+  HTTP/1.1 200 Ok
+  ...
+
+  >>> print http(r"""
+  ... GET / HTTP/1.1
+  ... """)
+  HTTP/1.1 401 Unauthorized
+  ...
+
+Now, we'll grant to unauthenticated:
+
+  >>> print http(r"""
+  ... POST /@@grant.html HTTP/1.1
+  ... Authorization: Basic mgr:mgrpw
+  ... Content-Type: application/x-www-form-urlencoded
+  ... Referer: http://localhost:8081/@@grant.html
+  ... 
+  ... field.principal=em9wZS5Bbnlib2R5"""
+  ... """&field.em9wZS5Bbnlib2R5.permission.zope.View=allow"""
+  ... """&field.em9wZS5Bbnlib2R5.permission.zope.app.dublincore.view=allow"""
+  ... """&GRANT_SUBMIT=Change""")
+  HTTP/1.1 200 Ok
+  ...
+
+With this, we can access the page as either bob or anonymous:
+
+  >>> print http(r"""
+  ... GET / HTTP/1.1
+  ... Authorization: Basic bob:123
+  ... """)
+  HTTP/1.1 200 Ok
+  ...
+
+  >>> print http(r"""
+  ... GET / HTTP/1.1
+  ... """)
+  HTTP/1.1 200 Ok
+  ...
+
+Now, we'll remove the authenticated group grant:
+
+  >>> print http(r"""
+  ... POST /@@grant.html HTTP/1.1
+  ... Authorization: Basic mgr:mgrpw
+  ... Content-Type: application/x-www-form-urlencoded
+  ... 
+  ... field.principal=em9wZS5BdXRoZW50aWNhdGVk"""
+  ... """&field.em9wZS5BdXRoZW50aWNhdGVk.permission.zope.View=unset"""
+  ... """&field.em9wZS5BdXRoZW50aWNhdGVk.permission.zope.app.dublincore.view=unset"""
+  ... """&GRANT_SUBMIT=Change""")
+  HTTP/1.1 200 Ok
+  ...
+
+And anonymous people will be able to access the page, but bob won't be able to:
+
+  >>> print http(r"""
+  ... GET / HTTP/1.1
+  ... Authorization: Basic bob:123
+  ... """)
+  HTTP/1.1 403 Forbidden
+  ...
+
+  >>> print http(r"""
+  ... GET / HTTP/1.1
+  ... """)
+  HTTP/1.1 200 Ok
+  ...
+
+Now, we'll remove the unauthenticated group grant:
+
+  >>> print http(r"""
+  ... POST /@@grant.html HTTP/1.1
+  ... Authorization: Basic mgr:mgrpw
+  ... Content-Type: application/x-www-form-urlencoded
+  ... Referer: http://localhost:8081/@@grant.html
+  ... 
+  ... field.principal=em9wZS5Bbnlib2R5"""
+  ... """&field.em9wZS5Bbnlib2R5.permission.zope.View=unset"""
+  ... """&field.em9wZS5Bbnlib2R5.permission.zope.app.dublincore.view=unset"""
+  ... """&GRANT_SUBMIT=Change""")
+  HTTP/1.1 200 Ok
+  ...
+
+and neither bob nor anonymous can access:
+
+  >>> print http(r"""
+  ... GET / HTTP/1.1
+  ... Authorization: Basic bob:123
+  ... """)
+  HTTP/1.1 403 Forbidden
+  ...
+
+  >>> print http(r"""
+  ... GET / HTTP/1.1
+  ... """)
+  HTTP/1.1 401 Unauthorized
+  ...
+
+Finally, we'll grant to everybody:
+
+  >>> print http(r"""
+  ... POST /@@grant.html HTTP/1.1
+  ... Authorization: Basic mgr:mgrpw
+  ... Content-Type: application/x-www-form-urlencoded
+  ... 
+  ... field.principal=em9wZS5FdmVyeWJvZHk_"""
+  ... """&field.em9wZS5FdmVyeWJvZHk_.permission.zope.View=allow"""
+  ... """&field.em9wZS5FdmVyeWJvZHk_.permission.zope.app.dublincore.view=allow"""
+  ... """&GRANT_SUBMIT=Change""", handle_errors = False)
+  HTTP/1.1 200 Ok
+  ...
+
+and both bob nor anonymous can access:
+
+  >>> print http(r"""
+  ... GET / HTTP/1.1
+  ... Authorization: Basic bob:123
+  ... """)
+  HTTP/1.1 200 Ok
+  ...
+
+  >>> print http(r"""
+  ... GET / HTTP/1.1
+  ... """)
+  HTTP/1.1 200 Ok
+  ...
+

Modified: Zope3/trunk/src/zope/app/authentication/principalplugins.zcml
===================================================================
--- Zope3/trunk/src/zope/app/authentication/principalplugins.zcml	2005-02-07 21:33:47 UTC (rev 29076)
+++ Zope3/trunk/src/zope/app/authentication/principalplugins.zcml	2005-02-07 21:33:49 UTC (rev 29077)
@@ -15,4 +15,9 @@
       handler=".principalplugins.addTitleAndDescription"
       />
 
+  <subscriber
+      for=".interfaces.IPrincipalCreated"
+      handler=".authentication.specialGroups"
+      />
+
 </configure>



More information about the Zope3-Checkins mailing list