summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2013-10-20 16:17:51 -0400
committerChris McDonough <chrism@plope.com>2013-10-20 16:17:51 -0400
commit5688b6e76ba8059826ba6ff756b3e94b311320d2 (patch)
tree5074ba1d0d378b91b640e234c9c9267fcbe06015
parent0264cc0c3d4ca091d4d5c8bd0c2fda38a3f8a0c7 (diff)
parent2a6e6b3776b07589f8bbaaf4c72419f2bdf5e218 (diff)
downloadpyramid-5688b6e76ba8059826ba6ff756b3e94b311320d2.tar.gz
pyramid-5688b6e76ba8059826ba6ff756b3e94b311320d2.tar.bz2
pyramid-5688b6e76ba8059826ba6ff756b3e94b311320d2.zip
Merge branch 'fix.basic-authentication-encodings'
-rw-r--r--CHANGES.txt6
-rw-r--r--pyramid/authentication.py9
-rw-r--r--pyramid/tests/test_authentication.py26
3 files changed, 40 insertions, 1 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index e215b21bc..15b1b910e 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -51,6 +51,12 @@ Bug Fixes
- Remove unused ``renderer`` argument from ``Configurator.add_route``.
+- Allow the ``BasicAuthenticationPolicy`` to work with non-ascii usernames
+ and passwords. The charset is not passed as part of the header and different
+ browsers alternate between UTF-8 and Latin-1, so the policy now attempts
+ to decode with UTF-8 first, and will fallback to Latin-1.
+ See https://github.com/Pylons/pyramid/pull/1170
+
Documentation
-------------
diff --git a/pyramid/authentication.py b/pyramid/authentication.py
index 3c4077073..ec8ac0a41 100644
--- a/pyramid/authentication.py
+++ b/pyramid/authentication.py
@@ -1178,10 +1178,17 @@ class BasicAuthAuthenticationPolicy(CallbackAuthenticationPolicy):
return None
if authmeth.lower() != 'basic':
return None
+
try:
- auth = b64decode(auth.strip()).decode('ascii')
+ authbytes = b64decode(auth.strip())
except (TypeError, binascii.Error): # can't decode
return None
+
+ try:
+ auth = authbytes.decode('utf-8')
+ except UnicodeDecodeError:
+ auth = authbytes.decode('latin-1')
+
try:
username, password = auth.split(':', 1)
except ValueError: # not enough values to unpack
diff --git a/pyramid/tests/test_authentication.py b/pyramid/tests/test_authentication.py
index 6e9e3920d..3ac8f2d61 100644
--- a/pyramid/tests/test_authentication.py
+++ b/pyramid/tests/test_authentication.py
@@ -1374,6 +1374,32 @@ class TestBasicAuthAuthenticationPolicy(unittest.TestCase):
policy = self._makeOne(check)
self.assertEqual(policy.authenticated_userid(request), 'chrisr')
+ def test_authenticated_userid_utf8(self):
+ import base64
+ request = testing.DummyRequest()
+ inputs = (b'm\xc3\xb6rk\xc3\xb6:'
+ b'm\xc3\xb6rk\xc3\xb6password').decode('utf-8')
+ request.headers['Authorization'] = 'Basic %s' % (
+ base64.b64encode(inputs.encode('utf-8')).decode('latin-1'))
+ def check(username, password, request):
+ return []
+ policy = self._makeOne(check)
+ self.assertEqual(policy.authenticated_userid(request),
+ b'm\xc3\xb6rk\xc3\xb6'.decode('utf-8'))
+
+ def test_authenticated_userid_latin1(self):
+ import base64
+ request = testing.DummyRequest()
+ inputs = (b'm\xc3\xb6rk\xc3\xb6:'
+ b'm\xc3\xb6rk\xc3\xb6password').decode('utf-8')
+ request.headers['Authorization'] = 'Basic %s' % (
+ base64.b64encode(inputs.encode('latin-1')).decode('latin-1'))
+ def check(username, password, request):
+ return []
+ policy = self._makeOne(check)
+ self.assertEqual(policy.authenticated_userid(request),
+ b'm\xc3\xb6rk\xc3\xb6'.decode('utf-8'))
+
def test_unauthenticated_userid_invalid_payload(self):
import base64
request = testing.DummyRequest()