[Checkins] SVN: z3c.layer.pagelet/trunk/ merged login-logout branch

Michael Howitz mh at gocept.com
Fri Mar 13 17:20:33 EDT 2009


Log message for revision 98052:
  merged login-logout branch
  

Changed:
  U   z3c.layer.pagelet/trunk/CHANGES.txt
  U   z3c.layer.pagelet/trunk/buildout.cfg
  U   z3c.layer.pagelet/trunk/setup.py
  U   z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/README.txt
  D   z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/SETUP.cfg
  A   z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/auth.py
  U   z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/configure.zcml
  A   z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/login_failed.pt
  A   z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/login_success.pt
  A   z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/logout.pt
  A   z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/logout_head.pt
  A   z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/redirect.pt
  A   z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/redirect_head.pt
  A   z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/session_cred_loginform.pt
  A   z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/zope.app.security.browser.zcml
  A   z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/login.txt
  U   z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/__init__.py
  U   z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/bugfixes.txt
  U   z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/ftesting.zcml
  A   z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/login-logout-template.pt
  U   z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/test_layer.py

-=-
Modified: z3c.layer.pagelet/trunk/CHANGES.txt
===================================================================
--- z3c.layer.pagelet/trunk/CHANGES.txt	2009-03-13 21:18:28 UTC (rev 98051)
+++ z3c.layer.pagelet/trunk/CHANGES.txt	2009-03-13 21:20:33 UTC (rev 98052)
@@ -5,13 +5,16 @@
 1.2.2 (unreleased)
 ------------------
 
-- Nothing changed yet.
+- Implemented login and logout using pagelets resp. viewlets.
 
+- Updated tests to use new ``zope.configuration`` which containts the
+  exclude directive.
 
+
 1.2.1 (2009-02-21)
 ------------------
 
-- Release 1.2.0 was missing the test file for the secrity issue.
+- Release 1.2.0 was missing the test file for the security issue.
 
 
 1.2.0 (2009-02-21)

Modified: z3c.layer.pagelet/trunk/buildout.cfg
===================================================================
--- z3c.layer.pagelet/trunk/buildout.cfg	2009-03-13 21:18:28 UTC (rev 98051)
+++ z3c.layer.pagelet/trunk/buildout.cfg	2009-03-13 21:20:33 UTC (rev 98052)
@@ -1,6 +1,6 @@
 [buildout]
 develop = .
-parts = test checker coverage-test coverage-report
+parts = test checker coverage-test coverage-report omelette
 
 [test]
 recipe = zc.recipe.testrunner
@@ -15,8 +15,11 @@
 eggs = z3c.layer.pagelet [test]
 defaults = ['--tests-pattern', '^f?tests$', '--coverage', '../../coverage']
 
-
 [coverage-report]
 recipe = zc.recipe.egg
 eggs = z3c.coverage
 scripts = coverage=coverage-report
+
+[omelette]
+recipe = collective.recipe.omelette
+eggs = z3c.layer.pagelet [test]

Modified: z3c.layer.pagelet/trunk/setup.py
===================================================================
--- z3c.layer.pagelet/trunk/setup.py	2009-03-13 21:18:28 UTC (rev 98051)
+++ z3c.layer.pagelet/trunk/setup.py	2009-03-13 21:20:33 UTC (rev 98052)
@@ -34,6 +34,8 @@
         + '\n\n' +
         read('src', 'z3c', 'layer', 'pagelet', 'README.txt')
         + '\n\n' +
+        read('src', 'z3c', 'layer', 'pagelet', 'login.txt')
+        + '\n\n' +
         read('CHANGES.txt')
         ),
     keywords = "z3c pagelet layer zope zope3",
@@ -60,9 +62,7 @@
             'zope.app.testing',
             'zope.app.zcmlfiles',
             'zope.app.twisted',
-            'zope.viewlet',
-            'z3c.pagelet',
-            'zc.configuration',
+            'zope.configuration>=3.5.0',
             'zope.component',
             'zope.app.component',
             ],
@@ -74,6 +74,8 @@
         'zope.app.publisher',
         'zope.app.security',
         'zope.app.exception',
+        'z3c.pagelet',
+        'zope.viewlet',
         ],
     zip_safe = False,
 )

Modified: z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/README.txt
===================================================================
--- z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/README.txt	2009-03-13 21:18:28 UTC (rev 98051)
+++ z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/README.txt	2009-03-13 21:20:33 UTC (rev 98052)
@@ -45,7 +45,6 @@
 
   >>> from zope.testbrowser.testing import Browser
   >>> manager = Browser()
-  >>> manager.addHeader('Authorization', 'Basic mgr:mgrpw')
 
 Check if we can access the ``page.html`` view which is registred in the
 ``ftesting.zcml`` file with our skin:
@@ -155,14 +154,17 @@
   </html>
   <BLANKLINE>
 
-And check the ``zope.security.interfaces.IUnauthorized`` view, use a new
-unregistred user (test browser) for this:
+To check the ``zope.security.interfaces.IUnauthorized`` view, we use a
+new unregistred user (test browser). As we have defined an
+unauthenticatedPrincipal in ZCML (see tests/ftesting.zcml) ``401
+Unauthorized`` is returned instead of ``403 Forbidden`` which would
+show up otherwise:
 
   >>> unauthorized = Browser()
   >>> unauthorized.open(skinURL + '/@@forbidden.html')
   Traceback (most recent call last):
   ...
-  httperror_seek_wrapper: HTTP Error 403: Forbidden
+  HTTPError: HTTP Error 401: Unauthorized
 
   >>> print unauthorized.contents
   <!DOCTYPE ...

Deleted: z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/SETUP.cfg
===================================================================
--- z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/SETUP.cfg	2009-03-13 21:18:28 UTC (rev 98051)
+++ z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/SETUP.cfg	2009-03-13 21:20:33 UTC (rev 98052)
@@ -1,3 +0,0 @@
-<data-files zopeskel/etc/package-includes>
-  z3c.layer.pagelet-*.zcml
-</data-files>

Copied: z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/auth.py (from rev 98051, z3c.layer.pagelet/branches/icemac_login_support/src/z3c/layer/pagelet/browser/auth.py)
===================================================================
--- z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/auth.py	                        (rev 0)
+++ z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/auth.py	2009-03-13 21:20:33 UTC (rev 98052)
@@ -0,0 +1,177 @@
+##############################################################################
+#
+# 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.template.interfaces
+import zope.app.pagetemplate
+import zope.app.publisher.interfaces.http
+import zope.app.security.interfaces
+import zope.component
+import zope.i18n
+import zope.i18nmessageid
+import zope.interface
+import zope.publisher.interfaces.browser
+import zope.traversing.browser.interfaces
+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.app.security.interfaces.IUnauthenticatedPrincipal
+    return not unauthenticated.providedBy(principal)
+
+
+def logout_supported(request):
+    "Tell whether logout is supported."
+    logout = zope.app.security.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.app.security.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.app.security.interfaces.ILogout)
+
+    def logout(self, nextURL=None):
+        if authenticated(self.request.principal):
+            auth = zope.component.getUtility(
+                zope.app.security.interfaces.IAuthentication)
+            zope.app.security.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."
+
+

Modified: z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/configure.zcml
===================================================================
--- z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/configure.zcml	2009-03-13 21:18:28 UTC (rev 98051)
+++ z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/configure.zcml	2009-03-13 21:20:33 UTC (rev 98052)
@@ -98,4 +98,6 @@
       layer="z3c.layer.pagelet.IPageletBrowserLayer"
       />
 
+  <include file="zope.app.security.browser.zcml" />
+
 </configure>

Copied: z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/login_failed.pt (from rev 98051, z3c.layer.pagelet/branches/icemac_login_support/src/z3c/layer/pagelet/browser/login_failed.pt)
===================================================================
--- z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/login_failed.pt	                        (rev 0)
+++ z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/login_failed.pt	2009-03-13 21:20:33 UTC (rev 98052)
@@ -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>

Copied: z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/login_success.pt (from rev 98051, z3c.layer.pagelet/branches/icemac_login_support/src/z3c/layer/pagelet/browser/login_success.pt)
===================================================================
--- z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/login_success.pt	                        (rev 0)
+++ z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/login_success.pt	2009-03-13 21:20:33 UTC (rev 98052)
@@ -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>

Copied: z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/logout.pt (from rev 98051, z3c.layer.pagelet/branches/icemac_login_support/src/z3c/layer/pagelet/browser/logout.pt)
===================================================================
--- z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/logout.pt	                        (rev 0)
+++ z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/logout.pt	2009-03-13 21:20:33 UTC (rev 98052)
@@ -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>

Copied: z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/logout_head.pt (from rev 98051, z3c.layer.pagelet/branches/icemac_login_support/src/z3c/layer/pagelet/browser/logout_head.pt)
===================================================================
--- z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/logout_head.pt	                        (rev 0)
+++ z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/logout_head.pt	2009-03-13 21:20:33 UTC (rev 98052)
@@ -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>

Copied: z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/redirect.pt (from rev 98051, z3c.layer.pagelet/branches/icemac_login_support/src/z3c/layer/pagelet/browser/redirect.pt)
===================================================================
--- z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/redirect.pt	                        (rev 0)
+++ z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/redirect.pt	2009-03-13 21:20:33 UTC (rev 98052)
@@ -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>

Copied: z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/redirect_head.pt (from rev 98051, z3c.layer.pagelet/branches/icemac_login_support/src/z3c/layer/pagelet/browser/redirect_head.pt)
===================================================================
--- z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/redirect_head.pt	                        (rev 0)
+++ z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/redirect_head.pt	2009-03-13 21:20:33 UTC (rev 98052)
@@ -0,0 +1,2 @@
+<meta http-equiv="refresh" content="0;url=./"
+      tal:attributes="content string:0;;url=${request/nextURL}" />

Copied: z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/session_cred_loginform.pt (from rev 98051, z3c.layer.pagelet/branches/icemac_login_support/src/z3c/layer/pagelet/browser/session_cred_loginform.pt)
===================================================================
--- z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/session_cred_loginform.pt	                        (rev 0)
+++ z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/session_cred_loginform.pt	2009-03-13 21:20:33 UTC (rev 98052)
@@ -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>

Copied: z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/zope.app.security.browser.zcml (from rev 98051, z3c.layer.pagelet/branches/icemac_login_support/src/z3c/layer/pagelet/browser/zope.app.security.browser.zcml)
===================================================================
--- z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/zope.app.security.browser.zcml	                        (rev 0)
+++ z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/browser/zope.app.security.browser.zcml	2009-03-13 21:20:33 UTC (rev 98052)
@@ -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>

Copied: z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/login.txt (from rev 98051, z3c.layer.pagelet/branches/icemac_login_support/src/z3c/layer/pagelet/login.txt)
===================================================================
--- z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/login.txt	                        (rev 0)
+++ z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/login.txt	2009-03-13 21:20:33 UTC (rev 98052)
@@ -0,0 +1,608 @@
+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.app.security
+  >>> import zope.app.security.interfaces
+  >>> ztapi.provideAdapter(
+  ...     zope.interface.Interface,
+  ...     zope.app.security.interfaces.ILogoutSupported,
+  ...     zope.app.security.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.app.security.interfaces import IAuthentication
+  >>> from zope.app.authentication.interfaces import IAuthenticatorPlugin
+  >>> from zope.app.appsetup.bootstrap import ensureUtility
+  >>> from zope.app.authentication.authentication import PluggableAuthentication
+  >>> from zope.app.authentication.principalfolder import PrincipalFolder
+  >>> from zope.site import site
+
+  >>> auth = ensureUtility(
+  ...     getRootFolder(), IAuthentication, '', PluggableAuthentication,
+  ...     asObject=True)
+  >>> auth.credentialsPlugins = (u'Session Credentials',)
+  >>> principal_folder = ensureUtility(getRootFolder(), IAuthenticatorPlugin,
+  ...     '', PrincipalFolder, name=u'principal_folder', asObject=True)
+  >>> auth.authenticatorPlugins = (u'principal_folder',)
+
+We need a principal inside the principal folder:
+
+  >>> from zope.app.authentication.principalfolder import InternalPrincipal
+  >>> 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>

Modified: z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/__init__.py
===================================================================
--- z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/__init__.py	2009-03-13 21:18:28 UTC (rev 98051)
+++ z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/__init__.py	2009-03-13 21:20:33 UTC (rev 98052)
@@ -36,7 +36,6 @@
 
     def __call__(self):
         raise Unauthorized('not authorized')
-        return u''
 
 
 class UserErrorPage(BrowserPage):
@@ -44,7 +43,6 @@
 
     def __call__(self):
         raise UserError('simply user error')
-        return u''
 
 
 class SystemErrorPage(BrowserPage):
@@ -52,7 +50,6 @@
 
     def __call__(self):
         raise Exception('simply system error')
-        return u''
 
 
 class ContainerContentsPage(BrowserPage):
@@ -60,3 +57,11 @@
 
     def __call__(self):
         return str([type(x) for x in self.context.values()])
+
+
+class LoginLogoutPage(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: ''

Modified: z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/bugfixes.txt
===================================================================
--- z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/bugfixes.txt	2009-03-13 21:18:28 UTC (rev 98051)
+++ z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/bugfixes.txt	2009-03-13 21:20:33 UTC (rev 98052)
@@ -2,8 +2,8 @@
  Bugfixes
 ==========
 
-Traversed objects where not security proxied
-============================================
+Traversed objects were not security proxied
+===========================================
 
 When an object got traversed its security proxy was removed, so its
 sub-objects could be publically accessed. To show that this behavior

Modified: z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/ftesting.zcml
===================================================================
--- z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/ftesting.zcml	2009-03-13 21:18:28 UTC (rev 98051)
+++ z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/ftesting.zcml	2009-03-13 21:20:33 UTC (rev 98052)
@@ -5,13 +5,9 @@
     xmlns:z3c="http://namespaces.zope.org/z3c"
     i18n_domain="zope">
 
-  <!-- load meta configuration for exclude -->
-  <include package="zc.configuration" file="meta.zcml" />
-
   <!-- exclude will prevent from include -->
   <exclude package="zope.app.authentication" file="ftpplugins.zcml" />
   <exclude package="zope.app.authentication" file="groupfolder.zcml" />
-  <exclude package="zope.app.authentication" file="principalfolder.zcml" />
   <exclude package="zope.app.authentication.browser" />
   <exclude package="zope.app.authentication.browser" file="configure.zcml" />
   <exclude package="zope.app.authentication.browser" file="groupfolder.zcml" />
@@ -20,7 +16,6 @@
   <exclude package="zope.app.authentication.browser" file="session.zcml" />
   <exclude package="zope.app.broken" file="browser.zcml" />
   <exclude package="zope.app.error.browser" />
-  <exclude package="zope.app.folder.browser" />
   <exclude package="zope.app.i18n.browser" />
   <exclude package="zope.dublincore.browser" />
 
@@ -33,6 +28,7 @@
   <include package="zope.app.publisher" file="meta.zcml" />
   <include package="zope.app.security" file="meta.zcml" />
   <include package="zope.securitypolicy" file="meta.zcml" />
+  <include package="zope.viewlet" file="meta.zcml" />
 
 
   <!-- 3rd party meta configure -->
@@ -51,6 +47,7 @@
   <include package="zope.app.publication" />
   <include package="zope.app.publisher.browser" />
   <include package="zope.app.security" />
+  <include package="zope.app.authentication" />
   <include package="zope.securitypolicy" />
   <include package="zope.app.twisted" />
   <include package="zope.app.wsgi" />
@@ -61,6 +58,7 @@
   <include package="zope.traversing" />
   <include package="zope.traversing.browser" />
   <include package="zope.viewlet" />
+  <include package="zope.session" />
 
 
   <!-- z3c component -->
@@ -120,6 +118,7 @@
         class=".SystemErrorPage"
         />
 
+    <!-- page for bugfix.txt -->
     <browser:page
         for="*"
         name="container_contents.html"
@@ -127,6 +126,42 @@
         layer="z3c.layer.pagelet.IPageletBrowserLayer"
         class=".ContainerContentsPage"
         />
+
+    <!-- definitions for login-logout tests -->
+    <!-- use special template for default.html view -->
+    <z3c:layout
+        for=".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=".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="..browser.auth.LogoutRedirectPagelet"
+        layer="z3c.layer.pagelet.IPageletBrowserLayer"
+        template="login-logout-template.pt"
+        />
+
+    <z3c:layout
+        for="..browser.auth.LogoutSuccessPagelet"
+        layer="z3c.layer.pagelet.IPageletBrowserLayer"
+        template="login-logout-template.pt"
+        />
+
   </configure>
 
 
@@ -135,6 +170,27 @@
       component="zope.securitypolicy.zopepolicy.ZopeSecurityPolicy"
       />
 
+  <!-- default principals -->
+  <unauthenticatedPrincipal
+      id="zope.anybody"
+      title="Unauthenticated User" />
+
+  <unauthenticatedGroup
+    id="zope.Anybody"
+    title="Unauthenticated Users"
+    />
+
+  <authenticatedGroup
+    id="zope.Authenticated"
+    title="Authenticated Users"
+    />
+
+  <everybodyGroup
+    id="zope.Everybody"
+    title="All Users"
+    />
+
+  <!-- default users -->
   <role
       id="zope.Manager"
       title="Manager"
@@ -143,8 +199,8 @@
   <principal
       id="zope.manager"
       title="Manager"
-      login="Manager"
-      password="password"
+      login="mgr"
+      password="mgrpw"
       />
 
   <grant

Copied: z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/login-logout-template.pt (from rev 98051, z3c.layer.pagelet/branches/icemac_login_support/src/z3c/layer/pagelet/tests/login-logout-template.pt)
===================================================================
--- z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/login-logout-template.pt	                        (rev 0)
+++ z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/login-logout-template.pt	2009-03-13 21:20:33 UTC (rev 98052)
@@ -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>

Modified: z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/test_layer.py
===================================================================
--- z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/test_layer.py	2009-03-13 21:18:28 UTC (rev 98051)
+++ z3c.layer.pagelet/trunk/src/z3c/layer/pagelet/tests/test_layer.py	2009-03-13 21:20:33 UTC (rev 98052)
@@ -38,9 +38,6 @@
 def test_suite():
     suite = unittest.TestSuite()
     suite.addTest(create_suite('../README.txt', checker=checker))
+    suite.addTest(create_suite('../login.txt', checker=checker))
     suite.addTest(create_suite('bugfixes.txt'))
     return suite
-
-
-if __name__ == '__main__':
-    unittest.main(defaultTest='test_suite')



More information about the Checkins mailing list