summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHelmut Grohne <helmut@subdivi.de>2011-12-01 15:07:19 +0100
committerHelmut Grohne <helmut@subdivi.de>2011-12-01 15:07:19 +0100
commit1696718c0b89b7562f13135a91356358933c27c4 (patch)
treeb3bbc87a17039c6668d28bfbbfe171492c3a873a
parent2c607a3b8e0584fa20ce38095c9158f623501cee (diff)
downloadwsgitools-1696718c0b89b7562f13135a91356358933c27c4.tar.gz
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)".
-rw-r--r--wsgitools/digest.py36
1 files 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)