From 5cc157a749d4720144f4156c1d9fbd673e1dc68d Mon Sep 17 00:00:00 2001 From: Cuidight Heach Date: Sun, 10 Mar 2013 18:03:04 +0200 Subject: Added test for unicode basic authentication --- pyramid/tests/test_authentication.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pyramid/tests/test_authentication.py b/pyramid/tests/test_authentication.py index 123e4f9f5..c9313e0c6 100644 --- a/pyramid/tests/test_authentication.py +++ b/pyramid/tests/test_authentication.py @@ -1287,6 +1287,16 @@ 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 = u'm\xf6rk\xf6:m\xf6rk\xf6password' + request.headers['Authorization'] = 'Basic %s' % base64.b64encode(inputs.encode('utf-8')) + def check(username, password, request): + return [] + policy = self._makeOne(check) + self.assertEqual(policy.authenticated_userid(request), u'm\xf6rk\xf6') + def test_unauthenticated_userid_invalid_payload(self): import base64 request = testing.DummyRequest() -- cgit v1.2.3 From 3ac0b98a980a930ec9e6a6d4d364eb8af505a77c Mon Sep 17 00:00:00 2001 From: Cuidight Heach Date: Sun, 10 Mar 2013 20:36:47 +0200 Subject: Python 3 compatible string handling --- pyramid/tests/test_authentication.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyramid/tests/test_authentication.py b/pyramid/tests/test_authentication.py index c9313e0c6..e696a5754 100644 --- a/pyramid/tests/test_authentication.py +++ b/pyramid/tests/test_authentication.py @@ -1290,12 +1290,12 @@ class TestBasicAuthAuthenticationPolicy(unittest.TestCase): def test_authenticated_userid_utf8(self): import base64 request = testing.DummyRequest() - inputs = u'm\xf6rk\xf6:m\xf6rk\xf6password' + inputs = 'm\xc3\xb6rk\xc3\xb6:m\xc3\xb6rk\xc3\xb6password'.decode('utf-8') request.headers['Authorization'] = 'Basic %s' % base64.b64encode(inputs.encode('utf-8')) def check(username, password, request): return [] policy = self._makeOne(check) - self.assertEqual(policy.authenticated_userid(request), u'm\xf6rk\xf6') + self.assertEqual(policy.authenticated_userid(request), 'm\xc3\xb6rk\xc3\xb6'.decode('utf-8')) def test_unauthenticated_userid_invalid_payload(self): import base64 -- cgit v1.2.3 From dc8533aad4d432817b52f158804f0b6a81fab374 Mon Sep 17 00:00:00 2001 From: Cuidight Heach Date: Sun, 10 Mar 2013 20:59:00 +0200 Subject: Switched to bytes --- pyramid/tests/test_authentication.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyramid/tests/test_authentication.py b/pyramid/tests/test_authentication.py index e696a5754..97b2b1a7c 100644 --- a/pyramid/tests/test_authentication.py +++ b/pyramid/tests/test_authentication.py @@ -1290,12 +1290,12 @@ class TestBasicAuthAuthenticationPolicy(unittest.TestCase): def test_authenticated_userid_utf8(self): import base64 request = testing.DummyRequest() - inputs = 'm\xc3\xb6rk\xc3\xb6:m\xc3\xb6rk\xc3\xb6password'.decode('utf-8') + inputs = b'm\xc3\xb6rk\xc3\xb6:m\xc3\xb6rk\xc3\xb6password'.decode('utf-8') request.headers['Authorization'] = 'Basic %s' % base64.b64encode(inputs.encode('utf-8')) def check(username, password, request): return [] policy = self._makeOne(check) - self.assertEqual(policy.authenticated_userid(request), 'm\xc3\xb6rk\xc3\xb6'.decode('utf-8')) + self.assertEqual(policy.authenticated_userid(request), b'm\xc3\xb6rk\xc3\xb6'.decode('utf-8')) def test_unauthenticated_userid_invalid_payload(self): import base64 -- cgit v1.2.3 From 604297a083419278d85be47e40d1905043c38460 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sat, 19 Oct 2013 03:10:54 -0500 Subject: attempt to decode basic header as utf-8 and fallback to latin-1 fixes #898 fixes #904 --- pyramid/authentication.py | 9 ++++++++- pyramid/tests/test_authentication.py | 18 ++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/pyramid/authentication.py b/pyramid/authentication.py index 454ebd4b2..6b6fbd041 100644 --- a/pyramid/authentication.py +++ b/pyramid/authentication.py @@ -1176,10 +1176,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 19e95cf9a..ed6cc5903 100644 --- a/pyramid/tests/test_authentication.py +++ b/pyramid/tests/test_authentication.py @@ -1378,11 +1378,25 @@ class TestBasicAuthAuthenticationPolicy(unittest.TestCase): import base64 request = testing.DummyRequest() inputs = b'm\xc3\xb6rk\xc3\xb6:m\xc3\xb6rk\xc3\xb6password'.decode('utf-8') - request.headers['Authorization'] = 'Basic %s' % base64.b64encode(inputs.encode('utf-8')) + request.headers['Authorization'] = 'Basic %s' % ( + base64.b64encode(inputs.encode('utf-8'))) 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')) + 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:m\xc3\xb6rk\xc3\xb6password'.decode('utf-8') + request.headers['Authorization'] = 'Basic %s' % ( + base64.b64encode(inputs.encode('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 -- cgit v1.2.3 From 42f0cb2923200f07c89e011f80fe15e3c65caf03 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sat, 19 Oct 2013 03:18:05 -0500 Subject: update changelog --- CHANGES.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index a228fbb3a..f170308b0 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -32,6 +32,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 ------------- -- cgit v1.2.3 From 6c98b17ed9aadbe485c6473c3f76e1b2b529dc78 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sat, 19 Oct 2013 03:26:53 -0500 Subject: fix tests on py3 --- pyramid/tests/test_authentication.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pyramid/tests/test_authentication.py b/pyramid/tests/test_authentication.py index ed6cc5903..3ac8f2d61 100644 --- a/pyramid/tests/test_authentication.py +++ b/pyramid/tests/test_authentication.py @@ -1377,9 +1377,10 @@ class TestBasicAuthAuthenticationPolicy(unittest.TestCase): def test_authenticated_userid_utf8(self): import base64 request = testing.DummyRequest() - inputs = b'm\xc3\xb6rk\xc3\xb6:m\xc3\xb6rk\xc3\xb6password'.decode('utf-8') + 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'))) + base64.b64encode(inputs.encode('utf-8')).decode('latin-1')) def check(username, password, request): return [] policy = self._makeOne(check) @@ -1389,9 +1390,10 @@ class TestBasicAuthAuthenticationPolicy(unittest.TestCase): def test_authenticated_userid_latin1(self): import base64 request = testing.DummyRequest() - inputs = b'm\xc3\xb6rk\xc3\xb6:m\xc3\xb6rk\xc3\xb6password'.decode('utf-8') + 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'))) + base64.b64encode(inputs.encode('latin-1')).decode('latin-1')) def check(username, password, request): return [] policy = self._makeOne(check) -- cgit v1.2.3