[Checkins] SVN: z3c.authviewlet/ - added initial implementation, moved from z3c.layer.pagelet package
Roger Ineichen
roger at projekt01.ch
Mon Nov 30 11:03:19 EST 2009
Log message for revision 106124:
- added initial implementation, moved from z3c.layer.pagelet package
- prepare for release
Changed:
A z3c.authviewlet/branches/
A z3c.authviewlet/tags/
A z3c.authviewlet/trunk/
A z3c.authviewlet/trunk/CHANGES.txt
A z3c.authviewlet/trunk/LICENSE.txt
A z3c.authviewlet/trunk/README.txt
A z3c.authviewlet/trunk/bootstrap.py
A z3c.authviewlet/trunk/buildout.cfg
A z3c.authviewlet/trunk/setup.py
A z3c.authviewlet/trunk/src/
A z3c.authviewlet/trunk/src/z3c/
A z3c.authviewlet/trunk/src/z3c/__init__.py
A z3c.authviewlet/trunk/src/z3c/authviewlet/
A z3c.authviewlet/trunk/src/z3c/authviewlet/README.txt
A z3c.authviewlet/trunk/src/z3c/authviewlet/__init__.py
A z3c.authviewlet/trunk/src/z3c/authviewlet/browser/
A z3c.authviewlet/trunk/src/z3c/authviewlet/browser/__init__.py
A z3c.authviewlet/trunk/src/z3c/authviewlet/browser/auth.py
A z3c.authviewlet/trunk/src/z3c/authviewlet/browser/configure.zcml
A z3c.authviewlet/trunk/src/z3c/authviewlet/browser/login_failed.pt
A z3c.authviewlet/trunk/src/z3c/authviewlet/browser/login_success.pt
A z3c.authviewlet/trunk/src/z3c/authviewlet/browser/logout.pt
A z3c.authviewlet/trunk/src/z3c/authviewlet/browser/logout_head.pt
A z3c.authviewlet/trunk/src/z3c/authviewlet/browser/redirect.pt
A z3c.authviewlet/trunk/src/z3c/authviewlet/browser/redirect_head.pt
A z3c.authviewlet/trunk/src/z3c/authviewlet/browser/session_cred_loginform.pt
A z3c.authviewlet/trunk/src/z3c/authviewlet/configure.zcml
A z3c.authviewlet/trunk/src/z3c/authviewlet/tests/
A z3c.authviewlet/trunk/src/z3c/authviewlet/tests/__init__.py
A z3c.authviewlet/trunk/src/z3c/authviewlet/tests/ftesting.zcml
A z3c.authviewlet/trunk/src/z3c/authviewlet/tests/login-logout-template.pt
A z3c.authviewlet/trunk/src/z3c/authviewlet/tests/test_layer.py
-=-
Property changes on: z3c.authviewlet/trunk
___________________________________________________________________
Added: svn:ignore
+ .installed.cfg
bin
develop-eggs
parts
Added: z3c.authviewlet/trunk/CHANGES.txt
===================================================================
--- z3c.authviewlet/trunk/CHANGES.txt (rev 0)
+++ z3c.authviewlet/trunk/CHANGES.txt 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,12 @@
+=======
+CHANGES
+=======
+
+0.5.0 (2009-11-30)
+------------------
+
+- moved authentication viewlet implementation from z3c.layer.pagelet to this
+ package. Not sure but probably we should skip the dependency to
+ zope.app.publisher.interfaces.http and use and define own interfaces.
+
+- initial release.
Added: z3c.authviewlet/trunk/LICENSE.txt
===================================================================
--- z3c.authviewlet/trunk/LICENSE.txt (rev 0)
+++ z3c.authviewlet/trunk/LICENSE.txt 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,54 @@
+Zope Public License (ZPL) Version 2.1
+-------------------------------------
+
+A copyright notice accompanies this license document that
+identifies the copyright holders.
+
+This license has been certified as open source. It has also
+been designated as GPL compatible by the Free Software
+Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the
+following conditions are met:
+
+1. Redistributions in source code must retain the
+ accompanying copyright notice, this list of conditions,
+ and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the accompanying
+ copyright notice, this list of conditions, and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+3. Names of the copyright holders must not be used to
+ endorse or promote products derived from this software
+ without prior written permission from the copyright
+ holders.
+
+4. The right to distribute this software or to use it for
+ any purpose does not give you the right to use
+ Servicemarks (sm) or Trademarks (tm) of the copyright
+ holders. Use of them is covered by separate agreement
+ with the copyright holders.
+
+5. If any files are modified, you must cause the modified
+ files to carry prominent notices stating that you changed
+ the files and the date of any change.
+
+Disclaimer
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS''
+ AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ NO EVENT SHALL THE COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
Added: z3c.authviewlet/trunk/README.txt
===================================================================
--- z3c.authviewlet/trunk/README.txt (rev 0)
+++ z3c.authviewlet/trunk/README.txt 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1 @@
+This package provides an authentication viewlet implementation for Zope3.
Added: z3c.authviewlet/trunk/bootstrap.py
===================================================================
--- z3c.authviewlet/trunk/bootstrap.py (rev 0)
+++ z3c.authviewlet/trunk/bootstrap.py 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# Copyright (c) 2006 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.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id: bootstrap.py 35779 2007-03-22 16:08:07Z batlogg $
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+ez = {}
+exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+ ).read() in ez
+ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+import pkg_resources
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+ cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+assert os.spawnle(
+ os.P_WAIT, sys.executable, sys.executable,
+ '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+ dict(os.environ,
+ PYTHONPATH=
+ ws.find(pkg_resources.Requirement.parse('setuptools')).location
+ ),
+ ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)
Added: z3c.authviewlet/trunk/buildout.cfg
===================================================================
--- z3c.authviewlet/trunk/buildout.cfg (rev 0)
+++ z3c.authviewlet/trunk/buildout.cfg 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,22 @@
+[buildout]
+develop = .
+parts = test checker coverage-test coverage-report
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = z3c.authviewlet [test]
+ z3c.layer.pagelet [test]
+
+[checker]
+recipe = lovely.recipe:importchecker
+path = src/z3c/authviewlet
+
+[coverage-test]
+recipe = zc.recipe.testrunner
+eggs = ${test:eggs}
+defaults = ['--coverage', '../../coverage']
+
+[coverage-report]
+recipe = zc.recipe.egg
+eggs = z3c.coverage
+scripts = coverage=coverage-report
Added: z3c.authviewlet/trunk/setup.py
===================================================================
--- z3c.authviewlet/trunk/setup.py (rev 0)
+++ z3c.authviewlet/trunk/setup.py 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,76 @@
+##############################################################################
+#
+# Copyright (c) 2007-2009 Zope Foundation 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.
+#
+##############################################################################
+"""Setup"""
+
+import os
+from setuptools import setup, find_packages
+
+def read(*rnames):
+ return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+
+setup(
+ name='z3c.authviewlet',
+ version='0.5.0',
+ author='Zope Foundation and Contributors',
+ author_email='zope-dev at zope.org',
+ description = "Authentication viewlet for Zope3",
+ long_description=(
+ read('README.txt')
+ + '\n\n' +
+ '.. contents::'
+ + '\n\n' +
+ read('src', 'z3c', 'authviewlet', 'README.txt')
+ + '\n\n' +
+ read('CHANGES.txt')
+ ),
+ keywords = "z3c authentication viewlet zope zope3",
+ classifiers = [
+ 'Development Status :: 5 - Production/Stable',
+ 'Environment :: Web Environment',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: Zope Public License',
+ 'Programming Language :: Python',
+ 'Natural Language :: English',
+ 'Operating System :: OS Independent',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Framework :: Zope3'],
+ url='http://pypi.python.org/pypi/z3c.authviewlet',
+ license='ZPL 2.1',
+ packages = find_packages('src'),
+ include_package_data = True,
+ package_dir = {'':'src'},
+ namespace_packages = ['z3c',],
+ extras_require = dict(
+ test = [
+ 'zope.testbrowser',
+ 'z3c.layer.pagelet',
+ 'zope.app.testing',
+ 'zope.testing',
+ ],
+ ),
+ install_requires = [
+ 'setuptools',
+ 'z3c.layer.pagelet',
+ 'zope.app.publisher',
+ 'zope.authentication',
+ 'zope.component',
+ 'zope.i18n',
+ 'zope.i18nmessageid',
+ 'zope.interface',
+ 'zope.viewlet',
+ ],
+ zip_safe = False,
+)
+
Property changes on: z3c.authviewlet/trunk/src
___________________________________________________________________
Added: svn:ignore
+ z3c.authviewlet.egg-info
Added: z3c.authviewlet/trunk/src/z3c/__init__.py
===================================================================
--- z3c.authviewlet/trunk/src/z3c/__init__.py (rev 0)
+++ z3c.authviewlet/trunk/src/z3c/__init__.py 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,7 @@
+# this is a namespace package
+try:
+ import pkg_resources
+ pkg_resources.declare_namespace(__name__)
+except ImportError:
+ import pkgutil
+ __path__ = pkgutil.extend_path(__path__, __name__)
Added: z3c.authviewlet/trunk/src/z3c/authviewlet/README.txt
===================================================================
--- z3c.authviewlet/trunk/src/z3c/authviewlet/README.txt (rev 0)
+++ z3c.authviewlet/trunk/src/z3c/authviewlet/README.txt 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,613 @@
+Login and logout
+----------------
+
+Login and logout work both for basic auth and cookie auth.
+
+
+Setup
+~~~~~
+
+The layout page template has to include two content providers (viewlet
+mangers):
+
+ - ``login-logout-head`` inside the head tag to get automatic
+ redirects and JavaScript code which does the logout for basic
+ auth and
+
+ - ``login-logout`` inside the body tag to get login and logout links.
+
+The sample template looks like this:
+
+ >>> import os.path
+ >>> template_path = os.path.join(os.path.dirname(__file__), "tests",
+ ... "login-logout-template.pt")
+ >>> print file(template_path, "r").read()
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTest</title>
+ <tal:block replace="structure provider:login-logout-head" />
+ </head>
+ <body>
+ <tal:block replace="structure provider:login-logout" />
+ <tal:block replace="structure provider:pagelet" />
+ </body>
+ </html>
+
+This template is registered for the ``IContainer`` interface in
+``ftesting.zcml``. After creating a container the template is
+used when browsing the container:
+
+ >>> from zope.container.btree import BTreeContainer
+ >>> getRootFolder()['container'] = BTreeContainer()
+
+Basic auth
+~~~~~~~~~~
+
+When the user is not logged in the login link is displayed:
+
+ >>> from zope.testbrowser.testing import Browser
+ >>> skinURL = 'http://localhost/++skin++PageletTestSkin/'
+ >>> browser = Browser()
+ >>> browser.handleErrors = False
+ >>> browser.open(skinURL + 'container/@@default.html')
+ >>> browser.url
+ 'http://localhost/++skin++PageletTestSkin/container/@@default.html'
+ >>> print browser.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTest</title>
+ </head>
+ <body>
+ <a href="http://localhost/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Login</a>
+ </body>
+ </html>
+
+Selecting the link leads to the login page, as we use basic auth here,
+we get an HTTP error 401 (unauthorized):
+
+ >>> login_url = browser.getLink('Login').url
+ >>> browser.getLink('Login').click()
+ Traceback (most recent call last):
+ httperror_seek_wrapper: HTTP Error 401: Unauthorized
+ >>> browser.url
+ 'http://localhost/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html'
+
+When adding correct credentials we get authorized:
+
+ >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+ >>> browser.reload()
+
+We are redirected to the page where we selected the login link. After
+logging in the login link is no longer displayed. As we did not
+specify that logout is supported, no logout link is displayed:
+
+ >>> browser.url
+ 'http://localhost/++skin++PageletTestSkin/container/@@default.html'
+ >>> print browser.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTest</title>
+ </head>
+ <body>
+ </body>
+ </html>
+
+Calling the login URL again leads directly to the page referred in nextURL:
+
+ >>> browser.open(login_url)
+ >>> browser.url
+ 'http://localhost/++skin++PageletTestSkin/container/@@default.html'
+ >>> print browser.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTest</title>
+ </head>
+ <body>
+ </body>
+ </html>
+
+Calling the login URL again without the query parameter leeds to a
+confirmation page telling that login was successfull:
+
+ >>> browser.open(login_url.split('?')[0])
+ >>> browser.url
+ 'http://localhost/++skin++PageletTestSkin/container/@@login.html'
+ >>> print browser.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTestLayout</title>
+ </head>
+ <body>
+ <div>
+ <h1>Login successful!</h1>
+ <p style="font-size: 200%"> You are now logged in as <em>Manager</em>. </p>
+ <a href=".">Back to the main page.</a>
+ </div>
+ </body>
+ </html>
+
+Selecting the ``Back to the main page.`` link send the user back to
+the default view of the container. (``ftesting.zcml`` defines
+``@@default.html`` as the default view.):
+
+ >>> browser.getLink('Back to the main page.').click()
+ >>> browser.url
+ 'http://localhost/++skin++PageletTestSkin/container/'
+ >>> print browser.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTest</title>
+ </head>
+ <body>
+ </body>
+ </html>
+
+
+Providing an ``ILogoutSupported`` adapter leads to a logout link being
+displayed:
+
+ >>> from zope.app.testing import ztapi
+ >>> import zope.interface
+ >>> import zope.authentication.logout
+ >>> import zope.authentication.interfaces
+ >>> ztapi.provideAdapter(
+ ... zope.interface.Interface,
+ ... zope.authentication.interfaces.ILogoutSupported,
+ ... zope.authentication.logout.LogoutSupported)
+ >>> browser.reload()
+ >>> browser.url
+ 'http://localhost/++skin++PageletTestSkin/container/'
+ >>> print browser.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTest</title>
+ </head>
+ <body>
+ <a href="http://localhost/++skin++PageletTestSkin/container/@@logout.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Logout</a>
+ </body>
+ </html>
+
+Logout is done using JavaScript and a redirect. zope.testbrowser
+follows the redirects even if they use the meta tag instead of the
+status code. So I have to use a non API call to change this behavior
+to show the file contents:
+
+ >>> browser.mech_browser.set_handle_refresh(False)
+
+As testbrowser is not able to execute JavaScript the user remains
+authenticated:
+
+ >>> logout_url = browser.getLink('Logout').url
+ >>> browser.getLink('Logout').click()
+ >>> browser.url
+ 'http://localhost/++skin++PageletTestSkin/container/@@logout.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html'
+ >>> print browser.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTest</title>
+ <script type="text/javascript"><!--
+ // clear HTTP Authentication
+ ...
+ //-->
+ </script>
+ <meta http-equiv="refresh"
+ content="0;url=http://localhost/++skin++PageletTestSkin/container/@@default.html" />
+ </head>
+ <body>
+ <a href="http://localhost/++skin++PageletTestSkin/container/@@logout.html/@@logout.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40logout.html">Logout</a>
+ <div>
+ <h1>You are being redirected!</h1>
+ <p style="font-size: 150%">
+ <a href="http://localhost/++skin++PageletTestSkin/container/@@default.html">
+ If you see this screen for more than 5 seconds, click here.
+ </a>
+ </p>
+ </div>
+ </body>
+ </html>
+
+Calling the logout URL again after logout (simulated using a new
+browser instance) leads directly to the page referred in nextURL:
+
+ >>> browser2 = Browser(logout_url)
+ >>> browser2.url
+ 'http://localhost/++skin++PageletTestSkin/container/@@default.html'
+ >>> print browser2.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTest</title>
+ </head>
+ <body>
+ <a href="http://localhost/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Login</a>
+ </body>
+ </html>
+
+Calling the logout URL again without the query parameter leeds to a
+confirmation page telling that logout was successfull:
+
+ >>> browser2.open(logout_url.split('?')[0])
+ >>> browser2.url
+ 'http://localhost/++skin++PageletTestSkin/container/@@logout.html'
+ >>> print browser2.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTest</title>
+ <script type="text/javascript"><!--
+ // clear HTTP Authentication
+ ...
+ //-->
+ </script>
+ </head>
+ <body>
+ <a href="http://localhost/++skin++PageletTestSkin/container/logout.html/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40logout.html">Login</a>
+ <div>
+ <h1>Logout successful!</h1>
+ <p style="font-size: 200%">
+ You are now logged out.
+ </p>
+ <a href=".">Back to the main page.</a>
+ </div>
+ </body>
+ </html>
+
+
+Cookie auth
+~~~~~~~~~~~
+
+To do cookie auth we have to set up a pluggable auth utility (PAU)
+with a authenticator plug-in (principal folder) first:
+
+ >>> from zope.authentication.interfaces import IAuthentication
+ >>> from zope.app.authentication.interfaces import IAuthenticatorPlugin
+ >>> from zope.app.authentication.authentication import PluggableAuthentication
+ >>> from zope.app.authentication.principalfolder import PrincipalFolder
+ >>> from zope.site import site
+
+ >>> root = getRootFolder()
+ >>> root['principal_folder'] = PrincipalFolder()
+ >>> sm = root.getSiteManager()
+ >>> sm.registerUtility(
+ ... root['principal_folder'], IAuthenticatorPlugin, 'principal_folder')
+
+ >>> root['auth'] = PluggableAuthentication()
+ >>> sm.registerUtility(root['auth'], IAuthentication, '')
+ >>> root['auth'].credentialsPlugins = (u'Session Credentials',)
+ >>> root['auth'].authenticatorPlugins = (u'principal_folder',)
+
+We need a principal inside the principal folder:
+
+ >>> from zope.app.authentication.principalfolder import InternalPrincipal
+ >>> root['principal_folder']['1'] = InternalPrincipal(
+ ... 'tester', 'tpass', 'Tester')
+
+
+We use a new browser, so the principal is not logged in and the login
+link is displayed:
+
+ >>> browser = Browser()
+ >>> browser.open(skinURL + 'container/@@default.html')
+ >>> browser.url
+ 'http://localhost/++skin++PageletTestSkin/container/@@default.html'
+ >>> print browser.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTest</title>
+ </head>
+ <body>
+ <a href="http://localhost/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Login</a>
+ </body>
+ </html>
+
+Selecting the link leads to the login page:
+
+ >>> login_url = browser.getLink('Login').url
+ >>> browser.getLink('Login').click()
+ >>> browser.url
+ 'http://localhost/++skin++PageletTestSkin/@@loginForm.html?camefrom=%2F%2B%2Bskin%2B%2BPageletTestSkin%2Fcontainer%2F%40%40login.html%3FnextURL%3Dhttp%253A%2F%2Flocalhost%2F%252B%252Bskin%252B%252BPageletTestSkin%2Fcontainer%2F%2540%2540default.html'
+ >>> print browser.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTestLayout</title>
+ </head>
+ <body>
+ <div>
+ <p>
+ Please provide Login Information
+ </p>
+ <form action="" method="post">
+ <div class="row">
+ <div class="label"><label for="login">User Name</label></div>
+ <div class="field">
+ <input type="text" name="login" id="login" />
+ </div>
+ </div>
+ <div class="row">
+ <div class="label"><label for="password">Password</label></div>
+ <div class="field">
+ <input type="password" name="password" id="password" />
+ </div>
+ </div>
+ <div class="row">
+ <input class="form-element" type="submit"
+ name="SUBMIT" value="Log in" />
+ </div>
+ <input type="hidden" name="camefrom"
+ value="/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">
+ </form>
+ </div>
+ </body>
+ </html>
+
+Entering wrong username does not authorize but display an error
+message:
+
+ >>> browser.getControl('User Name').value = 'me'
+ >>> browser.getControl('Password').value = 'tpass'
+ >>> browser.getControl('Log in').click()
+ >>> browser.url
+ 'http://localhost/++skin++PageletTestSkin/@@loginForm.html?camefrom=%2F%2B%2Bskin%2B%2BPageletTestSkin%2Fcontainer%2F%40%40login.html%3FnextURL%3Dhttp%253A%2F%2Flocalhost%2F%252B%252Bskin%252B%252BPageletTestSkin%2Fcontainer%2F%2540%2540default.html'
+ >>> print browser.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTestLayout</title>
+ </head>
+ <body>
+ <div>
+ <p>
+ Please provide Login Information
+ </p>
+ <form action="" method="post">
+ <div class="row">
+ <div class="label"><label for="login">User Name</label></div>
+ <div class="field">
+ <input type="text" name="login" id="login" />
+ </div>
+ </div>
+ <div class="row">
+ <div class="label"><label for="password">Password</label></div>
+ <div class="field">
+ <input type="password" name="password" id="password" />
+ </div>
+ </div>
+ <div class="row">
+ <input class="form-element" type="submit"
+ name="SUBMIT" value="Log in" />
+ </div>
+ <input type="hidden" name="camefrom"
+ value="/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">
+ </form>
+ </div>
+ </body>
+ </html>
+
+Entering wrong password does not authorize either:
+
+ >>> browser.getControl('User Name').value = 'tester'
+ >>> browser.getControl('Password').value = 'let me in'
+ >>> browser.getControl('Log in').click()
+ >>> browser.url
+ 'http://localhost/++skin++PageletTestSkin/@@loginForm.html?camefrom=%2F%2B%2Bskin%2B%2BPageletTestSkin%2Fcontainer%2F%40%40login.html%3FnextURL%3Dhttp%253A%2F%2Flocalhost%2F%252B%252Bskin%252B%252BPageletTestSkin%2Fcontainer%2F%2540%2540default.html'
+ >>> print browser.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTestLayout</title>
+ </head>
+ <body>
+ <div>
+ <p>
+ Please provide Login Information
+ </p>
+ <form action="" method="post">
+ <div class="row">
+ <div class="label"><label for="login">User Name</label></div>
+ <div class="field">
+ <input type="text" name="login" id="login" />
+ </div>
+ </div>
+ <div class="row">
+ <div class="label"><label for="password">Password</label></div>
+ <div class="field">
+ <input type="password" name="password" id="password" />
+ </div>
+ </div>
+ <div class="row">
+ <input class="form-element" type="submit"
+ name="SUBMIT" value="Log in" />
+ </div>
+ <input type="hidden" name="camefrom"
+ value="/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">
+ </form>
+ </div>
+ </body>
+ </html>
+
+
+After entering a correct username and password the user gets
+authorized:
+
+ >>> browser.getControl('User Name').value = 'tester'
+ >>> browser.getControl('Password').value = 'tpass'
+ >>> browser.getControl('Log in').click()
+
+The user gets redirected to the page where he selected the login
+link. After logging in the login link is no longer displayed. As we
+already specified that logout is supported, a logout link is
+displayed:
+
+ >>> browser.url
+ 'http://localhost/++skin++PageletTestSkin/container/@@default.html'
+ >>> print browser.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTest</title>
+ </head>
+ <body>
+ <a href="http://localhost/++skin++PageletTestSkin/container/@@logout.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Logout</a>
+ </body>
+ </html>
+
+
+Calling the login URL again leads directly to the page referred in nextURL:
+
+ >>> browser.open(login_url)
+ >>> browser.url
+ 'http://localhost/++skin++PageletTestSkin/container/@@default.html'
+ >>> print browser.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTest</title>
+ </head>
+ <body>
+ <a href="http://localhost/++skin++PageletTestSkin/container/@@logout.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Logout</a>
+ </body>
+ </html>
+
+Calling the login URL again without the query parameter leeds to a
+confirmation page telling that login was successfull:
+
+ >>> browser.open(login_url.split('?')[0])
+ >>> browser.url
+ 'http://localhost/++skin++PageletTestSkin/container/@@login.html'
+ >>> print browser.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTestLayout</title>
+ </head>
+ <body>
+ <div>
+ <h1>Login successful!</h1>
+ <p style="font-size: 200%"> You are now logged in as <em>Tester</em>. </p>
+ <a href=".">Back to the main page.</a>
+ </div>
+ </body>
+ </html>
+
+Selecting the ``Back to the main page.`` link send the user back to
+the default view of the container. (``ftesting.zcml`` defines
+``@@default.html`` as the default view.):
+
+ >>> browser.getLink('Back to the main page.').click()
+ >>> browser.url
+ 'http://localhost/++skin++PageletTestSkin/container/'
+ >>> print browser.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTest</title>
+ </head>
+ <body>
+ <a href="http://localhost/++skin++PageletTestSkin/container/@@logout.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Logout</a>
+ </body>
+ </html>
+
+
+Selecting the displayed logout link drops authentication information
+and displays a confirmation page, which redirects to the default page
+where the login link is displayed again (as redirection is done
+automatically by testbrowser I have to use the non API call trick
+again to show the displayed page):
+
+ >>> browser.mech_browser.set_handle_refresh(False)
+ >>> logout_url = browser.getLink('Logout').url
+ >>> browser.getLink('Logout').click()
+ >>> print browser.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTest</title>
+ <script type="text/javascript"><!--
+ // clear HTTP Authentication
+ ...
+ //-->
+ </script>
+ <meta http-equiv="refresh"
+ content="0;url=http://localhost/++skin++PageletTestSkin/container/@@default.html" />
+ </head>
+ <body>
+ <a href="http://localhost/++skin++PageletTestSkin/container/@@logout.html/@@logout.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40logout.html">Logout</a>
+ <div>
+ <h1>You are being redirected!</h1>
+ <BLANKLINE>
+ <p style="font-size: 150%">
+ <a href="http://localhost/++skin++PageletTestSkin/container/@@default.html">
+ If you see this screen for more than 5 seconds, click here.
+ </a>
+ </p>
+ </div>
+ </body>
+ </html>
+ >>> browser.getLink('If you see this screen for more than 5 seconds').click()
+ >>> print browser.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTest</title>
+ </head>
+ <body>
+ <a href="http://localhost/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Login</a>
+ </body>
+ </html>
+ >>> browser.mech_browser.set_handle_refresh(True)
+
+Calling the logout URL again after logout leads directly to the page
+referred in nextURL:
+
+ >>> browser.open(logout_url)
+ >>> browser.url
+ 'http://localhost/++skin++PageletTestSkin/container/@@default.html'
+ >>> print browser.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTest</title>
+ </head>
+ <body>
+ <a href="http://localhost/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Login</a>
+ </body>
+ </html>
+
+Calling the logout URL again without the query parameter leeds to a
+confirmation page telling that logout was successfull:
+
+ >>> browser.open(logout_url.split('?')[0])
+ >>> browser.url
+ 'http://localhost/++skin++PageletTestSkin/container/@@logout.html'
+ >>> print browser.contents
+ <!DOCTYPE ...>
+ <html ...>
+ <head>
+ <title>PageletTest</title>
+ <script type="text/javascript"><!--
+ // clear HTTP Authentication
+ ...
+ //-->
+ </script>
+ </head>
+ <body>
+ <a href="http://localhost/++skin++PageletTestSkin/container/logout.html/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40logout.html">Login</a>
+ <div>
+ <h1>Logout successful!</h1>
+ <p style="font-size: 200%">
+ You are now logged out.
+ </p>
+ <a href=".">Back to the main page.</a>
+ </div>
+ </body>
+ </html>
Added: z3c.authviewlet/trunk/src/z3c/authviewlet/__init__.py
===================================================================
--- z3c.authviewlet/trunk/src/z3c/authviewlet/__init__.py (rev 0)
+++ z3c.authviewlet/trunk/src/z3c/authviewlet/__init__.py 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1 @@
+# make a package
Added: z3c.authviewlet/trunk/src/z3c/authviewlet/browser/__init__.py
===================================================================
--- z3c.authviewlet/trunk/src/z3c/authviewlet/browser/__init__.py (rev 0)
+++ z3c.authviewlet/trunk/src/z3c/authviewlet/browser/__init__.py 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1 @@
+# make a package
Added: z3c.authviewlet/trunk/src/z3c/authviewlet/browser/auth.py
===================================================================
--- z3c.authviewlet/trunk/src/z3c/authviewlet/browser/auth.py (rev 0)
+++ z3c.authviewlet/trunk/src/z3c/authviewlet/browser/auth.py 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,174 @@
+##############################################################################
+#
+# Copyright (c) 2003-2009 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.
+#
+##############################################################################
+"""Login and Logout screens
+
+$Id:$
+"""
+import urllib
+import z3c.pagelet.interfaces
+import zope.app.publisher.interfaces.http
+import zope.authentication.interfaces
+import zope.component
+import zope.i18n
+import zope.i18nmessageid
+import zope.interface
+import zope.viewlet.interfaces
+import zope.viewlet.manager
+import zope.viewlet.viewlet
+
+_ = zope.i18nmessageid.MessageFactory("z3c")
+
+
+class ILoginLogoutHeadViewletManager(zope.viewlet.interfaces.IViewletManager):
+ """ViewletManager for supporting header contents (e. g. JavaScript)."""
+
+
+LoginLogoutHeadViewletManager = zope.viewlet.manager.ViewletManager(
+ 'login-logout-head', ILoginLogoutHeadViewletManager)
+
+
+class ILoginLogoutViewletManager(zope.viewlet.interfaces.IViewletManager):
+ """ViewletManager for login and logout viewlets."""
+
+
+LoginLogoutViewletManager = zope.viewlet.manager.ViewletManager(
+ 'login-logout', ILoginLogoutViewletManager,
+ bases=(zope.viewlet.manager.ConditionalViewletManager,))
+
+
+def authenticated(principal):
+ "Tell whether the principal is authenticated."
+ unauthenticated = zope.authentication.interfaces.IUnauthenticatedPrincipal
+ return not unauthenticated.providedBy(principal)
+
+
+def logout_supported(request):
+ "Tell whether logout is supported."
+ logout = zope.authentication.interfaces.ILogoutSupported(request, None)
+ return logout is not None
+
+
+def get_view_url(context, request, view_name):
+ "Compute the url of a view."
+ if view_name.startswith('@@'):
+ view_name = view_name[2:]
+ view_name_truncated = True
+ else:
+ view_name_truncated = False
+ view = zope.component.getMultiAdapter((context, request), name=view_name)
+ view_url = zope.component.getMultiAdapter(
+ (view, request), name='absolute_url')()
+ if view_name_truncated:
+ view_url = view_url.replace(view_name, '@@'+view_name)
+ return view_url
+
+
+def render_pagelet(context, request, view_name):
+ "Render a pagelet."
+ pagelet = zope.component.getMultiAdapter(
+ (context, request), z3c.pagelet.interfaces.IPagelet, name=view_name)
+ return pagelet()
+
+
+class LoginViewlet(zope.viewlet.viewlet.ViewletBase):
+ """Display login link when user is not logged in."""
+
+ @property
+ def available(self):
+ return not authenticated(self.request.principal)
+
+ def render(self):
+ return u'<a href="%s?nextURL=%s">%s</a>' % (
+ get_view_url(self. context, self.request, self.viewName),
+ urllib.quote(self.request.getURL()),
+ zope.i18n.translate(
+ _('[Login]', default='Login'), context=self.request))
+
+
+class LogoutViewlet(zope.viewlet.viewlet.ViewletBase):
+ """Display logout link when user is logged in and logout is supported."""
+
+ @property
+ def available(self):
+ return (
+ authenticated(self.request.principal)
+ and
+ logout_supported(self.request))
+
+ def render(self):
+ return u'<a href="%s?nextURL=%s">%s</a>' % (
+ get_view_url(self. context, self.request, self.viewName),
+ urllib.quote(self.request.getURL()),
+ zope.i18n.translate(
+ _('[Logout]', default='Logout'), context=self.request))
+
+
+class HTTPAuthenticationLogin(object):
+
+ zope.interface.implements(zope.app.publisher.interfaces.http.ILogin)
+
+ def login(self, nextURL=None):
+ # we don't want to keep challenging if we're authenticated
+ if not authenticated(self.request.principal):
+ auth = zope.component.getUtility(
+ zope.authentication.interfaces.IAuthentication)
+ auth.unauthorized(
+ self.request.principal.id, self.request)
+ return render_pagelet(self, self.request, 'login_failed.html')
+ else:
+ if nextURL is None:
+ return render_pagelet(self, self.request, 'login_success.html')
+ else:
+ self.request.response.redirect(nextURL)
+
+
+class LoginFailedPagelet(object):
+ "Pagelet to display login failed notice."
+
+
+class LoginSuccessfulPagelet(object):
+ "Pagelet to display login succecc notice."
+
+
+class HTTPAuthenticationLogout(object):
+ """Since HTTP Authentication really does not know about logout, we are
+ simply challenging the client again."""
+
+ zope.interface.implements(zope.authentication.interfaces.ILogout)
+
+ def logout(self, nextURL=None):
+ if authenticated(self.request.principal):
+ auth = zope.component.getUtility(
+ zope.authentication.interfaces.IAuthentication)
+ zope.authentication.interfaces.ILogout(auth).logout(self.request)
+ if nextURL:
+ return render_pagelet(self, self.request, 'redirect.html')
+ if nextURL is None:
+ return render_pagelet(self, self.request, 'logout_success.html')
+ else:
+ return self.request.response.redirect(nextURL)
+
+
+class LogoutRedirectPagelet(object):
+ "Pagelet to display logout redirect."
+
+
+class LogoutSuccessPagelet(object):
+ "Pagelet to display logout success."
+
+
+class SessionCredentialsLoginForm(object):
+ "Login form using session credentials."
+
+
Added: z3c.authviewlet/trunk/src/z3c/authviewlet/browser/configure.zcml
===================================================================
--- z3c.authviewlet/trunk/src/z3c/authviewlet/browser/configure.zcml (rev 0)
+++ z3c.authviewlet/trunk/src/z3c/authviewlet/browser/configure.zcml 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,170 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ xmlns:z3c="http://namespaces.zope.org/z3c"
+ i18n_domain="z3c">
+
+ <!-- viewlets in head tag supporting login and logout
+ (viewlets are defined together with the pagelets below) -->
+ <browser:viewletManager
+ provides=".auth.ILoginLogoutHeadViewletManager"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ name="login-logout-head"
+ class=".auth.LoginLogoutHeadViewletManager"
+ permission="zope.Public"
+ />
+
+ <!-- viewlet manager and viewlets for login and logout links -->
+ <browser:viewletManager
+ provides=".auth.ILoginLogoutViewletManager"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ name="login-logout"
+ class=".auth.LoginLogoutViewletManager"
+ permission="zope.Public"
+ />
+
+ <browser:viewlet
+ manager=".auth.ILoginLogoutViewletManager"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ name="Login"
+ class=".auth.LoginViewlet"
+ permission="zope.Public"
+ weight="1"
+ viewName="@@login.html"
+ />
+
+ <browser:viewlet
+ manager=".auth.ILoginLogoutViewletManager"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ name="Logout"
+ class=".auth.LogoutViewlet"
+ permission="zope.Public"
+ weight="2"
+ viewName="@@logout.html"
+ />
+
+ <!-- login page (executing login and redirecting user) -->
+ <browser:page
+ for="*"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ name="login.html"
+ class=".auth.HTTPAuthenticationLogin"
+ attribute="login"
+ allowed_interface="zope.app.publisher.interfaces.http.ILogin"
+ permission="zope.Public"
+ />
+
+ <!-- login form for session credentials -->
+ <z3c:pagelet
+ for="*"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ name="loginForm.html"
+ class=".auth.SessionCredentialsLoginForm"
+ permission="zope.Public"
+ />
+
+ <z3c:template
+ for=".auth.SessionCredentialsLoginForm"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ template="session_cred_loginform.pt"
+ />
+
+ <!-- login failed -->
+ <z3c:pagelet
+ for=".auth.HTTPAuthenticationLogin"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ name="login_failed.html"
+ class=".auth.LoginFailedPagelet"
+ permission="zope.Public"
+ />
+
+ <z3c:template
+ for=".auth.LoginFailedPagelet"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ template="login_failed.pt"
+ />
+
+ <!-- login success confirmation -->
+ <z3c:pagelet
+ for=".auth.HTTPAuthenticationLogin"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ name="login_success.html"
+ class=".auth.LoginSuccessfulPagelet"
+ permission="zope.Public"
+ />
+
+ <z3c:template
+ for=".auth.LoginSuccessfulPagelet"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ template="login_success.pt"
+ />
+
+ <!-- logout page (executing logout and redirecting user) -->
+ <browser:page
+ for="*"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ name="logout.html"
+ class=".auth.HTTPAuthenticationLogout"
+ attribute="logout"
+ allowed_interface="zope.app.publisher.interfaces.http.ILogout"
+ permission="zope.Public"
+ />
+
+ <!-- redirecting logout confirmation -->
+ <z3c:pagelet
+ for=".auth.HTTPAuthenticationLogout"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ name="redirect.html"
+ class=".auth.LogoutRedirectPagelet"
+ permission="zope.Public"
+ />
+
+ <z3c:template
+ for=".auth.LogoutRedirectPagelet"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ template="redirect.pt"
+ />
+
+ <browser:viewlet
+ manager=".auth.ILoginLogoutHeadViewletManager"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ view=".auth.LogoutRedirectPagelet"
+ name="Redirect"
+ template="redirect_head.pt"
+ permission="zope.Public"
+ />
+
+ <browser:viewlet
+ manager=".auth.ILoginLogoutHeadViewletManager"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ view=".auth.LogoutRedirectPagelet"
+ name="Logout"
+ template="logout_head.pt"
+ permission="zope.Public"
+ />
+
+ <!-- not redirecting logout confirmation -->
+ <z3c:pagelet
+ for=".auth.HTTPAuthenticationLogout"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ name="logout_success.html"
+ class=".auth.LogoutSuccessPagelet"
+ permission="zope.Public"
+ />
+
+ <z3c:template
+ for=".auth.LogoutSuccessPagelet"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ template="logout.pt"
+ />
+
+ <browser:viewlet
+ manager=".auth.ILoginLogoutHeadViewletManager"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ view=".auth.LogoutSuccessPagelet"
+ name="Logout"
+ template="logout_head.pt"
+ permission="zope.Public"
+ />
+
+</configure>
Added: z3c.authviewlet/trunk/src/z3c/authviewlet/browser/login_failed.pt
===================================================================
--- z3c.authviewlet/trunk/src/z3c/authviewlet/browser/login_failed.pt (rev 0)
+++ z3c.authviewlet/trunk/src/z3c/authviewlet/browser/login_failed.pt 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,10 @@
+<div>
+ <h1 i18n:translate="">Login Failed!</h1>
+
+ <p style="font-size: 150%">
+ <tal:block
+ i18n:translate="">You cancelled the login procedure.</tal:block>
+ <a tal:attributes="href python: view.request.get('nextURL', '.')"
+ i18n:translate="">Click here to return.</a>
+ </p>
+</div>
Added: z3c.authviewlet/trunk/src/z3c/authviewlet/browser/login_success.pt
===================================================================
--- z3c.authviewlet/trunk/src/z3c/authviewlet/browser/login_success.pt (rev 0)
+++ z3c.authviewlet/trunk/src/z3c/authviewlet/browser/login_success.pt 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,9 @@
+<div>
+ <h1 i18n:translate="">Login successful!</h1>
+ <p style="font-size: 200%" i18n:translate="">
+ You are now logged in as
+ <em tal:content="view/request/principal/title"
+ i18n:name="UserTitle">Joe Smith</em>.
+ </p>
+ <a href="." i18n:translate="">Back to the main page.</a>
+</div>
Added: z3c.authviewlet/trunk/src/z3c/authviewlet/browser/logout.pt
===================================================================
--- z3c.authviewlet/trunk/src/z3c/authviewlet/browser/logout.pt (rev 0)
+++ z3c.authviewlet/trunk/src/z3c/authviewlet/browser/logout.pt 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,8 @@
+<div>
+ <h1 i18n:translate="">Logout successful!</h1>
+
+ <p style="font-size: 200%" i18n:translate="">
+ You are now logged out.
+ </p>
+ <a href="." i18n:translate="">Back to the main page.</a>
+</div>
Added: z3c.authviewlet/trunk/src/z3c/authviewlet/browser/logout_head.pt
===================================================================
--- z3c.authviewlet/trunk/src/z3c/authviewlet/browser/logout_head.pt (rev 0)
+++ z3c.authviewlet/trunk/src/z3c/authviewlet/browser/logout_head.pt 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,16 @@
+<script type="text/javascript"><!--
+ // clear HTTP Authentication
+ try {
+ if (window.XMLHttpRequest) {
+ var xmlhttp = new XMLHttpRequest();
+ // Send invalid credentials, then abort
+ xmlhttp.open("GET", "@@", true, "logout", "logout");
+ xmlhttp.send("");
+ xmlhttp.abort();
+ } else if (document.execCommand) {
+ // IE specific command
+ document.execCommand("ClearAuthenticationCache");
+ }
+ } catch(e) { }
+ //-->
+</script>
Added: z3c.authviewlet/trunk/src/z3c/authviewlet/browser/redirect.pt
===================================================================
--- z3c.authviewlet/trunk/src/z3c/authviewlet/browser/redirect.pt (rev 0)
+++ z3c.authviewlet/trunk/src/z3c/authviewlet/browser/redirect.pt 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,9 @@
+<div>
+ <h1 i18n:translate="">You are being redirected!</h1>
+
+ <p style="font-size: 150%">
+ <a tal:attributes="href view/request/nextURL" i18n:translate="">
+ If you see this screen for more than 5 seconds, click here.
+ </a>
+ </p>
+</div>
Added: z3c.authviewlet/trunk/src/z3c/authviewlet/browser/redirect_head.pt
===================================================================
--- z3c.authviewlet/trunk/src/z3c/authviewlet/browser/redirect_head.pt (rev 0)
+++ z3c.authviewlet/trunk/src/z3c/authviewlet/browser/redirect_head.pt 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,2 @@
+<meta http-equiv="refresh" content="0;url=./"
+ tal:attributes="content string:0;;url=${request/nextURL}" />
Added: z3c.authviewlet/trunk/src/z3c/authviewlet/browser/session_cred_loginform.pt
===================================================================
--- z3c.authviewlet/trunk/src/z3c/authviewlet/browser/session_cred_loginform.pt (rev 0)
+++ z3c.authviewlet/trunk/src/z3c/authviewlet/browser/session_cred_loginform.pt 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,36 @@
+<div tal:define="principal python:request.principal.id">
+ <p i18n:translate=""
+ tal:condition="python: principal == 'zope.anybody'">
+ Please provide Login Information
+ </p>
+ <p i18n:translate=""
+ tal:condition="python: principal != 'zope.anybody'">
+ You are not authorized to perform this action. However, you may login as a
+ different user who is authorized.
+ </p>
+ <form action="" method="post">
+ <div tal:omit-tag=""
+ tal:condition="python:principal != 'zope.anybody' and 'SUBMIT' in request">
+ <span tal:define="dummy python:request.response.redirect(request.get('camefrom', ''))" />
+ </div>
+ <div class="row">
+ <div class="label"><label for="login" i18n:translate="">User Name</label></div>
+ <div class="field">
+ <input type="text" name="login" id="login" />
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="label"><label for="password" i18n:translate="">Password</label></div>
+ <div class="field">
+ <input type="password" name="password" id="password" />
+ </div>
+ </div>
+
+ <div class="row">
+ <input class="form-element" type="submit"
+ name="SUBMIT" value="Log in" i18n:attributes="value login-button" />
+ </div>
+ <input type="hidden" name="camefrom" tal:attributes="value request/camefrom | nothing">
+ </form>
+</div>
Added: z3c.authviewlet/trunk/src/z3c/authviewlet/configure.zcml
===================================================================
--- z3c.authviewlet/trunk/src/z3c/authviewlet/configure.zcml (rev 0)
+++ z3c.authviewlet/trunk/src/z3c/authviewlet/configure.zcml 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,7 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ i18n_domain="z3c">
+
+ <include package=".browser" />
+
+</configure>
Added: z3c.authviewlet/trunk/src/z3c/authviewlet/tests/__init__.py
===================================================================
--- z3c.authviewlet/trunk/src/z3c/authviewlet/tests/__init__.py (rev 0)
+++ z3c.authviewlet/trunk/src/z3c/authviewlet/tests/__init__.py 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,26 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation 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.
+#
+##############################################################################
+"""
+$Id:$
+"""
+
+import z3c.pagelet.browser
+
+
+class LoginLogoutPage(z3c.pagelet.browser.BrowserPagelet):
+ """Login and logout page."""
+
+ # make sure the pagelet renders no content, as this is not what we
+ # want to show with this pagelet
+ template = lambda self: ''
Added: z3c.authviewlet/trunk/src/z3c/authviewlet/tests/ftesting.zcml
===================================================================
--- z3c.authviewlet/trunk/src/z3c/authviewlet/tests/ftesting.zcml (rev 0)
+++ z3c.authviewlet/trunk/src/z3c/authviewlet/tests/ftesting.zcml 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,54 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:meta="http://namespaces.zope.org/meta"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ xmlns:z3c="http://namespaces.zope.org/z3c"
+ i18n_domain="zope">
+
+ <!-- re-use ftesting configuration -->
+ <include package="z3c.layer.pagelet.tests" file="ftesting.zcml" />
+
+ <!-- load additional configuration -->
+ <include package="zope.viewlet" file="meta.zcml" />
+ <include package="zope.viewlet" />
+
+ <!-- load package configuration -->
+ <include package="z3c.authviewlet" />
+
+
+ <!-- definitions for login-logout tests -->
+ <!-- use special template for default.html view -->
+ <z3c:layout
+ for="z3c.authviewlet.tests.LoginLogoutPage"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ template="login-logout-template.pt"
+ />
+
+ <z3c:pagelet
+ for="zope.container.interfaces.IContainer"
+ name="default.html"
+ permission="zope.View"
+ class="z3c.authviewlet.tests.LoginLogoutPage"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ />
+
+ <browser:defaultView
+ name="default.html"
+ for="zope.container.interfaces.IContainer"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ />
+
+ <!-- use tempate with head slot for logout pagelets -->
+ <z3c:layout
+ for="z3c.authviewlet.browser.auth.LogoutRedirectPagelet"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ template="login-logout-template.pt"
+ />
+
+ <z3c:layout
+ for="z3c.authviewlet.browser.auth.LogoutSuccessPagelet"
+ layer="z3c.layer.pagelet.IPageletBrowserLayer"
+ template="login-logout-template.pt"
+ />
+
+</configure>
Added: z3c.authviewlet/trunk/src/z3c/authviewlet/tests/login-logout-template.pt
===================================================================
--- z3c.authviewlet/trunk/src/z3c/authviewlet/tests/login-logout-template.pt (rev 0)
+++ z3c.authviewlet/trunk/src/z3c/authviewlet/tests/login-logout-template.pt 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,11 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <title>PageletTest</title>
+ <tal:block replace="structure provider:login-logout-head" />
+ </head>
+ <body>
+ <tal:block replace="structure provider:login-logout" />
+ <tal:block replace="structure provider:pagelet" />
+ </body>
+</html>
Added: z3c.authviewlet/trunk/src/z3c/authviewlet/tests/test_layer.py
===================================================================
--- z3c.authviewlet/trunk/src/z3c/authviewlet/tests/test_layer.py (rev 0)
+++ z3c.authviewlet/trunk/src/z3c/authviewlet/tests/test_layer.py 2009-11-30 16:03:19 UTC (rev 106124)
@@ -0,0 +1,41 @@
+##############################################################################
+#
+# Copyright (c) 2007-2009 Zope Foundation 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.
+#
+##############################################################################
+"""
+$Id: __init__.py 97 2007-03-29 22:58:27Z rineichen $
+"""
+
+import re
+import unittest
+from zope.testing import renormalizing
+from zope.app.testing import functional
+
+
+functional.defineLayer('TestLayer', 'ftesting.zcml')
+
+
+checker = renormalizing.RENormalizing([
+ (re.compile(r'httperror_seek_wrapper:', re.M), 'HTTPError:'),
+ ])
+
+
+def create_suite(*args, **kw):
+ suite = functional.FunctionalDocFileSuite(*args, **kw)
+ suite.layer = TestLayer
+ return suite
+
+
+def test_suite():
+ return unittest.TestSuite((
+ create_suite('../README.txt', checker=checker),
+ ))
More information about the checkins
mailing list