]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Fix str/bytes problems in the auth module on python 3.
authorBen Darnell <ben@bendarnell.com>
Sun, 12 Aug 2012 00:51:27 +0000 (17:51 -0700)
committerBen Darnell <ben@bendarnell.com>
Sun, 12 Aug 2012 00:51:27 +0000 (17:51 -0700)
In some cases signatures were being computed on str(byte object),
which is incorrect.  Enable python -bb flag to catch this class of
errors and fix up a few more instances.

Fixes #581.

tornado/auth.py
tornado/test/options_test.py
tornado/test/runtests.py
tornado/test/web_test.py
tox.ini

index 4f9a980b89ad4d96d9ad0ab44d79fb8d22880fc9..78ea9df800576a85488860fa604b4deb805b6633 100644 (file)
@@ -282,10 +282,10 @@ class OAuthMixin(object):
         consumer_token = self._oauth_consumer_token()
         url = self._OAUTH_REQUEST_TOKEN_URL
         args = dict(
-            oauth_consumer_key=consumer_token["key"],
+            oauth_consumer_key=escape.to_basestring(consumer_token["key"]),
             oauth_signature_method="HMAC-SHA1",
             oauth_timestamp=str(int(time.time())),
-            oauth_nonce=binascii.b2a_hex(uuid.uuid4().bytes),
+            oauth_nonce=escape.to_basestring(binascii.b2a_hex(uuid.uuid4().bytes)),
             oauth_version=getattr(self, "_OAUTH_VERSION", "1.0a"),
         )
         if getattr(self, "_OAUTH_VERSION", "1.0a") == "1.0a":
@@ -312,7 +312,7 @@ class OAuthMixin(object):
         self.set_cookie("_oauth_request_token", data)
         args = dict(oauth_token=request_token["key"])
         if callback_uri == "oob":
-            self.finish(authorize_url + "?" + urllib.urlencode(args)) 
+            self.finish(authorize_url + "?" + urllib.urlencode(args))
             return
         elif callback_uri:
             args["oauth_callback"] = urlparse.urljoin(
@@ -323,11 +323,11 @@ class OAuthMixin(object):
         consumer_token = self._oauth_consumer_token()
         url = self._OAUTH_ACCESS_TOKEN_URL
         args = dict(
-            oauth_consumer_key=consumer_token["key"],
-            oauth_token=request_token["key"],
+            oauth_consumer_key=escape.to_basestring(consumer_token["key"]),
+            oauth_token=escape.to_basestring(request_token["key"]),
             oauth_signature_method="HMAC-SHA1",
             oauth_timestamp=str(int(time.time())),
-            oauth_nonce=binascii.b2a_hex(uuid.uuid4().bytes),
+            oauth_nonce=escape.to_basestring(binascii.b2a_hex(uuid.uuid4().bytes)),
             oauth_version=getattr(self, "_OAUTH_VERSION", "1.0a"),
         )
         if "verifier" in request_token:
@@ -372,11 +372,11 @@ class OAuthMixin(object):
         """
         consumer_token = self._oauth_consumer_token()
         base_args = dict(
-            oauth_consumer_key=consumer_token["key"],
-            oauth_token=access_token["key"],
+            oauth_consumer_key=escape.to_basestring(consumer_token["key"]),
+            oauth_token=escape.to_basestring(access_token["key"]),
             oauth_signature_method="HMAC-SHA1",
             oauth_timestamp=str(int(time.time())),
-            oauth_nonce=binascii.b2a_hex(uuid.uuid4().bytes),
+            oauth_nonce=escape.to_basestring(binascii.b2a_hex(uuid.uuid4().bytes)),
             oauth_version=getattr(self, "_OAUTH_VERSION", "1.0a"),
         )
         args = {}
index e5411d945f5b5499acba06f5d7fa1d8b4b64aadc..f792329df563845d7915c47fdee323ec30c984c3 100644 (file)
@@ -1,14 +1,27 @@
 from __future__ import absolute_import, division, with_statement
+import contextlib
 import logging
 import os
 import re
 import tempfile
 import unittest
+import warnings
 
 from tornado.escape import utf8
 from tornado.options import _Options, _LogFormatter
 from tornado.util import b, bytes_type
 
+@contextlib.contextmanager
+def ignore_bytes_warning():
+    if not hasattr(warnings, 'catch_warnings'):
+        # python 2.5 doesn't have catch_warnings, but it doesn't have
+        # BytesWarning either so there's nothing to catch.
+        yield
+        return
+    with warnings.catch_warnings():
+        warnings.simplefilter('ignore', category=BytesWarning)
+        yield
+
 
 class OptionsTest(unittest.TestCase):
     def setUp(self):
@@ -56,7 +69,7 @@ class LogFormatterTest(unittest.TestCase):
         # Base case: default setup without explicit encoding.
         # In python 2, supports arbitrary byte strings and unicode objects
         # that contain only ascii.  In python 3, supports ascii-only unicode
-        # strings (but byte strings will be repr'd automatically.
+        # strings (but byte strings will be repr'd automatically).
         return logging.FileHandler(filename)
 
     def get_output(self):
@@ -73,9 +86,10 @@ class LogFormatterTest(unittest.TestCase):
         self.assertEqual(self.get_output(), b("foo"))
 
     def test_bytes_logging(self):
-        self.logger.error(b("\xe9"))
-        # This will be "\xe9" on python 2 or "b'\xe9'" on python 3
-        self.assertEqual(self.get_output(), utf8(repr(b("\xe9"))))
+        with ignore_bytes_warning():
+            # This will be "\xe9" on python 2 or "b'\xe9'" on python 3
+            self.logger.error(b("\xe9"))
+            self.assertEqual(self.get_output(), utf8(repr(b("\xe9"))))
 
     def test_utf8_logging(self):
         self.logger.error(u"\u00e9".encode("utf8"))
index 047d458986dab07aa754cd232fd3c9868539a428..a7a73e1ff986f092ee887aebcecc62aad246d045 100644 (file)
@@ -1,6 +1,7 @@
 #!/usr/bin/env python
 
 from __future__ import absolute_import, division, with_statement
+import sys
 import unittest
 
 TEST_MODULES = [
@@ -53,4 +54,12 @@ if __name__ == '__main__':
                             module=r"tornado\..*")
 
     import tornado.testing
-    tornado.testing.main()
+    kwargs = {}
+    if sys.version_info >= (3,2):
+        # HACK:  unittest.main will make its own changes to the warning
+        # configuration, which may conflict with the settings above
+        # or command-line flags like -bb.  Passing warnings=False
+        # suppresses this behavior, although this looks like an implementation
+        # detail.  http://bugs.python.org/issue15626
+        kwargs['warnings'] = False
+    tornado.testing.main(**kwargs)
index ad417336535696403ef931cbf38fb2afb140d19d..3418ec42ef1afd28493acc4d8600a4157dad2b80 100644 (file)
@@ -1,6 +1,6 @@
 from __future__ import absolute_import, division, with_statement
 from tornado import gen
-from tornado.escape import json_decode, utf8, to_unicode, recursive_unicode, native_str
+from tornado.escape import json_decode, utf8, to_unicode, recursive_unicode, native_str, to_basestring
 from tornado.iostream import IOStream
 from tornado.template import DictLoader
 from tornado.testing import LogTrapTestCase, AsyncHTTPTestCase
@@ -66,7 +66,8 @@ class SecureCookieTest(LogTrapTestCase):
                               'foo', '1234', b('5678') + timestamp),
             sig)
         # tamper with the cookie
-        handler._cookies['foo'] = utf8('1234|5678%s|%s' % (timestamp, sig))
+        handler._cookies['foo'] = utf8('1234|5678%s|%s' % (
+                to_basestring(timestamp), to_basestring(sig)))
         # it gets rejected
         self.assertTrue(handler.get_secure_cookie('foo') is None)
 
diff --git a/tox.ini b/tox.ini
index dd4132a8b0f91156fd74954589b33aa99f0484d1..381320424d8e6bbe1b84133b90546c22d7f49b0a 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -83,6 +83,9 @@ deps =
 [testenv:py32]
 basepython = python3.2
 setenv = LANG=C
+# -b turns on an extra warning when calling str(bytes), and -bb makes
+# it an error.
+commands = python -bb -m tornado.test.runtests {posargs:}
 
 [testenv:py32-utf8]
 basepython = python3.2