[Checkins] SVN: z3c.authenticator/trunk/ Added coverage recipe

Roger Ineichen roger at projekt01.ch
Thu Mar 27 02:36:49 EDT 2008


Log message for revision 84958:
  Added coverage recipe
  Cleanup tests

Changed:
  U   z3c.authenticator/trunk/TODO.txt
  U   z3c.authenticator/trunk/buildout.cfg
  U   z3c.authenticator/trunk/src/z3c/authenticator/README.txt
  U   z3c.authenticator/trunk/src/z3c/authenticator/credential.py
  U   z3c.authenticator/trunk/src/z3c/authenticator/group.txt
  U   z3c.authenticator/trunk/src/z3c/authenticator/interfaces.py
  U   z3c.authenticator/trunk/src/z3c/authenticator/password.py
  U   z3c.authenticator/trunk/src/z3c/authenticator/testing.py
  U   z3c.authenticator/trunk/src/z3c/authenticator/tests.py
  U   z3c.authenticator/trunk/src/z3c/authenticator/vocabulary.txt

-=-
Modified: z3c.authenticator/trunk/TODO.txt
===================================================================
--- z3c.authenticator/trunk/TODO.txt	2008-03-26 22:05:39 UTC (rev 84957)
+++ z3c.authenticator/trunk/TODO.txt	2008-03-27 06:36:47 UTC (rev 84958)
@@ -2,13 +2,4 @@
 TODO
 ====
 
-- remove session setup from zope.app.authentication
-
-- implement own zope.app.authentication.idpicker.IdPicker
-
-- implement own zope.app.authentication.interfaces import IPasswordManager
-
 - implement nickName, email and phone?
-
-- check README and make sure the documentation is conform with the 
-  implementation

Modified: z3c.authenticator/trunk/buildout.cfg
===================================================================
--- z3c.authenticator/trunk/buildout.cfg	2008-03-26 22:05:39 UTC (rev 84957)
+++ z3c.authenticator/trunk/buildout.cfg	2008-03-27 06:36:47 UTC (rev 84958)
@@ -3,16 +3,27 @@
           externals/z3c.contents
           externals/z3c.table
 
-parts = test checker coverage
+parts = test checker coverage-test coverage-report
 
+
 [test]
 recipe = zc.recipe.testrunner
 eggs = z3c.authenticator [test]
 
+
 [checker]
 recipe = lovely.recipe:importchecker
 path = src/z3c/authenticator
 
-[coverage]
+
+[coverage-test]
+recipe = zc.recipe.testrunner
+eggs = z3c.authenticator [test]
+defaults = ['--coverage', '../../coverage']
+
+
+[coverage-report]
 recipe = zc.recipe.egg
 eggs = z3c.coverage
+scripts = coverage=coverage-report
+arguments = ('coverage', 'coverage/report')

Modified: z3c.authenticator/trunk/src/z3c/authenticator/README.txt
===================================================================
--- z3c.authenticator/trunk/src/z3c/authenticator/README.txt	2008-03-26 22:05:39 UTC (rev 84957)
+++ z3c.authenticator/trunk/src/z3c/authenticator/README.txt	2008-03-27 06:36:47 UTC (rev 84958)
@@ -2,7 +2,7 @@
 IAuthentication Utility
 =======================
 
-The Authenticator Utility provides a framework for authenticating principals 
+The Authenticator package provides a framework for authenticating principals 
 and associating information with them. It uses plugins and subscribers to get 
 its work done.
 
@@ -10,7 +10,8 @@
 utility providing the `zope.app.security.interfaces.IAuthentication` interface.
 
 Our target is to support a handy IAuthentication utility which offers a simple
-API for custom IUser implementations.
+API for custom IUser implementations and does not depend on the default
+zope.app.authentication implementation.
 
 
 Security
@@ -37,11 +38,11 @@
 it's context which is the real IUser.
 
 The Authenticator doesn't use a prefix. The usage of a prefix is only
-implemented in the IUserContainer. 
+implemented in the IGroupContainer. 
 
 We do not use a prefix in the IUserContainer because of the used unique user 
 id tokens. This will make sure that the same principal id doesn't get used at 
-a later time (Common criteria). There is a ``add`` method which creates 
+a later time (common criteria). There is a ``add`` method which creates 
 this id for you based on the login. The __setitem__ should not get used 
 directly for adding IUser instances anymore. We heavily restricted the
 usage of this method. See the inline doc tests in __setitem__ for more info.

Modified: z3c.authenticator/trunk/src/z3c/authenticator/credential.py
===================================================================
--- z3c.authenticator/trunk/src/z3c/authenticator/credential.py	2008-03-26 22:05:39 UTC (rev 84957)
+++ z3c.authenticator/trunk/src/z3c/authenticator/credential.py	2008-03-27 06:36:47 UTC (rev 84958)
@@ -175,9 +175,8 @@
     To illustrate how a session plugin works, we'll first setup some session
     machinery:
 
-      >>> from zope.session.session import RAMSessionDataContainer
-      >>> from zope.app.authentication.tests import sessionSetUp
-      >>> sessionSetUp(RAMSessionDataContainer)
+      >>> from z3c.authenticator.testing import sessionSetUp
+      >>> sessionSetUp()
 
     This lets us retrieve the same session info from any test request, which
     simulates what happens when a user submits a session ID as a cookie.
@@ -190,6 +189,12 @@
     credentials it gets from a request. Credentials can be retrieved from
     subsequent requests using the session-stored credentials.
 
+    If the given extractCredentials argument doesn't provide IHTTPRequest the
+    result will always be None:
+
+      >>> print plugin.extractCredentials(None)
+      None
+
     Our test environment is initially configured without credentials:
 
       >>> from zope.publisher.tests.httprequest import TestRequest
@@ -235,10 +240,20 @@
       >>> plugin.extractCredentials(request)
       {'login': 'luke', 'password': 'the_force'}
 
-    Finally, we clear the session credentials using the logout method:
+    Finally, we clear the session credentials using the logout method.
+    If the given logout argument doesn't provide IHTTPRequest the
+    result will always be False:
 
+      >>> plugin.logout(None)
+      False
+
+    Now try to logout with the correct argument:
+
       >>> plugin.logout(TestRequest())
       True
+
+    After logout we can not logaout again:
+
       >>> print plugin.extractCredentials(TestRequest())
       None
 
@@ -334,6 +349,12 @@
           >>> request.response.getHeader('location') # doctest: +ELLIPSIS
           '.../@@mylogin.html?camefrom=%2Ffoo%2Fbar%2Ffolder%2Fpage+1.html%3Fq%3Dvalue'
 
+        If the given challenge argument doesn't provide IHTTPRequest the
+        result will always be False:
+
+          >>> plugin.challenge(None)
+          False
+
         This can be used by the login form to redirect the user back to the
         originating URL upon successful authentication.
         """

Modified: z3c.authenticator/trunk/src/z3c/authenticator/group.txt
===================================================================
--- z3c.authenticator/trunk/src/z3c/authenticator/group.txt	2008-03-26 22:05:39 UTC (rev 84957)
+++ z3c.authenticator/trunk/src/z3c/authenticator/group.txt	2008-03-27 06:36:47 UTC (rev 84958)
@@ -15,6 +15,9 @@
   >>> from z3c.authenticator import interfaces
   >>> from z3c.authenticator.group import Group
   >>> group1 = Group(u'groups')
+  >>> group1
+  <Group None>
+
   >>> interfaces.IGroup.providedBy(group1)
   True
 
@@ -65,18 +68,18 @@
 authentication service, we will setup a Authenticator utility:
 
   >>> from z3c.authenticator.authentication import Authenticator
-  >>> sau = Authenticator()
+  >>> authenticator = Authenticator()
 
 Give them a location and register them as a IAuthentication utility :
 
   >>> import zope.component
   >>> from zope.app.security.interfaces import IAuthentication
-  >>> rootFolder['sau'] = sau
-  >>> zope.component.provideUtility(sau, IAuthentication)
+  >>> rootFolder['authenticator'] = authenticator
+  >>> zope.component.provideUtility(authenticator, IAuthentication)
 
 We will create and register a new principals utility:
 
-  >>> zope.component.provideUtility(sau, IAuthentication)
+  >>> zope.component.provideUtility(authenticator, IAuthentication)
 
 We also need to register the group athentication plugin:
 
@@ -107,8 +110,8 @@
 and configure and add the credential plugin to the Authenticator:
 
   >>> myCredentialsPlugin = MyCredentialsPlugin()
-  >>> sau['credentials'] = myCredentialsPlugin
-  >>> sau.credentialsPlugins = ('credentials', )
+  >>> authenticator['credentials'] = myCredentialsPlugin
+  >>> authenticator.credentialsPlugins = ('credentials', )
 
 We also need a principal and a IAuthenticationPlugin:
 
@@ -128,9 +131,9 @@
 Add the GroupContainer and UserContainer to the Authenticator and 
 set the correct plugin names
 
-  >>> sau['users'] = users
-  >>> sau['groups'] = groups
-  >>> sau.authenticatorPlugins = ('users', 'groups')
+  >>> authenticator['users'] = users
+  >>> authenticator['groups'] = groups
+  >>> authenticator.authenticatorPlugins = ('users', 'groups')
 
 
 Adding users to groups
@@ -384,14 +387,14 @@
 principal-creation events.  It adds any group-folder-defined groups to
 users in those groups:
 
-  >>> auth1 = sau.getPrincipal(p1.__name__)
+  >>> auth1 = authenticator.getPrincipal(p1.__name__)
 
   >>> auth1.groups
   [u'groups.G1', u'groups.GA']
 
 Of course, this applies to groups too:
 
-  >>> g1 = sau.getPrincipal('groups.G1')
+  >>> g1 = authenticator.getPrincipal('groups.G1')
   >>> g1.id
   u'groups.G1'
 
@@ -429,7 +432,7 @@
   >>> from z3c.authenticator.group import specialGroups
   >>> x = User('x', 'password', 'X')
   >>> found = FoundPrincipal(x)
-  >>> event = FoundPrincipalCreated(sau, found)
+  >>> event = FoundPrincipalCreated(authenticator, found)
   >>> specialGroups(event)
   >>> found.groups
   []
@@ -473,6 +476,16 @@
   >>> found.groups
   [u'groups.all', u'groups.authenticated']
 
+The `allGroups` attribute is a readonly iterable of the full closure of the
+groups in the `groups` attribute--that is, if the principal is a direct member
+of the 'Administrators' group, and the 'Administrators' group is a member of
+the 'Reviewers' group, then p.groups would be ['Administrators'] and 
+list(p.allGroups) would be ['Administrators', 'Reviewers'].
+
+  >>> sorted(found.allGroups)
+  [u'groups.all', u'groups.authenticated']
+
+
 These groups are only added to non-group principals:
 
   >>> found.groups = []
@@ -487,12 +500,13 @@
   ...     zope.interface.implements(zope.security.interfaces.IPrincipal)
   ...     id = title = description = ''
 
-  >>> event = FoundPrincipalCreated(sau, SolitaryPrincipal())
+  >>> event = FoundPrincipalCreated(authenticator, SolitaryPrincipal())
   >>> specialGroups(event)
   >>> found.groups
   []
 
 
+
 UserAwareGroup
 ----------------
 
@@ -527,55 +541,3 @@
 
   >>> zope.security.interfaces.IMemberAwareGroup.providedBy(foundGroup)
   True
-
-#User-aware groups
-#-------------------
-#The groupfolder includes a subscriber that gives group principals the
-#zope.security.interfaces.IGroupAware interface and an implementation thereof.
-#This allows groups to be able to get and set their members.
-#
-#Given an info object and a groups...
-#
-#    >>> class DemoGroupInformation(object):
-#    ...     interface.implements(
-#    ...         zope.app.authentication.groupfolder.IGroupInformation)
-#    ...     def __init__(self, title, description, principals):
-#    ...         self.title = title
-#    ...         self.description = description
-#    ...         self.principals = principals
-#    ...
-#    >>> i = DemoGroupInformation(
-#    ...     'Managers', 'Taskmasters', ('joe', 'jane'))
-#    ...
-#    >>> info = zope.app.authentication.groupfolder.GroupInfo(
-#    ...     'groups.managers', i)
-#    >>> class DummyGroup(object):
-#    ...     interface.implements(IGroupAwarePrincipal)
-#    ...     def __init__(self, id, title=u'', description=u''):
-#    ...         self.id = id
-#    ...         self.title = title
-#    ...         self.description = description
-#    ...         self.groups = []
-#    ...
-#    >>> principal = DummyGroup('foo')
-#    >>> zope.security.interfaces.IMemberAwareGroup.providedBy(principal)
-#    False
-#
-#...when you call the subscriber, it adds the two pseudo-methods to the
-#principal and makes the principal provide the IMemberAwareGroup interface.
-#
-#    >>> zope.app.authentication.groupfolder.setUserSubscriber(
-#    ...     interfaces.FoundPrincipalCreated(
-#    ...         'dummy auth (ignored)', principal, info))
-#    >>> principal.getUsers()
-#    ('joe', 'jane')
-#    >>> principal.setUsers(('joe', 'jane', 'jaimie'))
-#    >>> principal.getUsers()
-#    ('joe', 'jane', 'jaimie')
-#    >>> zope.security.interfaces.IMemberAwareGroup.providedBy(principal)
-#    True
-#
-#The two methods work with the value on the IGroupInformation object.
-#
-#    >>> i.principals == principal.getUsers()
-#    True

Modified: z3c.authenticator/trunk/src/z3c/authenticator/interfaces.py
===================================================================
--- z3c.authenticator/trunk/src/z3c/authenticator/interfaces.py	2008-03-26 22:05:39 UTC (rev 84957)
+++ z3c.authenticator/trunk/src/z3c/authenticator/interfaces.py	2008-03-27 06:36:47 UTC (rev 84958)
@@ -409,9 +409,6 @@
         access to the credentials.
     """
 
-    def __init__(login, password):
-        pass
-
     def getLogin():
         """Return login name."""
 

Modified: z3c.authenticator/trunk/src/z3c/authenticator/password.py
===================================================================
--- z3c.authenticator/trunk/src/z3c/authenticator/password.py	2008-03-26 22:05:39 UTC (rev 84957)
+++ z3c.authenticator/trunk/src/z3c/authenticator/password.py	2008-03-27 06:36:47 UTC (rev 84958)
@@ -28,7 +28,6 @@
 
 from z3c.authenticator.interfaces import IPasswordManager
 
-
 _encoder = getencoder("utf-8")
 
 

Modified: z3c.authenticator/trunk/src/z3c/authenticator/testing.py
===================================================================
--- z3c.authenticator/trunk/src/z3c/authenticator/testing.py	2008-03-26 22:05:39 UTC (rev 84957)
+++ z3c.authenticator/trunk/src/z3c/authenticator/testing.py	2008-03-27 06:36:47 UTC (rev 84958)
@@ -17,9 +17,22 @@
 __docformat__ = "reStructuredText"
 
 import zope.component
+import zope.interface
+from zope.publisher.interfaces import IRequest
+from zope.app.testing import setup
+from zope.app.testing import placelesssetup
+
+from zope.session.interfaces import IClientId
+from zope.session.interfaces import IClientIdManager
+from zope.session.interfaces import ISession
+from zope.session.interfaces import ISessionDataContainer
+from zope.session.session import ClientId
+from zope.session.session import Session
+from zope.session.session import RAMSessionDataContainer
+from zope.session.http import CookieClientIdManager
+
 from z3c.authenticator.interfaces import IPasswordManager
 from z3c.authenticator.password import PlainTextPasswordManager
-from zope.app.testing import setup
 
 ###############################################################################
 #
@@ -32,17 +45,32 @@
         IPasswordManager, "Plain Text")
 
 
+class TestClientId(object):
+    zope.interface.implements(IClientId)
+    def __new__(cls, request):
+        return 'dummyclientidfortesting'
+
+
+def sessionSetUp(session_data_container_class=RAMSessionDataContainer):
+    placelesssetup.setUp()
+    zope.component.provideAdapter(TestClientId, (IRequest,), IClientId)
+    zope.component.provideAdapter(Session, (IRequest,), ISession)
+    zope.component.provideUtility(CookieClientIdManager(), IClientIdManager)
+    sdc = session_data_container_class()
+    zope.component.provideUtility(sdc, ISessionDataContainer, name='')
+
+
 ###############################################################################
 #
 # placeful setup/teardown
 #
 ###############################################################################
 
-def siteSetUp(test):
+def placefulSetUp(test):
     site = setup.placefulSetUp(site=True)
     test.globs['rootFolder'] = site
     setUpPasswordManager()
 
 
-def siteTearDown(test):
+def placefulTearDown(test):
     setup.placefulTearDown()

Modified: z3c.authenticator/trunk/src/z3c/authenticator/tests.py
===================================================================
--- z3c.authenticator/trunk/src/z3c/authenticator/tests.py	2008-03-26 22:05:39 UTC (rev 84957)
+++ z3c.authenticator/trunk/src/z3c/authenticator/tests.py	2008-03-27 06:36:47 UTC (rev 84958)
@@ -147,10 +147,10 @@
 def test_suite():
     return unittest.TestSuite((
         doctest.DocFileSuite('README.txt',
-            setUp=testing.siteSetUp, tearDown=testing.siteTearDown,
+            setUp=testing.placefulSetUp, tearDown=testing.placefulSetUp,
             optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS),
         doctest.DocFileSuite('group.txt',
-            setUp=testing.siteSetUp, tearDown=testing.siteTearDown,
+            setUp=testing.placefulSetUp, tearDown=testing.placefulSetUp,
             optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS),
         doctest.DocTestSuite('z3c.authenticator.credential',
             setUp=placelesssetup.setUp, tearDown=placelesssetup.tearDown),

Modified: z3c.authenticator/trunk/src/z3c/authenticator/vocabulary.txt
===================================================================
--- z3c.authenticator/trunk/src/z3c/authenticator/vocabulary.txt	2008-03-26 22:05:39 UTC (rev 84957)
+++ z3c.authenticator/trunk/src/z3c/authenticator/vocabulary.txt	2008-03-27 06:36:47 UTC (rev 84958)
@@ -2,11 +2,12 @@
 Vocabulary
 ==========
 
-The vocabulary module provides vocabularies for the authenticatorPlugins.
+The vocabulary module provides vocabularies for the authenticator plugins and
+the credentials plugins.
 
 The options should include the unique names of all of the plugins that provide
-the appropriate interface (interfaces.IAuthentiatorPlugin, respectively) for 
-the current context-- which is expected to be a pluggable authentication 
+the appropriate interface (IAuthentiatorPlugin or ICredentialsPlugin, 
+respectively) for the current context which is expected to be a IAuthenticator 
 utility, hereafter referred to as a Authenticator.
 
 These names may be for objects contained within the Authenticator 
@@ -56,6 +57,10 @@
     ...
     >>> zope.component.provideAdapter(getSiteManager)
 
+
+authenticatorPlugins
+--------------------
+
 We are now ready to create a vocabulary that we can use.  The context is
 our faux authentication utility, `auth`.
 
@@ -134,3 +139,70 @@
      u'Plugin 3 (in contents)',
      u'Plugin 4 (in contents)',
      u'Plugin X (not found; deselecting will remove)']
+
+
+credentialsPlugins
+------------------
+
+For completeness, we'll do the same review of the credentialsPlugins.
+
+    >>> class DemoPlugin(object):
+    ...     zope.interface.implements(interfaces.ICredentialsPlugin)
+    ...     def __init__(self, name):
+    ...         self.name = name
+    ...
+    >>> utility_plugins = dict(
+    ...     (i, DemoPlugin(u'Plugin %d' % i)) for i in range(4))
+    >>> contained_plugins = dict(
+    ...     (i, DemoPlugin(u'Plugin %d' % i)) for i in range(1, 5))
+    >>> for p in utility_plugins.values():
+    ...     zope.component.provideUtility(p, name=p.name)
+    ...
+    >>> auth = DemoAuth((p.name, p) for p in contained_plugins.values())
+    >>> vocab = vocabulary.credentialsPlugins(auth)
+
+Iterating over the vocabulary results in all of the terms, in a relatively
+arbitrary order of their names.  (This vocabulary should typically use a
+widget that sorts values on the basis of localized collation order of the term
+titles.) Similarly, we can use `in` to test for the presence of values in the
+vocabulary. The length reports the expected value.
+
+    >>> [term.value for term in vocab] # doctest: +NORMALIZE_WHITESPACE
+    [u'Plugin 0', u'Plugin 1', u'Plugin 2', u'Plugin 3', u'Plugin 4',
+     u'Plugin X']
+    >>> ['Plugin %s' % i in vocab for i in range(-1, 6)]
+    [False, True, True, True, True, True, False]
+    >>> 'Plugin X' in vocab
+    True
+    >>> len(vocab)
+    6
+
+One can get a term for a given value using `getTerm()`; its token, in
+turn, should also return the same effective term from `getTermByToken`.
+
+    >>> values = ['Plugin 0', 'Plugin 1', 'Plugin 2', 'Plugin 3', 'Plugin 4',
+    ...           'Plugin X']
+    >>> for val in values:
+    ...     term = vocab.getTerm(val)
+    ...     assert term.value == val
+    ...     term2 = vocab.getTermByToken(term.token)
+    ...     assert term2.token == term.token
+    ...     assert term2.value == val
+    ...
+
+The terms have titles, which are message ids that show the plugin title or id
+and whether the plugin is a utility or just contained in the auth utility.
+We'll give one of the plugins a dublin core title just to show the
+functionality. We need to regenerate the vocabulary, since it calculates all
+of its data at once. Then we'll check the titles.  We'll have to translate
+them to see what we expect.
+
+    >>> zope.interface.directlyProvides(contained_plugins[1], ISpecial)
+    >>> vocab = vocabulary.credentialsPlugins(auth)
+    >>> pprint.pprint([i18n.translate(term.title) for term in vocab])
+    [u'Plugin 0 (a utility)',
+     u'Special Title (in contents)',
+     u'Plugin 2 (in contents)',
+     u'Plugin 3 (in contents)',
+     u'Plugin 4 (in contents)',
+     u'Plugin X (not found; deselecting will remove)']



More information about the Checkins mailing list