]> granicus.if.org Git - python/commitdiff
- Issue #13642: Unquote before b64encoding user:password during Basic
authorSenthil Kumaran <senthil@uthcode.com>
Tue, 10 Jan 2012 16:09:24 +0000 (00:09 +0800)
committerSenthil Kumaran <senthil@uthcode.com>
Tue, 10 Jan 2012 16:09:24 +0000 (00:09 +0800)
  Authentication. Patch contributed by Joonas Kuorilehto and Michele OrrĂ¹.

Lib/test/test_urllib.py
Lib/urllib.py
Misc/NEWS

index db908399f43e4e6a013550317a6d5c258e420f9c..085eecf0f609033c56d1445ba9a521ca837e950f 100644 (file)
@@ -3,13 +3,16 @@
 import urllib
 import httplib
 import unittest
-from test import test_support
 import os
 import sys
 import mimetools
 import tempfile
 import StringIO
 
+from test import test_support
+from base64 import b64encode
+
+
 def hexescape(char):
     """Escape char as RFC 2396 specifies"""
     hex_repr = hex(ord(char))[2:].upper()
@@ -22,8 +25,9 @@ class FakeHTTPMixin(object):
     def fakehttp(self, fakedata):
         class FakeSocket(StringIO.StringIO):
 
-            def sendall(self, str):
-                pass
+            def sendall(self, data):
+                FakeHTTPConnection.buf = data
+
             def makefile(self, *args, **kwds):
                 return self
 
@@ -38,9 +42,15 @@ class FakeHTTPMixin(object):
                 return StringIO.StringIO.readline(self, length)
 
         class FakeHTTPConnection(httplib.HTTPConnection):
+
+            # buffer to store data for verification in urlopen tests.
+            buf = ""
+
             def connect(self):
                 self.sock = FakeSocket(fakedata)
+
         assert httplib.HTTP._connection_class == httplib.HTTPConnection
+
         httplib.HTTP._connection_class = FakeHTTPConnection
 
     def unfakehttp(self):
@@ -209,6 +219,41 @@ Content-Type: text/html; charset=iso-8859-1
         finally:
             self.unfakehttp()
 
+    def test_userpass_inurl(self):
+        self.fakehttp('Hello!')
+        try:
+            fakehttp_wrapper = httplib.HTTP._connection_class
+            fp = urllib.urlopen("http://user:pass@python.org/")
+            authorization = ("Authorization: Basic %s\r\n" %
+                            b64encode('user:pass'))
+            # The authorization header must be in place
+            self.assertIn(authorization, fakehttp_wrapper.buf)
+            self.assertEqual(fp.readline(), "Hello!")
+            self.assertEqual(fp.readline(), "")
+            self.assertEqual(fp.geturl(), 'http://user:pass@python.org/')
+            self.assertEqual(fp.getcode(), 200)
+        finally:
+            self.unfakehttp()
+
+    def test_userpass_with_spaces_inurl(self):
+        self.fakehttp('Hello!')
+        try:
+            url = "http://a b:c d@python.org/"
+            fakehttp_wrapper = httplib.HTTP._connection_class
+            authorization = ("Authorization: Basic %s\r\n" %
+                             b64encode('a b:c d'))
+            fp = urllib.urlopen(url)
+            # The authorization header must be in place
+            self.assertIn(authorization, fakehttp_wrapper.buf)
+            self.assertEqual(fp.readline(), "Hello!")
+            self.assertEqual(fp.readline(), "")
+            # the spaces are quoted in URL so no match
+            self.assertNotEqual(fp.geturl(), url)
+            self.assertEqual(fp.getcode(), 200)
+        finally:
+            self.unfakehttp()
+
+
 class urlretrieve_FileTests(unittest.TestCase):
     """Test urllib.urlretrieve() on local files"""
 
@@ -716,6 +761,9 @@ class Utility_Tests(unittest.TestCase):
         self.assertEqual(('user', 'a\fb'),urllib.splitpasswd('user:a\fb'))
         self.assertEqual(('user', 'a\vb'),urllib.splitpasswd('user:a\vb'))
         self.assertEqual(('user', 'a:b'),urllib.splitpasswd('user:a:b'))
+        self.assertEqual(('user', 'a b'),urllib.splitpasswd('user:a b'))
+        self.assertEqual(('user 2', 'ab'),urllib.splitpasswd('user 2:ab'))
+        self.assertEqual(('user+1', 'a+b'),urllib.splitpasswd('user+1:a+b'))
 
 
 class URLopener_Tests(unittest.TestCase):
index 7b0a81cade78515f8efd149f266fd3a4e8cf717f..c7af8ec4fd987610984df94be032735ef60b1a72 100644 (file)
@@ -27,6 +27,8 @@ import socket
 import os
 import time
 import sys
+import base64
+
 from urlparse import urljoin as basejoin
 
 __all__ = ["urlopen", "URLopener", "FancyURLopener", "urlretrieve",
@@ -318,13 +320,13 @@ class URLopener:
         if not host: raise IOError, ('http error', 'no host given')
 
         if proxy_passwd:
-            import base64
+            proxy_passwd = unquote(proxy_passwd)
             proxy_auth = base64.b64encode(proxy_passwd).strip()
         else:
             proxy_auth = None
 
         if user_passwd:
-            import base64
+            user_passwd = unquote(user_passwd)
             auth = base64.b64encode(user_passwd).strip()
         else:
             auth = None
@@ -408,12 +410,12 @@ class URLopener:
                 #print "proxy via https:", host, selector
             if not host: raise IOError, ('https error', 'no host given')
             if proxy_passwd:
-                import base64
+                proxy_passwd = unquote(proxy_passwd)
                 proxy_auth = base64.b64encode(proxy_passwd).strip()
             else:
                 proxy_auth = None
             if user_passwd:
-                import base64
+                user_passwd = unquote(user_passwd)
                 auth = base64.b64encode(user_passwd).strip()
             else:
                 auth = None
@@ -589,7 +591,6 @@ class URLopener:
                                             time.gmtime(time.time())))
         msg.append('Content-type: %s' % type)
         if encoding == 'base64':
-            import base64
             data = base64.decodestring(data)
         else:
             data = unquote(data)
index 8bd308bd2699c1b29d6c4c8191466995e5e1847b..aa32dd75872ade9447668e72e362138087594d0e 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -89,6 +89,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #13642: Unquote before b64encoding user:password during Basic
+  Authentication. Patch contributed by Joonas Kuorilehto and Michele OrrĂ¹.
+
 - Issue #13636: Weak ciphers are now disabled by default in the ssl module
   (except when SSLv2 is explicitly asked for).