Skip to content

Commit

Permalink
backport from trunk rev 71678
Browse files Browse the repository at this point in the history
-----------------------------
Work against squid negative_ttl when unauthorized
For a complete description of the problem solved see:
http://mail.zope.org/pipermail/zope3-dev/2006-December/021321.html
  • Loading branch information
Adam Groszer committed Jan 2, 2007
0 parents commit 32c3585
Show file tree
Hide file tree
Showing 2 changed files with 174 additions and 0 deletions.
127 changes: 127 additions & 0 deletions browser/tests/test_unauthorized.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
##############################################################################
#
# Copyright (c) 2001, 2002 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.
#
##############################################################################
"""Test Unauthorized Exception Views
$Id$
"""
from unittest import TestCase, main, makeSuite
from zope import component, interface
import zope.formlib.namedtemplate
from zope.publisher.browser import TestRequest
import zope.publisher.interfaces.browser
from zope.app.testing import ztapi
from zope.app.security.interfaces import IAuthentication, IPrincipal
from zope.app.exception.browser.unauthorized import Unauthorized
from zope.app.testing.placelesssetup import PlacelessSetup

class DummyPrincipal(object):
interface.implements(IPrincipal) # this is a lie

def __init__(self, id):
self.id = id

def getId(self):
return self.id

class DummyAuthUtility(object):
interface.implements(IAuthentication) # this is a lie

status = None

def unauthorized(self, principal_id, request):
self.principal_id = principal_id
self.request = request
if self.status is not None:
self.request.response.setStatus(self.status)

class DummyTemplate (object):

def __init__(self, context):
self.context = context

component.adapts(Unauthorized)
interface.implements(zope.formlib.namedtemplate.INamedTemplate)

def __call__(self):
return 'You are not authorized'

class Test(PlacelessSetup, TestCase):

def setUp(self):
super(Test, self).setUp()
self.auth = DummyAuthUtility()
ztapi.provideUtility(IAuthentication, self.auth)

def tearDown(self):
super(Test, self).tearDown()

def testUnauthorized(self):
component.provideAdapter(DummyTemplate, name="default")
exception = Exception()
try:
raise exception
except:
pass
request = TestRequest()
request.setPrincipal(DummyPrincipal(23))
u = Unauthorized(exception, request)
res = u()

# Make sure that we rendered the expected template
self.assertEqual("You are not authorized", res)

# Make sure the response status was set
self.assertEqual(request.response.getStatus(), 403)

# check headers that work around squid "negative_ttl"
self.assertEqual(request.response.getHeader('Expires'),
'Mon, 26 Jul 1997 05:00:00 GMT')
self.assertEqual(request.response.getHeader('Pragma'),
'no-cache')
self.assertEqual(request.response.getHeader('Cache-Control'),
'no-store, no-cache, must-revalidate')

# Make sure the auth utility was called
self.failUnless(self.auth.request is request)
self.assertEqual(self.auth.principal_id, 23)

def testRedirect(self):
exception= Exception()
try:
raise exception
except:
pass
request = TestRequest()
request.setPrincipal(DummyPrincipal(23))
u = Unauthorized(exception, request)

self.auth.status = 303

res = u()

# Make sure that the template was not rendered
self.assert_(res is None)

# Make sure the auth's redirect is honored
self.assertEqual(request.response.getStatus(), 303)

# Make sure the auth utility was called
self.failUnless(self.auth.request is request)
self.assertEqual(self.auth.principal_id, 23)

def test_suite():
return makeSuite(Test)

if __name__=='__main__':
main(defaultTest='test_suite')
47 changes: 47 additions & 0 deletions browser/unauthorized.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
##############################################################################
#
# Copyright (c) 2003 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.
#
##############################################################################
"""Unauthorized Exception View Class
$Id$
"""
__docformat__ = 'restructuredtext'

from zope.publisher.browser import BrowserPage
from zope.formlib import namedtemplate

from zope.app import zapi
from zope.app.pagetemplate import ViewPageTemplateFile

class Unauthorized(BrowserPage):

def __call__(self):
# Set the error status to 403 (Forbidden) in the case when we don't
# challenge the user
self.request.response.setStatus(403)

# make sure that squid does not keep the response in the cache
self.request.response.setHeader('Expires', 'Mon, 26 Jul 1997 05:00:00 GMT')
self.request.response.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate')
self.request.response.setHeader('Pragma', 'no-cache')

principal = self.request.principal
auth = zapi.principals()
auth.unauthorized(principal.id, self.request)
if self.request.response.getStatus() not in (302, 303):
return self.template()

template = namedtemplate.NamedTemplate('default')

default_template = namedtemplate.NamedTemplateImplementation(
ViewPageTemplateFile('unauthorized.pt'), Unauthorized)

0 comments on commit 32c3585

Please sign in to comment.