CVS: Products/PluggableAuthService/plugins/tests - ChallengeProtocolChooser.txt:1.4 test_ChallengeProtocolChooser.py:1.4 test_RequestTypeSniffer.py:1.4 test_doctests.py:1.4

Sidnei da Silva <[email protected]>
Newsgroups gmane.comp.web.zope.public-cvs
Message-ID <[email protected]>
Update of /cvs-repository/Products/PluggableAuthService/plugins/tests
In directory cvs.zope.org:/tmp/cvs-serv13697/plugins/tests

Added Files:
	ChallengeProtocolChooser.txt test_ChallengeProtocolChooser.py 
	test_RequestTypeSniffer.py test_doctests.py 
Log Message:

Merge changes from sidnei-challenge-protocol-chooser:

    - Added two new interfaces, IChallengeProtocolChooser and
      IRequestTypeSniffer. Those are used to select the 'authorization
      protocol' or 'challenger protocol' to be used for challenging
      according to the incoming request type.

    - Fixed a couple more places where Zope 2-style __implements__
      where being used to standardize on using classImplements.

    - Fixed fallback implementations of providedBy and
      implementedBy to always return a tuple.

    - Make sure challenge doesn't break if existing instances of the
      PluginRegistry don't yet have IChallengeProtocolChooser as a
      registered interface. (Would be nice to have some sort of
      migration for the PluginRegistry between PAS releases)

    - Don't assume that just because zope.interface can be imported
      that Five is present.


=== Products/PluggableAuthService/plugins/tests/ChallengeProtocolChooser.txt 1.3 => 1.4 ===
--- /dev/null	Wed Aug 17 16:53:44 2005
+++ Products/PluggableAuthService/plugins/tests/ChallengeProtocolChooser.txt	Wed Aug 17 16:53:14 2005
@@ -0,0 +1,268 @@
+Challenge Protocol Chooser
+--------------------------
+
+The Challenge Protocol Chooser is a plugin that decides what
+authentication protocol to use for a given request type.
+
+Let's start by setting up a PAS instance inside our existing test
+folder.
+
+  >>> folder = self.folder
+
+  >>> 'acl_users' in folder.objectIds()
+  True
+
+  >>> folder.manage_delObjects(ids=['acl_users'])
+
+  >>> 'acl_users' in folder.objectIds()
+  False
+
+  >>> dispatcher = folder.manage_addProduct['PluggableAuthService']
+  >>> dispatcher.addPluggableAuthService()
+
+  >>> 'acl_users' in folder.objectIds()
+  True
+
+  >>> folder.acl_users.meta_type
+  'Pluggable Auth Service'
+
+Now, we'll setup this PAS instance with what most people would get by
+default, users and roles stored in ZODB with HTTP Basic auth.
+
+  >>> pas = folder.acl_users
+
+  >>> dispatcher = pas.manage_addProduct['PluggableAuthService']
+
+  >>> dispatcher.addZODBUserManager('users')
+  >>> dispatcher.addZODBRoleManager('roles')
+  >>> dispatcher.addHTTPBasicAuthHelper('http_auth')
+
+  >>> plugins = pas.plugins
+
+  >>> from Products.PluggableAuthService.interfaces.plugins import \
+  ...   IAuthenticationPlugin, IUserEnumerationPlugin, IRolesPlugin, \
+  ...	IRoleEnumerationPlugin, IRoleAssignerPlugin, \
+  ...   IChallengePlugin, IExtractionPlugin, IUserAdderPlugin
+
+  >>> plugins.activatePlugin(IUserAdderPlugin, 'users')
+  >>> plugins.activatePlugin(IAuthenticationPlugin, 'users')
+  >>> plugins.activatePlugin(IUserEnumerationPlugin, 'users')
+  >>> plugins.activatePlugin(IRolesPlugin, 'roles')
+  >>> plugins.activatePlugin(IRoleEnumerationPlugin, 'roles')
+  >>> plugins.activatePlugin(IRoleAssignerPlugin, 'roles')
+  >>> plugins.activatePlugin(IExtractionPlugin, 'http_auth')
+  >>> plugins.activatePlugin(IChallengePlugin, 'http_auth')
+
+Create a user for testing:
+
+  >>> pas.getUserById('test_user_') is None
+  True
+
+  >>> username, password  = 'test_user_', 'test_user_pw'
+  >>> pas._doAddUser(username, password, ['Manager'], [])
+
+  >>> pas.getUserById('test_user_') is None
+  False
+
+We are now going to try some different kinds of requests and make sure
+all of them work. They all use HTTP Basic Auth, which is the default
+in this configuration we just set up. For the sake of testing, we are
+going to create a simple script that requires the 'Manager' role to be
+called.
+
+  >>> folder_name = folder.getId()
+  >>> dispatcher = folder.manage_addProduct['PythonScripts']
+  >>> _ = dispatcher.manage_addPythonScript('test_script')
+
+  >>> script = folder._getOb('test_script')
+  >>> script.write('return "Access Granted"')
+  >>> script.manage_permission(permission_to_manage='View',
+  ...                          roles=['Manager'], acquire=0)
+
+Access the script through a simple ``GET`` request, simulating browser
+access. Anonymous user should be challenged with a 401 response
+status.
+
+  >>> print http(r"""
+  ... GET /%s/test_script HTTP/1.1
+  ... """ % (folder_name), handle_errors=False)
+  HTTP/1.1 401 Unauthorized...
+
+With the right credentials though the request should succeed:
+
+  >>> print http(r"""
+  ... GET /%s/test_script HTTP/1.1
+  ... Authorization: Basic %s:%s
+  ... """ % (folder_name, username, password), handle_errors=False)
+  HTTP/1.1 200 OK
+  ...
+  Access Granted
+
+Now a PROPFIND request, simulating a WebDAV client. Anonymous user
+should be challenged with a 401 response status:
+
+  >>> print http(r"""
+  ... PROPFIND /%s/test_script HTTP/1.1
+  ... """ % (folder_name), handle_errors=False)
+  HTTP/1.1 401 Unauthorized...
+
+And with the right credentials the request should succeed:
+
+  >>> print http(r"""
+  ... PROPFIND /%s/test_script HTTP/1.1
+  ... Authorization: Basic %s:%s
+  ... """ % (folder_name, username, password), handle_errors=False)
+  HTTP/1.1 207 Multi-Status...
+
+  >>> print http(r"""
+  ... GET /%s/test_script/manage_DAVget HTTP/1.1
+  ... Authorization: Basic %s:%s
+  ... """ % (folder_name, username, password), handle_errors=False)
+  HTTP/1.1 200 OK...
+
+And a XML-RPC Request. Again, Anonymous user should be challenged with
+a 401 response status.
+
+  >>> print http(r"""
+  ... POST /%s HTTP/1.1
+  ... Content-Type: text/xml; charset="utf-8"
+  ... <?xml version="1.0"?>
+  ... <methodCall>
+  ... <methodName>test_script</methodName>
+  ... </methodCall>
+  ... """ % (folder_name), handle_errors=False)
+  HTTP/1.1 401 Unauthorized...
+
+And with valid credentials the reqeuest should succeed:
+
+  >>> print http(r"""
+  ... POST /%s HTTP/1.1
+  ... Content-Type: text/xml; charset="utf-8"
+  ... Authorization: Basic %s:%s
+  ... <?xml version="1.0"?>
+  ... <methodCall>
+  ... <methodName>test_script</methodName>
+  ... </methodCall>
+  ... """ % (folder_name, username, password), handle_errors=False)
+  HTTP/1.1 200 OK
+  Content-Length: 140
+  Content-Type: text/xml
+  <BLANKLINE>
+  <?xml version='1.0'?>
+  <methodResponse>
+  <params>
+  <param>
+  <value><string>Access Granted</string></value>
+  </param>
+  </params>
+  </methodResponse>
+
+Adding a Cookie Auth Helper now to test the correct behaviour of the
+Challenge Protocol Helper.
+
+  >>> dispatcher = pas.manage_addProduct['PluggableAuthService']
+  >>> dispatcher.addCookieAuthHelper('cookie_auth',
+  ...                                cookie_name='__ac')
+
+  >>> plugins.activatePlugin(IExtractionPlugin, 'cookie_auth')
+  >>> plugins.activatePlugin(IChallengePlugin, 'cookie_auth')
+
+Re-activate HTTP Auth Helper so that it appears **after** Cookie Auth
+Helper:
+
+  >>> plugins.deactivatePlugin(IExtractionPlugin, 'http_auth')
+  >>> plugins.activatePlugin(IExtractionPlugin, 'http_auth')
+  >>> plugins.deactivatePlugin(IChallengePlugin, 'http_auth')
+  >>> plugins.activatePlugin(IChallengePlugin, 'http_auth')
+
+Now, invalid credentials should result in a 302 response status for a
+normal (eg: browser) request:
+
+  >>> print http(r"""
+  ... GET /%s/test_script HTTP/1.1
+  ... """ % (folder_name), handle_errors=False)
+  HTTP/1.1 302 Moved Temporarily...
+
+And the same for a WebDAV request:
+
+  >>> print http(r"""
+  ... PROPFIND /%s/test_script HTTP/1.1
+  ... """ % (folder_name), handle_errors=False)
+  HTTP/1.1 302 Moved Temporarily...
+
+  >>> print http(r"""
+  ... GET /%s/test_script/manage_DAVget HTTP/1.1
+  ... """ % (folder_name), handle_errors=False)
+  HTTP/1.1 302 Moved Temporarily...
+
+And for a XML-RPC request:
+
+  >>> print http(r"""
+  ... POST /%s HTTP/1.1
+  ... Content-Type: text/xml; charset="utf-8"
+  ... <?xml version="1.0"?>
+  ... <methodCall>
+  ... <methodName>test_script</methodName>
+  ... </methodCall>
+  ... """ % (folder_name), handle_errors=False)
+  HTTP/1.1 302 Moved Temporarily...
+
+However, not all WebDAV and XML-RPC clients understand the
+redirect. Even worse, they will not be able to display the login form
+that is the target of this redirect.
+
+For this reason we should disable the Cookie Auth Helper for
+non-browser requests. In fact, we might only want plugins that
+understand the 'http' authorization protocol to issue challenges for
+WebDAV and XML-RPC.
+
+To do this, we use the Challenge Protocol Chooser plugin together with
+the Request Type Sniffer plugin.
+
+  >>> from Products.PluggableAuthService.interfaces.plugins import \
+  ...   IRequestTypeSniffer, IChallengeProtocolChooser
+
+  >>> dispatcher = pas.manage_addProduct['PluggableAuthService']
+
+  >>> dispatcher.addRequestTypeSnifferPlugin('sniffer')
+  >>> plugins.activatePlugin(IRequestTypeSniffer, 'sniffer')
+
+  >>> mapping = {'WebDAV': ['http'],
+  ...            'XML-RPC': ['http'],
+  ...		 'Browser': []}
+
+  >>> dispatcher.addChallengeProtocolChooserPlugin('chooser',
+  ...                                              mapping=mapping)
+  >>> plugins.activatePlugin(IChallengeProtocolChooser, 'chooser')
+
+Now, invalid credentials should result in a 302 response status for a
+normal (eg: browser) request:
+
+  >>> print http(r"""
+  ... GET /%s/test_script HTTP/1.1
+  ... """ % (folder_name), handle_errors=False)
+  HTTP/1.1 302 Moved Temporarily...
+
+A WebDAV request should result in a 401 response status:
+
+  >>> print http(r"""
+  ... PROPFIND /%s/test_script HTTP/1.1
+  ... """ % (folder_name), handle_errors=False)
+  HTTP/1.1 401 Unauthorized...
+
+  >>> print http(r"""
+  ... GET /%s/test_script/manage_DAVget HTTP/1.1
+  ... """ % (folder_name), handle_errors=False)
+  HTTP/1.1 401 Unauthorized...
+
+And a XML-RPC request should also result in a 401 response status:
+
+  >>> print http(r"""
+  ... POST /%s HTTP/1.1
+  ... Content-Type: text/xml; charset="utf-8"
+  ... <?xml version="1.0"?>
+  ... <methodCall>
+  ... <methodName>test_script</methodName>
+  ... </methodCall>
+  ... """ % (folder_name), handle_errors=False)
+  HTTP/1.1 401 Unauthorized...


=== Products/PluggableAuthService/plugins/tests/test_ChallengeProtocolChooser.py 1.3 => 1.4 ===
--- /dev/null	Wed Aug 17 16:53:44 2005
+++ Products/PluggableAuthService/plugins/tests/test_ChallengeProtocolChooser.py	Wed Aug 17 16:53:14 2005
@@ -0,0 +1,48 @@
+##############################################################################
+#
+# Copyright (c) 2001 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.
+#
+##############################################################################
+""" Unit tests for ChallengeProtocolChooser
+
+$Id$
+"""
+import unittest
+
+from Products.PluggableAuthService.tests.conformance \
+    import IChallengeProtocolChooser_conformance
+
+class ChallengeProtocolChooser( unittest.TestCase
+                                , IChallengeProtocolChooser_conformance 
+                              ):
+
+
+    def _getTargetClass( self ):
+
+        from Products.PluggableAuthService.plugins.ChallengeProtocolChooser \
+            import ChallengeProtocolChooser
+
+        return ChallengeProtocolChooser
+
+    def _makeOne( self, id='test', *args, **kw ):
+
+        return self._getTargetClass()( id, *args, **kw )
+
+
+if __name__ == "__main__":
+    unittest.main()
+        
+def test_suite():
+    return unittest.TestSuite((
+        unittest.makeSuite( ChallengeProtocolChooser ),
+        ))
+        


=== Products/PluggableAuthService/plugins/tests/test_RequestTypeSniffer.py 1.3 => 1.4 ===
--- /dev/null	Wed Aug 17 16:53:44 2005
+++ Products/PluggableAuthService/plugins/tests/test_RequestTypeSniffer.py	Wed Aug 17 16:53:14 2005
@@ -0,0 +1,48 @@
+##############################################################################
+#
+# Copyright (c) 2001 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.
+#
+##############################################################################
+""" Unit tests for RequestTypeSniffer
+
+$Id$
+"""
+import unittest
+
+from Products.PluggableAuthService.tests.conformance \
+    import IRequestTypeSniffer_conformance
+
+class RequestTypeSniffer( unittest.TestCase
+                          , IRequestTypeSniffer_conformance 
+                        ):
+
+
+    def _getTargetClass( self ):
+
+        from Products.PluggableAuthService.plugins.RequestTypeSniffer \
+            import RequestTypeSniffer
+
+        return RequestTypeSniffer
+
+    def _makeOne( self, id='test', *args, **kw ):
+
+        return self._getTargetClass()( id, *args, **kw )
+
+
+if __name__ == "__main__":
+    unittest.main()
+        
+def test_suite():
+    return unittest.TestSuite((
+        unittest.makeSuite( RequestTypeSniffer ),
+        ))
+        


=== Products/PluggableAuthService/plugins/tests/test_doctests.py 1.3 => 1.4 ===
--- /dev/null	Wed Aug 17 16:53:44 2005
+++ Products/PluggableAuthService/plugins/tests/test_doctests.py	Wed Aug 17 16:53:14 2005
@@ -0,0 +1,32 @@
+##############################################################################
+#
+# Copyright (c) 2001 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.
+#
+##############################################################################
+
+import unittest
+from Testing import ZopeTestCase
+
+ZopeTestCase.installProduct('PythonScripts')
+ZopeTestCase.installProduct('PluginRegistry')
+ZopeTestCase.installProduct('PluggableAuthService')
+
+def test_suite():
+    suite = unittest.TestSuite()
+    package = 'Products.PluggableAuthService.plugins.tests'
+    tests = [
+        ZopeTestCase.FunctionalDocFileSuite('ChallengeProtocolChooser.txt',
+                                            package=package),
+        ]
+    for t in tests:
+        suite.addTest(t)
+    return suite

_______________________________________________
Zope-CVS maillist  -  [email protected]
http://mail.zope.org/mailman/listinfo/zope-cvs

Zope CVS instructions: http://dev.zope.org/CVS
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.