[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