[Checkins] SVN: Products.CMFDefault/branches/cookiecrumbler_with_views/ modernizing CookieCrumbler
Yvo Schubbe
y.2010 at wcm-solutions.de
Fri Apr 23 12:27:25 EDT 2010
Log message for revision 111308:
modernizing CookieCrumbler
Changed:
A Products.CMFDefault/branches/cookiecrumbler_with_views/
U Products.CMFDefault/branches/cookiecrumbler_with_views/Products/CMFDefault/browser/authentication.py
U Products.CMFDefault/branches/cookiecrumbler_with_views/Products/CMFDefault/browser/configure.zcml
A Products.CMFDefault/branches/cookiecrumbler_with_views/Products/CMFDefault/browser/templates/forbidden.pt
U Products.CMFDefault/branches/cookiecrumbler_with_views/Products/CMFDefault/browser/tests/authentication.txt
-=-
Modified: Products.CMFDefault/branches/cookiecrumbler_with_views/Products/CMFDefault/browser/authentication.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/authentication.py 2010-04-23 16:02:22 UTC (rev 111307)
+++ Products.CMFDefault/branches/cookiecrumbler_with_views/Products/CMFDefault/browser/authentication.py 2010-04-23 16:27:25 UTC (rev 111308)
@@ -15,7 +15,12 @@
$Id$
"""
+from urllib import quote
+
+from Products.Five import BrowserView
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
+from zExceptions import Forbidden
+from zExceptions import Redirect
from zope.app.form.browser import TextWidget
from zope.formlib import form
from zope.interface import implements
@@ -27,11 +32,61 @@
from zope.schema.interfaces import ISource
from zope.site.hooks import getSite
+from Products.CMFCore.CookieCrumbler import ATTEMPT_LOGIN
+from Products.CMFCore.CookieCrumbler import ATTEMPT_NONE
from Products.CMFCore.utils import getToolByName
from Products.CMFDefault.formlib.form import EditFormBase
from Products.CMFDefault.utils import Message as _
+class UnauthorizedView(BrowserView):
+
+ """Exception view for Unauthorized.
+ """
+
+ forbidden_template = ViewPageTemplateFile('templates/forbidden.pt')
+
+ def __call__(self):
+ try:
+ cctool = getToolByName(self, 'cookie_authentication')
+ atool = getToolByName(self, 'portal_actions')
+ target = atool.getActionInfo('user/login')['url']
+ except (AttributeError, ValueError):
+ # re-raise the unhandled exception
+ raise self.context
+
+ req = self.request
+ attempt = getattr(req, '_cookie_auth', ATTEMPT_NONE)
+ if attempt == ATTEMPT_NONE:
+ # An anonymous user was denied access to something.
+ retry = ''
+ elif attempt == ATTEMPT_LOGIN:
+ # The login attempt failed. Try again.
+ retry = '1'
+ else:
+ # An authenticated user was denied access to something.
+ # XXX: hack context to get the right @@standard_macros/page
+ # why do we get the wrong without this hack?
+ self.context = self.__parent__
+ raise Forbidden(self.forbidden_template())
+
+ if req.response.cookies.has_key(cctool.auth_cookie):
+ del req.response.cookies[cctool.auth_cookie]
+
+ came_from = req.get('came_from', None)
+ if came_from is None:
+ came_from = req.get('ACTUAL_URL')
+ query = req.get('QUERY_STRING')
+ if query:
+ # Include the query string in came_from
+ if not query.startswith('?'):
+ query = '?' + query
+ came_from = came_from + query
+ url = '%s?came_from=%s&retry=%s&disable_cookie_login__=1' % (
+ target, quote(came_from), retry)
+ raise Redirect(url)
+
+
class NameSource(object):
implements(ISource)
Modified: Products.CMFDefault/branches/cookiecrumbler_with_views/Products/CMFDefault/browser/configure.zcml
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/configure.zcml 2010-04-23 16:02:22 UTC (rev 111307)
+++ Products.CMFDefault/branches/cookiecrumbler_with_views/Products/CMFDefault/browser/configure.zcml 2010-04-23 16:27:25 UTC (rev 111308)
@@ -185,4 +185,12 @@
permission="zope2.View"
/>
+ <browser:page
+ for="zExceptions.Unauthorized"
+ layer="..interfaces.ICMFDefaultSkin"
+ name="index.html"
+ class=".authentication.UnauthorizedView"
+ permission="zope.Public"
+ />
+
</configure>
Added: Products.CMFDefault/branches/cookiecrumbler_with_views/Products/CMFDefault/browser/templates/forbidden.pt
===================================================================
--- Products.CMFDefault/branches/cookiecrumbler_with_views/Products/CMFDefault/browser/templates/forbidden.pt (rev 0)
+++ Products.CMFDefault/branches/cookiecrumbler_with_views/Products/CMFDefault/browser/templates/forbidden.pt 2010-04-23 16:27:25 UTC (rev 111308)
@@ -0,0 +1,18 @@
+<html metal:use-macro="context/@@standard_macros/page">
+<body>
+
+<metal:slot metal:fill-slot="body" i18n:domain="cmf_default">
+<h1 id="DesktopTitle">Site Error</h1>
+
+<p id="DesktopDescription" i18n:translate="">An error was encountered while
+ publishing this resource.</p>
+
+<p><strong><tal:span i18n:translate="">Error Type:</tal:span>
+ <tal:span i18n:translate="">Forbidden</tal:span></strong><br />
+ <strong><tal:span i18n:translate="">Error Value:</tal:span>
+ <tal:span i18n:translate="">You don't have all the permissions necessary
+ to see the requested page.</tal:span></strong></p>
+</metal:slot>
+
+</body>
+</html>
Property changes on: Products.CMFDefault/branches/cookiecrumbler_with_views/Products/CMFDefault/browser/templates/forbidden.pt
___________________________________________________________________
Added: svn:eol-style
+ native
Modified: Products.CMFDefault/branches/cookiecrumbler_with_views/Products/CMFDefault/browser/tests/authentication.txt
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/tests/authentication.txt 2010-04-23 16:02:22 UTC (rev 111307)
+++ Products.CMFDefault/branches/cookiecrumbler_with_views/Products/CMFDefault/browser/tests/authentication.txt 2010-04-23 16:27:25 UTC (rev 111308)
@@ -3,15 +3,60 @@
Set up user.
+ >>> from urllib import quote
>>> uf = app.site.acl_users
- >>> uf._doAddUser('mgr', 'mgrpw', ['Manager'], [])
+ >>> uf._doAddUser('mbr', 'mbrpw', ['Member'], [])
+ >>> mbr_credentials = quote('mbr:mbrpw'.encode('base64').rstrip())
Create the browser object we'll be using.
- >>> from Products.Five.testbrowser import Browser
+ >>> try:
+ ... from Testing.testbrowser import Browser
+ ... except ImportError: # BBB: for Zope 2.12
+ ... from Products.Five.testbrowser import Browser
>>> browser = Browser()
- >>> browser.handleErrors = False
+ >>> # XXX: browser has no API for disabling redirects
+ >>> browser.mech_browser.set_handle_redirect(False)
+The view for zExceptions.Unauthorized redirects anonymous requests to the
+login_form. This works if raised by the object (here by the reconfig_form).
+
+ >>> browser.open('http://localhost/site/reconfig_form')
+ Traceback (most recent call last):
+ ...
+ HTTPError: HTTP Error 302: Moved Temporarily
+ >>> browser.contents
+ ''
+ >>> browser.headers['Location']
+ 'http://localhost/site/login_form?came_from=http%3A//localhost/site/reconfig_form&retry=&disable_cookie_login__=1'
+
+And it works if raised by BaseRequest.traverse (here caused by manage_main).
+
+ >>> browser.open('http://localhost/site/manage_main')
+ Traceback (most recent call last):
+ ...
+ HTTPError: HTTP Error 302: Moved Temporarily
+ >>> browser.contents
+ ''
+ >>> browser.headers['Location']
+ 'http://localhost/site/login_form?came_from=http%3A//localhost/site/manage_main&retry=&disable_cookie_login__=1'
+
+The view for zExceptions.Unauthorized shows a Forbidden error if logged in.
+
+ >>> browser.cookies['__ac'] = '%s' % mbr_credentials
+ >>> browser.open('http://localhost/site/manage_main')
+ Traceback (most recent call last):
+ ...
+ HTTPError: HTTP Error 403: Forbidden
+ >>> 'zpt_stylesheet.css' in browser.contents
+ True
+ >>> '[[cmf_default][Forbidden]]' in browser.contents
+ True
+
+For the following examples we have to reset the browser object.
+
+ >>> browser = Browser()
+
Use the login form without input.
>>> browser.open('http://localhost/site/@@login.html')
@@ -34,22 +79,26 @@
Use the login form with valid input but wrong password.
>>> browser.open('http://localhost/site/@@login.html')
- >>> browser.getControl('[[cmf_default][Member ID]]').value = 'mgr'
+ >>> browser.getControl('[[cmf_default][Member ID]]').value = 'mbr'
>>> browser.getControl('[[cmf_default][Password]]').value = 'wrong'
>>> browser.getControl('[[cmf_default][Remember my ID.]]').selected = False
>>> browser.getControl('[[cmf_default][Login]]').click()
>>> '[[cmf_default][Login failure]]' in browser.contents
True
+ >>> '__ac' not in browser.cookies
+ True
Use the login form with valid input and correct password.
>>> browser.open('http://localhost/site/@@login.html')
- >>> browser.getControl('[[cmf_default][Member ID]]').value = 'mgr'
- >>> browser.getControl('[[cmf_default][Password]]').value = 'mgrpw'
+ >>> browser.getControl('[[cmf_default][Member ID]]').value = 'mbr'
+ >>> browser.getControl('[[cmf_default][Password]]').value = 'mbrpw'
>>> browser.getControl('[[cmf_default][Remember my ID.]]').selected = False
>>> browser.getControl('[[cmf_default][Login]]').click()
>>> '[[cmf_default][Login success]]' in browser.contents
True
+ >>> browser.cookies['__ac'] == '"%s"' % mbr_credentials
+ True
Use the mail password form without input.
More information about the checkins
mailing list