From 1696718c0b89b7562f13135a91356358933c27c4 Mon Sep 17 00:00:00 2001 From: Helmut Grohne Date: Thu, 1 Dec 2011 15:07:19 +0100 Subject: respect RFC2617 in terms of what is quoted Said RFC is quite precise on which values of a challenge are to be quoted. I didn't honour those parts and many applications do not enforce these requirements, so I didn't notice. Now I explain which values are to be quoted in the hopes that it works with "Wget/1.10.2 (Red Hat modified)". --- wsgitools/digest.py | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/wsgitools/digest.py b/wsgitools/digest.py index 6781e94..0acfa34 100644 --- a/wsgitools/digest.py +++ b/wsgitools/digest.py @@ -111,14 +111,22 @@ def parse_digest_response(data, ret=None): def format_digest(mapping): """internal - @type mapping: {str: str} + @type mapping: {str: (str, bool)} + @param mapping: a mapping of keys to values and a boolean that + determines whether the value needs quoting. @rtype: str + @note: the RFC specifies which values must be quoted and which must not be + quoted. """ assert isinstance(mapping, dict) - result = ((key, value if value.isalnum() else - '"%s"' % value.replace('\\', '\\\\').replace('"', '\\"')) - for key, value in mapping.items()) - result = map("%s=%s".__mod__, result) + result = [] + for key, (value, needsquoting) in mapping.items(): + if needsquoting: + value = '"%s"' % value.replace('\\', '\\\\').replace('"', '\\"') + else: + assert '"' not in value + assert ',' not in value + result.append("%s=%s" % (key, value)) return ", ".join(result) class StaleNonce(AuthenticationRequired): @@ -741,11 +749,11 @@ class AuthDigestMiddleware(AuthenticationMiddleware): if response is None or response != credresponse: raise AuthenticationRequired("wrong response") - digest = dict(nextnonce=self.noncestore.newnonce()) + digest = dict(nextnonce=(self.noncestore.newnonce(), True)) if "qop" in credentials: - digest["qop"] = "auth" - digest["cnonce"] = credentials["cnonce"] # no KeyError - digest["rspauth"] = self.auth_response(credentials, "") + digest["qop"] = ("auth", False) + digest["cnonce"] = (credentials["cnonce"], True) # no KeyError + digest["rspauth"] = (self.auth_response(credentials, ""), True) return dict(user=credentials["username"], outheaders=[("Authentication-Info", format_digest(digest))]) @@ -785,11 +793,11 @@ class AuthDigestMiddleware(AuthenticationMiddleware): return self.algorithms[algo](":".join(dig)) def www_authenticate(self, exception): - digest = dict(nonce=self.noncestore.newnonce(), - realm=self.gentoken.realm, - algorithm="md5", - qop="auth") + digest = dict(nonce=(self.noncestore.newnonce(), True), + realm=(self.gentoken.realm, True), + algorithm=("MD5", False), + qop=("auth", False)) if isinstance(exception, StaleNonce): - digest["stale"] = "TRUE" + digest["stale"] = ("TRUE", False) challenge = format_digest(digest) return ("WWW-Authenticate", "Digest %s" % challenge) -- cgit v1.2.3