[Checkins] SVN: Products.PluggableAuthService/trunk/ Merge Dieter Maurer's 'not-compenetent plugin' branch.

Tres Seaver cvs-admin at zope.org
Fri May 25 18:19:21 UTC 2012


Log message for revision 126497:
  Merge Dieter Maurer's 'not-compenetent plugin' branch.
  
  See:  https://bugs.launchpad.net/bugs/649596

Changed:
  _U  Products.PluggableAuthService/trunk/
  U   Products.PluggableAuthService/trunk/Products/PluggableAuthService/PluggableAuthService.py
  U   Products.PluggableAuthService/trunk/Products/PluggableAuthService/__init__.py
  U   Products.PluggableAuthService/trunk/Products/PluggableAuthService/interfaces/plugins.py
  A   Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/NotCompetentHelper.py
  A   Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/tests/test_NotCompetentHelper.py
  A   Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/www/ncbrAdd.zpt
  U   Products.PluggableAuthService/trunk/Products/PluggableAuthService/tests/conformance.py
  U   Products.PluggableAuthService/trunk/Products/PluggableAuthService/tests/test_PluggableAuthService.py

-=-
Modified: Products.PluggableAuthService/trunk/Products/PluggableAuthService/PluggableAuthService.py
===================================================================
--- Products.PluggableAuthService/trunk/Products/PluggableAuthService/PluggableAuthService.py	2012-05-25 14:48:51 UTC (rev 126496)
+++ Products.PluggableAuthService/trunk/Products/PluggableAuthService/PluggableAuthService.py	2012-05-25 18:19:18 UTC (rev 126497)
@@ -62,6 +62,7 @@
 from .interfaces.plugins import IGroupEnumerationPlugin
 from .interfaces.plugins import IRoleEnumerationPlugin
 from .interfaces.plugins import IRoleAssignerPlugin
+from .interfaces.plugins import INotCompetentPlugin
 from .interfaces.plugins import IChallengeProtocolChooser
 from .interfaces.plugins import IRequestTypeSniffer
 from .permissions import SearchPrincipals
@@ -223,6 +224,10 @@
         plugins = self._getOb( 'plugins' )
         is_top = self._isTop()
 
+        if not is_top and self._isNotCompetent( request, plugins ):
+            # this user folder should not try to authenticate this request
+            return None
+
         user_ids = self._extractUserIds(request, plugins)
         ( accessed
         , container
@@ -521,6 +526,32 @@
     #
     #   Helper methods
     #
+    security.declarePrivate( '_isNotCompetent' )
+    def _isNotCompetent( self, request, plugins ):
+
+        """ return true when this user folder should not try authentication.
+
+        Never called for top level user folder.
+        """
+        try:
+            not_competents = plugins.listPlugins( INotCompetentPlugin )
+        except _SWALLOWABLE_PLUGIN_EXCEPTIONS:
+            logger.debug('NotCompetent plugin listing error', exc_info=True)
+            not_competents = ()
+
+        for not_competent_id, not_competent in not_competents:
+            try:
+                if not_competent.isNotCompetentToAuthenticate(request):
+                    return True
+            except _SWALLOWABLE_PLUGIN_EXCEPTIONS:
+                reraise(not_competent)
+                logger.debug( 'NotCompetentPlugin %s error' % not_competent_id
+                            , exc_info=True
+                            )
+                continue
+        return False
+
+        
     security.declarePrivate( '_extractUserIds' )
     def _extractUserIds( self, request, plugins ):
 
@@ -1273,6 +1304,15 @@
     , 'request_type_sniffer'
     , "Request Type Sniffer plugins detect the type of an incoming request."
     )
+  , ( INotCompetentPlugin
+    , 'INotCompetentPlugin'
+    , 'notcompetent'
+    , "Not-Competent plugins check whether this user folder should not "
+      "authenticate the current request. "
+      "These plugins are not used for a top level user folder. "
+      "They are typically used to prevent shaddowing of authentications by "
+      "higher level user folders."
+    )
   )
 
 def addPluggableAuthService( dispatcher

Modified: Products.PluggableAuthService/trunk/Products/PluggableAuthService/__init__.py
===================================================================
--- Products.PluggableAuthService/trunk/Products/PluggableAuthService/__init__.py	2012-05-25 14:48:51 UTC (rev 126496)
+++ Products.PluggableAuthService/trunk/Products/PluggableAuthService/__init__.py	2012-05-25 18:19:18 UTC (rev 126497)
@@ -44,6 +44,7 @@
 from plugins import DynamicGroupsPlugin as DGP
 from plugins import ChallengeProtocolChooser as CPC
 from plugins import RequestTypeSniffer as RTS
+from plugins import NotCompetentHelper as NCH
 
 registerMultiPlugin(HBAH.HTTPBasicAuthHelper.meta_type)
 registerMultiPlugin(IAH.InlineAuthHelper.meta_type)
@@ -61,6 +62,7 @@
 registerMultiPlugin(DGP.DynamicGroupsPlugin.meta_type)
 registerMultiPlugin(CPC.ChallengeProtocolChooser.meta_type)
 registerMultiPlugin(RTS.RequestTypeSniffer.meta_type)
+registerMultiPlugin(NCH.NotCompetent_byRoles.meta_type)
 
 try:
     from Products.GenericSetup import profile_registry
@@ -257,6 +259,14 @@
                          , icon='plugins/www/DelegatingMultiPlugin.png'
                          )
 
+    context.registerClass( NCH.NotCompetent_byRoles
+                         , permission=ManageUsers
+                         , constructors=(
+                            NCH.manage_addNotCompetent_byRolesForm,
+                            NCH.manage_addNotCompetent_byRoles, )
+                         , visibility=None
+                         )
+
     if profile_registry is not None:
 
         context.registerClass( PluggableAuthService.PluggableAuthService

Modified: Products.PluggableAuthService/trunk/Products/PluggableAuthService/interfaces/plugins.py
===================================================================
--- Products.PluggableAuthService/trunk/Products/PluggableAuthService/interfaces/plugins.py	2012-05-25 14:48:51 UTC (rev 126496)
+++ Products.PluggableAuthService/trunk/Products/PluggableAuthService/interfaces/plugins.py	2012-05-25 18:19:18 UTC (rev 126497)
@@ -479,3 +479,18 @@
 #         has two different algorithms, based on whether or not the
 #         context object implements IPlacelessSecurity.
 #
+
+
+class INotCompetentPlugin( Interface ):
+
+    """check whether this user folder is not competent to authenticate.
+
+    Never used for a top level user folder;
+    primarily used to prevent shaddowing of authentications by higher level
+    user folders.
+    """
+
+    def isNotCompetentToAuthenticate(request):
+
+        """return true if this user folder should not authenticate *request*.
+        """

Added: Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/NotCompetentHelper.py
===================================================================
--- Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/NotCompetentHelper.py	                        (rev 0)
+++ Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/NotCompetentHelper.py	2012-05-25 18:19:18 UTC (rev 126497)
@@ -0,0 +1,143 @@
+##############################################################################
+#
+# Copyright (c) 2012 Zope Foundation and Contributors
+#
+# 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.
+#
+##############################################################################
+""" NotCompetentHelper   `INotCompetent` plugin utilities
+
+`INotCompetent` plugins are usually used to prevent shaddowing of users
+authenticated by higher level user folders. This module provides
+an `INotCompetent` plugin base class which can check for authentications
+by higher level user folders and the class `NotCompetent_byRoles`
+to prevent shaddowing of higher level authentications with
+specified roles.
+"""
+# General Zope imports
+from Acquisition import aq_inner, aq_parent, aq_base
+from AccessControl import ClassSecurityInfo
+from AccessControl.Permissions import manage_users
+from AccessControl.User import nobody
+from ZPublisher.BaseRequest import UNSPECIFIED_ROLES
+from ZPublisher.Response import Response
+from OFS.PropertyManager import PropertyManager
+
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+
+# PluggableAuthService imports
+from Products.PluggableAuthService.interfaces.plugins import \
+    INotCompetentPlugin
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+from Products.PluggableAuthService.utils import classImplements
+
+
+class HigherLevelUserFolderAccessMixin( object ):
+    """mixin class for access to higher level user folders
+
+       requires to be mixed with a `BasePlugin`.
+    """
+    def _generateHigherLevelUserFolders( self ):
+        folder = aq_parent( aq_inner( self._getPAS( ) ) )
+        while True:
+            folder = aq_parent( aq_inner( folder ) )
+            if folder is None: return
+            uf = getattr( folder, "__allow_groups__", None )
+            validate = getattr( aq_base( uf ), "validate", None )
+            if validate is not None:
+                yield uf
+
+    def _getHigherLevelUser( self, request, roles=None ):
+        if roles:
+            accessed = self._getPAS( )._getObjectContext(
+                request[ "PUBLISHED" ], request
+                ) [ 1 ]
+        req_roles = request.roles
+        auth = request._auth
+        # save response and install new one to prevent side effects
+        saved_response = request.response
+        try:
+            request.response = Response()
+            for uf in self._generateHigherLevelUserFolders( ):
+                if req_roles is UNSPECIFIED_ROLES:
+                    u = uf.validate( request, auth )
+                else:
+                    u = uf.validate( request, auth, req_roles )
+                if u is None or u is nobody:
+                    continue
+                # this user folder has authenticated a user able to perform
+                #  the request
+                if roles:
+                    # check in addition that is has one of *roles*
+                    if not u.allowed(accessed, roles):
+                        # reject this user
+                        continue
+                return u
+        finally:
+            request.response = saved_response
+
+
+class NotCompetentBase( BasePlugin, HigherLevelUserFolderAccessMixin ):
+    """abstract `INotCompententPlugin` base class.
+
+    with access to higher level user folders.
+    """
+
+    security = ClassSecurityInfo()
+    security.declareObjectProtected(manage_users)
+
+    def __init__( self, id, title='' ):
+        self.id = id
+        self.title = title
+
+    security.declarePrivate( 'isNotCompetentToAuthenticate' )
+    def isNotCompetentToAuthenticate( self, request ):
+        raise NotImplementedError( )
+
+classImplements(NotCompetentBase, INotCompetentPlugin)
+
+
+class NotCompetent_byRoles( NotCompetentBase ):
+    """`INotCompetentPlugin` to prevent authentication shaddowing by roles.
+    """
+
+    meta_type = "prevent authentication shaddowing by roles"
+
+    _properties = (
+        PropertyManager._properties +
+        (
+            dict( id="roles", label="roles (empty means all roles)",
+                  type="lines", mode="rw",
+                  ),
+        )
+    )
+    roles = ()
+
+    manage_options = (
+        ( NotCompetentBase.manage_options[ 0 ], )
+        + PropertyManager.manage_options
+        + NotCompetentBase.manage_options[ 1:-1 ]
+        )
+  
+    def isNotCompetentToAuthenticate( self, request ):
+        return self._getHigherLevelUser( request, self.roles ) is not None
+
+
+manage_addNotCompetent_byRolesForm = PageTemplateFile(
+    'www/ncbrAdd', globals(), __name__='manage_addNotCompetent_byRolesForm' )
+
+def manage_addNotCompetent_byRoles(self, id, title='', REQUEST=None):
+    """ Factory method to instantiate a NotCompetent_byRoles """
+    obj = NotCompetent_byRoles(id, title=title)
+    self._setObject(id, obj)
+
+    if REQUEST is not None:
+        qs = 'manage_tabs_message=NotCompetent_byRoles+added.'
+        my_url = self.absolute_url()
+        REQUEST['RESPONSE'].redirect('%s/manage_workspace?%s' % (my_url, qs))

Added: Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/tests/test_NotCompetentHelper.py
===================================================================
--- Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/tests/test_NotCompetentHelper.py	                        (rev 0)
+++ Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/tests/test_NotCompetentHelper.py	2012-05-25 18:19:18 UTC (rev 126497)
@@ -0,0 +1,129 @@
+##############################################################################
+#
+# Copyright (c) 2012 Zope Foundation and Contributors
+#
+# 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.
+#
+##############################################################################
+import unittest
+
+from ZPublisher.BaseRequest import UNSPECIFIED_ROLES
+
+from Products.PluggableAuthService.tests.conformance \
+     import INotCompetentPlugin_conformance
+from Products.PluggableAuthService.tests.test_PluggableAuthService \
+     import PluggableAuthServiceTests
+
+
+
+class _WrapPluggableAuthServiceTests( PluggableAuthServiceTests ):
+    """auxiliary wrapper class to allow for instantiation."""
+
+    def __init__(self, *args, **kw): pass
+
+
+
+class NotCompetentHelperTests( unittest.TestCase
+                           , INotCompetentPlugin_conformance
+                           ):
+
+    def _getTargetClass( self ):
+
+        from Products.PluggableAuthService.plugins.NotCompetentHelper \
+            import NotCompetent_byRoles
+
+        return NotCompetent_byRoles
+
+    def _makeOne( self, id='test', *args, **kw ):
+
+        return self._getTargetClass()( id=id, *args, **kw )
+
+    def setUp( self ):
+        # we use `PluggableAuthServiceTests` to set up a structure
+        #  with two pas instances: one at the root set up for
+        #  authentications, the other further down with a
+        #  `NotCompetent_byRoles` plugin.
+        past = _WrapPluggableAuthServiceTests( )
+        root_pas, request = past._setup_for_authentication( )
+        request.roles = UNSPECIFIED_ROLES
+        request._auth = None
+        request.response = None
+        root = request[ "PARENTS" ][ -1 ]
+        root._setObject(root_pas.getId(), root_pas)
+        test_pas = past._makeOne( past._makePlugins( ) )
+        folder = request[ "PARENTS" ][ -2 ]
+        folder._setObject(test_pas.getId(), test_pas)
+        test_pas = folder._getOb( test_pas.getId( ) ) # ac wrap
+        nc = self._getTargetClass()( "nc" )
+        test_pas._setObject( nc.getId(), nc )
+        self.plugin, self.request = test_pas._getOb( nc.getId( ) ), request
+
+    def test__generateHigherLevelUserFolders( self ):
+        plugin = self.plugin
+        self.assertEqual( len( list( plugin._generateHigherLevelUserFolders( ) ) ), 1)
+
+    def test__getHigherLevelUser( self ):
+        plugin, request = self.plugin, self.request
+        hlu =  plugin._getHigherLevelUser( request )
+        self.assertEqual( hlu.getUserName( ), "olivier" )
+
+    def test__getHigherLevelUser_asHamlet( self ):
+        plugin, request = self.plugin, self.request
+        hlu =  plugin._getHigherLevelUser( request, ( "Hamlet", ) )
+        self.assertEqual( hlu.getUserName( ), "olivier" )
+
+    def test__getHigherLevelUser_asManager( self ):
+        plugin, request = self.plugin, self.request
+        hlu =  plugin._getHigherLevelUser( request, ( "Manager", ) )
+        self.assertEqual( hlu, None)
+
+    def test__getHigherLevelUser_requiresHamlet( self ):
+        plugin, request = self.plugin, self.request
+        request.roles =  ( "Hamlet", )
+        hlu =  plugin._getHigherLevelUser( request )
+        self.assertEqual( hlu.getUserName( ), "olivier" )
+
+    def test__getHigherLevelUser_requiresManager( self ):
+        plugin, request = self.plugin, self.request
+        request.roles =  ( "Manager", )
+        hlu =  plugin._getHigherLevelUser( request )
+        self.assertEqual( hlu, None)
+
+    def test_isNotCompetent_any( self ):
+        plugin, request = self.plugin, self.request
+        self.assertEqual( plugin.isNotCompetentToAuthenticate( request ),
+                          True
+                          )
+
+    def test_isNotCompetent_Hamlet( self ):
+        plugin, request = self.plugin, self.request
+        plugin.manage_changeProperties( roles=( "Hamlet", ) )
+        self.assertEqual( plugin.isNotCompetentToAuthenticate( request ),
+                          True
+                          )
+
+    def test_isNotCompetent_Manager( self ):
+        plugin, request = self.plugin, self.request
+        plugin.manage_changeProperties( roles=( "Manager", ) )
+        self.assertEqual( plugin.isNotCompetentToAuthenticate( request ),
+                          False
+                          )
+
+
+if __name__ == "__main__":
+    unittest.main()
+
+def test_suite():
+    return unittest.TestSuite((
+        unittest.makeSuite( NotCompetentHelperTests ),
+        ))
+
+
+
+

Added: Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/www/ncbrAdd.zpt
===================================================================
--- Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/www/ncbrAdd.zpt	                        (rev 0)
+++ Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/www/ncbrAdd.zpt	2012-05-25 18:19:18 UTC (rev 126497)
@@ -0,0 +1,47 @@
+<h1 tal:replace="structure here/manage_page_header">Header</h1>
+
+<h2 tal:define="form_title string:Not-Compentent by roles"
+    tal:replace="structure here/manage_form_title">Form Title</h2>
+
+<p class="form-help">
+The plugin prevents this user folder to shaddow higher level authentications with given roles.
+</p>
+
+<form action="manage_addNotCompetent_byRoles" method="post"
+ enctype="multipart/form-data">
+<table cellspacing="0" cellpadding="2" border="0">
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-label">
+    Id
+    </div>
+    </td>
+    <td align="left" valign="top">
+    <input type="text" name="id" size="40" />
+    </td>
+  </tr>
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-optional">
+    Title
+    </div>
+    </td>
+    <td align="left" valign="top">
+    <input type="text" name="title" size="40" />
+    </td>
+  </tr>
+  <tr>
+    <td align="left" valign="top">
+    </td>
+    <td align="left" valign="top">
+    <div class="form-element">
+    <input class="form-element" type="submit" name="submit"
+     value=" Add " />
+    </div>
+    </td>
+  </tr>
+</table>
+</form>
+
+<h1 tal:replace="structure here/manage_page_footer">Footer</h1>
+

Modified: Products.PluggableAuthService/trunk/Products/PluggableAuthService/tests/conformance.py
===================================================================
--- Products.PluggableAuthService/trunk/Products/PluggableAuthService/tests/conformance.py	2012-05-25 14:48:51 UTC (rev 126496)
+++ Products.PluggableAuthService/trunk/Products/PluggableAuthService/tests/conformance.py	2012-05-25 18:19:18 UTC (rev 126497)
@@ -347,3 +347,21 @@
 
         verifyClass( IPropertySheet, self._getTargetClass() )
 
+
+class INotCompetentPlugin_conformance:
+
+    def test_INotCompetentPlugin_conformance( self ):
+
+        from Products.PluggableAuthService.interfaces.plugins \
+            import INotCompetentPlugin
+
+        verifyClass( INotCompetentPlugin, self._getTargetClass() )
+
+    def test_INotCompetentPlugin_listInterfaces(self):
+
+        from Products.PluggableAuthService.interfaces.plugins \
+            import INotCompetentPlugin
+
+        listed = self._makeOne().listInterfaces()
+        self.failUnless(INotCompetentPlugin.__name__ in listed)
+

Modified: Products.PluggableAuthService/trunk/Products/PluggableAuthService/tests/test_PluggableAuthService.py
===================================================================
--- Products.PluggableAuthService/trunk/Products/PluggableAuthService/tests/test_PluggableAuthService.py	2012-05-25 14:48:51 UTC (rev 126496)
+++ Products.PluggableAuthService/trunk/Products/PluggableAuthService/tests/test_PluggableAuthService.py	2012-05-25 18:19:18 UTC (rev 126497)
@@ -22,6 +22,8 @@
 from zExceptions import Unauthorized, Redirect
 
 from Products.PluggableAuthService.utils import directlyProvides
+from zope.interface import implements
+from ..interfaces.plugins import INotCompetentPlugin
 
 from conformance import IUserFolder_conformance
 
@@ -217,6 +219,20 @@
         self.count += 1
         return True
 
+class DummyNotCompetentPlugin( DummyPlugin ):
+    implements( INotCompetentPlugin )
+
+    def __init__( self, id, type ):
+        self.id, self.type = id, type
+
+    def getId( self ): return id
+
+    def isNotCompetentToAuthenticate( self, request ):
+        if self.type is None:
+            raise KeyError("purposeful `KeyError` by `isNotCompetentToAuthenticate`")
+        return self.type
+
+
 class FauxRequest( object ):
 
     form = property(lambda self: self)
@@ -924,6 +940,46 @@
         finally:
             PluggableAuthService.emergency_user = old_eu
 
+
+
+    def _isNotCompetent_test( self, decisions, result):
+        from Products.PluggableAuthService.interfaces.plugins \
+            import INotCompetentPlugin
+
+        plugins = self._makePlugins( )
+        zcuf = self._makeOne( plugins )
+        plugins = zcuf._getOb("plugins") # acquisition wrap
+
+        for i, decision in enumerate( decisions ):
+            pid = "nc_%d" % i
+            p = DummyNotCompetentPlugin( pid, decision )
+            zcuf._setObject( pid, p )
+            plugins.activatePlugin( INotCompetentPlugin, pid )
+
+        self.assertEqual( zcuf._isNotCompetent( None, plugins ), result )
+
+    def test__isNotCompetent_empty( self ):
+        self._isNotCompetent_test( (), False )
+
+    def test__isNotCompetent_False( self ):
+        self._isNotCompetent_test( (False,), False )
+
+    def test__isNotCompetent_True( self ):
+        self._isNotCompetent_test( (True,), True )
+
+    def test__isNotCompetent_True_False( self ):
+        self._isNotCompetent_test( (True, False), True )
+
+    def test__isNotCompetent_False_True( self ):
+        self._isNotCompetent_test( (False, True), True )
+
+    def test__isNotCompetent_Broken( self ):
+        self._isNotCompetent_test( (None,), False )
+
+    def test__isNotCompetent_Broken_True( self ):
+        self._isNotCompetent_test( (None, True), True )
+
+
     def test__getObjectContext_no_steps( self ):
 
         zcuf = self._makeOne()
@@ -1773,6 +1829,82 @@
         self.assertEqual( root_validated.getGroups()
                         , [ 'All People Everywhere Ever' ] )
 
+    def _setup_for_authentication( self ):
+        """return pas set up for authentication and associated request."""
+
+
+        from Products.PluggableAuthService.interfaces.plugins \
+            import IExtractionPlugin, \
+                   IAuthenticationPlugin, \
+                   IUserEnumerationPlugin, \
+                   IRolesPlugin
+
+        plugins = self._makePlugins()
+        zcuf = self._makeOne( plugins )
+
+        login = DummyPlugin()
+        directlyProvides( login, IExtractionPlugin, IAuthenticationPlugin )
+        login.extractCredentials = _extractLogin
+        login.authenticateCredentials = _authLogin
+        zcuf._setObject( 'login', login )
+
+        nc = DummyNotCompetentPlugin( 'nc', True )
+        zcuf._setObject( 'nc', nc )
+
+        olivier = DummyPlugin()
+        directlyProvides( olivier, IUserEnumerationPlugin, IRolesPlugin )
+        olivier.enumerateUsers = lambda id: id == 'foo' or None
+        olivier.getRolesForPrincipal = lambda user, req: (
+                     user.getId() == 'olivier' and ( 'Hamlet', ) or () )
+
+        zcuf._setObject( 'olivier', olivier )
+
+        plugins = zcuf._getOb( 'plugins' )
+        plugins.activatePlugin( IExtractionPlugin, 'login' )
+        plugins.activatePlugin( IAuthenticationPlugin, 'login' )
+        plugins.activatePlugin( IUserEnumerationPlugin, 'olivier' )
+        plugins.activatePlugin( IRolesPlugin, 'olivier' )
+        plugins.activatePlugin( INotCompetentPlugin, 'nc' )
+
+        rc, root, folder, object = self._makeTree()
+
+        index = FauxObject( 'index_html' )
+        index.__roles__ = ( 'Hamlet', )
+        acquired_index = index.__of__( root ).__of__( object )
+
+        request = self._makeRequest( ( 'folder', 'object', 'index_html' )
+                                   , RESPONSE=FauxResponse()
+                                   , PARENTS=[ object, folder, root ]
+                                   , PUBLISHED=acquired_index.__of__( object )
+                                   , form={ 'login' : 'olivier'
+                                          , 'password' : 'arras'
+                                          }
+                                   )
+
+        return zcuf, request
+
+
+    def _NotCompetent_validate_check( self, is_top ):
+
+        zcuf, request = self._setup_for_authentication( )
+        folder, root = request[ "PARENTS" ][ -2: ]
+
+        wrapped = zcuf.__of__( is_top and root or folder )
+
+        return wrapped.validate( request )
+
+    def test_validate_NotCompetent_isTop( self ):
+        self.assertEqual(
+            self._NotCompetent_validate_check( True ).getUserName(),
+            'olivier'
+            )
+
+    def test_validate_NotCompetent_not_isTop( self ):
+        self.assertEqual(
+            self._NotCompetent_validate_check( False ),
+            None
+            )
+
     def testAllowGroupsAttribute(self):
         # Verify that __allow_groups__ gets set and removed
         from OFS.Folder import Folder



More information about the checkins mailing list