From c895f874184371ff5798748b1c7234128ca4b25e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariusz=20G=C3=B3recki?= Date: Fri, 1 Jul 2016 09:42:30 +0100 Subject: ref #2659 public HTTP Basic credentials extraction --- pyramid/authentication.py | 77 ++++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/pyramid/authentication.py b/pyramid/authentication.py index 9bf1de62e..95d6a710d 100644 --- a/pyramid/authentication.py +++ b/pyramid/authentication.py @@ -1128,7 +1128,7 @@ class BasicAuthAuthenticationPolicy(CallbackAuthenticationPolicy): def unauthenticated_userid(self, request): """ The userid parsed from the ``Authorization`` request header.""" - credentials = self._get_credentials(request) + credentials = extract_http_basic_credentials(request) if credentials: return credentials[0] @@ -1145,42 +1145,14 @@ class BasicAuthAuthenticationPolicy(CallbackAuthenticationPolicy): return [('WWW-Authenticate', 'Basic realm="%s"' % self.realm)] def callback(self, username, request): - # Username arg is ignored. Unfortunately _get_credentials winds up + # Username arg is ignored. Unfortunately extract_http_basic_credentials winds up # getting called twice when authenticated_userid is called. Avoiding # that, however, winds up duplicating logic from the superclass. - credentials = self._get_credentials(request) + credentials = extract_http_basic_credentials(request) if credentials: username, password = credentials return self.check(username, password, request) - def _get_credentials(self, request): - authorization = request.headers.get('Authorization') - if not authorization: - return None - try: - authmeth, auth = authorization.split(' ', 1) - except ValueError: # not enough values to unpack - return None - if authmeth.lower() != 'basic': - return None - - try: - authbytes = b64decode(auth.strip()) - except (TypeError, binascii.Error): # can't decode - return None - - # try utf-8 first, then latin-1; see discussion in - # https://github.com/Pylons/pyramid/issues/898 - 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 - return None - return username, password class _SimpleSerializer(object): def loads(self, bstruct): @@ -1188,3 +1160,46 @@ class _SimpleSerializer(object): def dumps(self, appstruct): return bytes_(appstruct) + + +def extract_http_basic_credentials(request): + """ A helper function for extraction of HTTP Basic credentials + from a given `request`. + + ``request`` + The request object + """ + try: + # First try authorization extraction logic from WebOb + try: + authmeth, auth = request.authorization + except AttributeError: # Probably a DummyRequest + authorization = request.headers.get('Authorization') + if not authorization: + return None + + authmeth, auth = authorization.split(' ', 1) + except (ValueError, TypeError): + # not enough values to unpack or None is not iterable + return None + + if authmeth.lower() != 'basic': + return None + + try: + authbytes = b64decode(auth.strip()) + except (TypeError, binascii.Error): # can't decode + return None + + # try utf-8 first, then latin-1; see discussion in + # https://github.com/Pylons/pyramid/issues/898 + 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 + return None + return username, password -- cgit v1.2.3