[Checkins] SVN: zope.testbrowser/branches/jinty-webtest3/src/zope/testbrowser/ Ressurect the AuthorizationMiddleware from trunk, write tests for it and work around a weird bug where unicode headers are getting passed to cStringIO
Brian Sutherland
jinty at web.de
Mon Mar 7 05:26:27 EST 2011
Log message for revision 120775:
Ressurect the AuthorizationMiddleware from trunk, write tests for it and work around a weird bug where unicode headers are getting passed to cStringIO
Changed:
U zope.testbrowser/branches/jinty-webtest3/src/zope/testbrowser/ftests/wsgitestapp.py
U zope.testbrowser/branches/jinty-webtest3/src/zope/testbrowser/tests/test_wsgi.py
U zope.testbrowser/branches/jinty-webtest3/src/zope/testbrowser/wsgi.py
-=-
Modified: zope.testbrowser/branches/jinty-webtest3/src/zope/testbrowser/ftests/wsgitestapp.py
===================================================================
--- zope.testbrowser/branches/jinty-webtest3/src/zope/testbrowser/ftests/wsgitestapp.py 2011-03-07 10:24:42 UTC (rev 120774)
+++ zope.testbrowser/branches/jinty-webtest3/src/zope/testbrowser/ftests/wsgitestapp.py 2011-03-07 10:26:26 UTC (rev 120775)
@@ -39,6 +39,7 @@
handler = {'/set_status.html': set_status,
'/echo.html': echo,
'/echo_one.html': echo_one,
+ '/set_header.html': set_header,
'/set_cookie.html': set_cookie,
'/get_cookie.html': get_cookie,
'/inner/set_cookie.html': set_cookie,
@@ -91,6 +92,15 @@
resp.set_cookie(name, value, **cookie_parms)
return resp
+def set_header(req):
+ resp = Response()
+ body = [u"Set Headers:"]
+ for k, v in sorted(req.params.items()):
+ body.extend([k, v])
+ resp.headers.add(k, v)
+ resp.unicode_body = u'\n'.join(body)
+ return resp
+
_interesting_environ = ('CONTENT_LENGTH',
'CONTENT_TYPE',
'HTTP_ACCEPT_LANGUAGE',
Modified: zope.testbrowser/branches/jinty-webtest3/src/zope/testbrowser/tests/test_wsgi.py
===================================================================
--- zope.testbrowser/branches/jinty-webtest3/src/zope/testbrowser/tests/test_wsgi.py 2011-03-07 10:24:42 UTC (rev 120774)
+++ zope.testbrowser/branches/jinty-webtest3/src/zope/testbrowser/tests/test_wsgi.py 2011-03-07 10:26:26 UTC (rev 120775)
@@ -16,6 +16,7 @@
from wsgiref.simple_server import demo_app
import zope.testbrowser.wsgi
+from zope.testbrowser.ftests.wsgitestapp import WSGITestApplication
class SimpleLayer(zope.testbrowser.wsgi.Layer):
@@ -50,3 +51,36 @@
another_layer = SimpleLayer()
# The layer has a .app property where the application under test is available
self.assertRaises(AssertionError, another_layer.setUp)
+
+class TestAuthorizationMiddleware(unittest.TestCase):
+
+ def setUp(self):
+ app = WSGITestApplication()
+ self.unwrapped_browser = zope.testbrowser.wsgi.Browser(wsgi_app=app)
+ app = zope.testbrowser.wsgi.AuthorizationMiddleware(app)
+ self.browser = zope.testbrowser.wsgi.Browser(wsgi_app=app)
+
+ def test_unwanted_headers(self):
+ #x-powered-by and x-content-type-warning are filtered
+ url = 'http://localhost/set_header.html?x-other=another&x-powered-by=zope&x-content-type-warning=bar'
+ self.browser.open(url)
+ self.assertEquals(self.browser.headers['x-other'], 'another')
+ self.assertTrue('x-other' in self.browser.headers)
+ self.assertFalse('x-powered-by' in self.browser.headers)
+ self.assertFalse('x-content-type-warning' in self.browser.headers)
+ # make sure we are actually testing something
+ self.unwrapped_browser.open(url)
+ self.assertTrue('x-powered-by' in self.unwrapped_browser.headers)
+ self.assertTrue('x-content-type-warning' in self.unwrapped_browser.headers)
+
+ def test_authorization(self):
+ # Basic authorization headers are encoded in base64
+ self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+ self.browser.open('http://localhost/echo_one.html?var=HTTP_AUTHORIZATION')
+ self.assertEquals(self.browser.contents, repr('Basic bWdyOm1ncnB3'))
+
+ def test_authorization_other(self):
+ # Non-Basic authorization headers are unmolested
+ self.browser.addHeader('Authorization', 'Digest foobar')
+ self.browser.open('http://localhost/echo_one.html?var=HTTP_AUTHORIZATION')
+ self.assertEquals(self.browser.contents, repr('Digest foobar'))
Modified: zope.testbrowser/branches/jinty-webtest3/src/zope/testbrowser/wsgi.py
===================================================================
--- zope.testbrowser/branches/jinty-webtest3/src/zope/testbrowser/wsgi.py 2011-03-07 10:24:42 UTC (rev 120774)
+++ zope.testbrowser/branches/jinty-webtest3/src/zope/testbrowser/wsgi.py 2011-03-07 10:26:26 UTC (rev 120775)
@@ -14,6 +14,8 @@
"""WSGI-specific testing code
"""
+import base64
+import re
import sys
from webtest import TestApp
@@ -103,6 +105,10 @@
headers.sort()
headers.insert(0, ('Status', response.status))
headers = '\r\n'.join('%s: %s' % h for h in headers)
+ # Ugh! WebTest's headers can at times be unicode. That causes weird
+ # problems later when they are shoved into a StringIO. So just cast
+ # to a string for now using ascii.
+ headers = str(headers)
content = response.body
return zope.testbrowser.connection.Response(content, headers, status, reason)
@@ -145,6 +151,59 @@
_APP_UNDER_TEST = None # setup and torn down by the Layer class
+# Compatibility helpers to behave like zope.app.testing
+
+basicre = re.compile('Basic (.+)?:(.+)?$')
+
+
+def auth_header(header):
+ """This function takes an authorization HTTP header and encode the
+ couple user, password into base 64 like the HTTP protocol wants
+ it.
+ """
+ match = basicre.match(header)
+ if match:
+ u, p = match.group(1, 2)
+ if u is None:
+ u = ''
+ if p is None:
+ p = ''
+ auth = base64.encodestring('%s:%s' % (u, p))
+ return 'Basic %s' % auth[:-1]
+ return header
+
+
+def is_wanted_header(header):
+ """Return True if the given HTTP header key is wanted.
+ """
+ key, value = header
+ return key.lower() not in ('x-content-type-warning', 'x-powered-by')
+
+
+class AuthorizationMiddleware(object):
+ """This middleware makes the WSGI application compatible with the
+ HTTPCaller behavior defined in zope.app.testing.functional:
+ - It modifies the HTTP Authorization header to encode user and
+ password into base64 if it is Basic authentication.
+ """
+
+ def __init__(self, wsgi_stack):
+ self.wsgi_stack = wsgi_stack
+
+ def __call__(self, environ, start_response):
+ # Handle authorization
+ auth_key = 'HTTP_AUTHORIZATION'
+ if auth_key in environ:
+ environ[auth_key] = auth_header(environ[auth_key])
+
+ # Remove unwanted headers
+ def application_start_response(status, headers, exc_info=None):
+ headers = filter(is_wanted_header, headers)
+ start_response(status, headers)
+
+ for entry in self.wsgi_stack(environ, application_start_response):
+ yield entry
+
class Layer(object):
"""Test layer which sets up WSGI application for use with
WebTest/testbrowser.
More information about the checkins
mailing list