From 56be1861917a9081a3883ae3b080d4683b52402c Mon Sep 17 00:00:00 2001 From: Helmut Grohne Date: Sun, 29 Mar 2009 23:27:33 +0200 Subject: improve digest module (killed isnonce method) Prior to this change the digest module would check whether a nonce looks like a nonce, verify the response and then verify the nonce. This left a bit more room for brute forcing passwords, as the same nonce could be used in arbitrary many tries and a stale response would indicate an authentication success. Now authentication is only tried for valid nonces. This also makes the NonceStoreBase.isnonce method superfluous. --- wsgitools/digest.py | 80 +++++++++-------------------------------------------- 1 file changed, 13 insertions(+), 67 deletions(-) (limited to 'wsgitools/digest.py') diff --git a/wsgitools/digest.py b/wsgitools/digest.py index cbd374b..aa1dc83 100755 --- a/wsgitools/digest.py +++ b/wsgitools/digest.py @@ -98,22 +98,10 @@ class NonceStoreBase: @rtype: str """ raise NotImplementedError - def isnonce(self, nonce, ident=None): - """ - This method is to be overridden and should do a quick check for whether - the given nonce has a chance to be a valid one. This function must not - return false for a stale nonce. - @type nonce: str - @type ident: str - @param ident: it is also checked that the nonce was associated to this - identifier when given - @rtype: bool - """ - raise NotImplementedError def checknonce(self, nonce, count=1, ident=None): """ - This method is to be overridden and should do a thorough check for - whether the given nonce is a valid as being used count times. + This method is to be overridden and should do a check for whether the + given nonce is valid as being used count times. @type nonce: str @type count: int @param count: indicates how often the nonce has been used (including @@ -147,8 +135,6 @@ class StatelessNonceStore(NonceStoreBase): >>> n = s.newnonce() >>> s.checknonce("spam") False - >>> s.isnonce(n) - True >>> s.checknonce(n) True >>> s.checknonce(n) @@ -184,27 +170,10 @@ class StatelessNonceStore(NonceStoreBase): token = md5(token).hexdigest() return "%s:%s:%s" % (nonce_time, nonce_value, token) - def isnonce(self, nonce, ident=None): - """ - Do a quick a stateless check for whether the provides string might - be a nonce. - @type nonce: str - @rtype: bool - """ - try: - nonce_time, nonce_value, nonce_hash = nonce.split(':') - except ValueError: - return False - token = "%s:%s:%s" % (nonce_time, nonce_value, self.server_secret) - if ident is not None: - token = "%s:%s" % (token, ident) - token = md5(token).hexdigest() - return nonce_hash == token - def checknonce(self, nonce, count=1, ident=None): """ - Do a thorough check for whether the provided string is a nonce and - increase usage count on returning True. + Do a check for whether the provided string is a nonce and increase usage + count on returning True. @type nonce: str @type count: int @rtype: bool @@ -235,8 +204,6 @@ class MemoryNonceStore(NonceStoreBase): >>> n = s.newnonce() >>> s.checknonce("spam") False - >>> s.isnonce(n) - True >>> s.checknonce(n) True >>> s.checknonce(n) @@ -281,27 +248,10 @@ class MemoryNonceStore(NonceStoreBase): token = md5(token).hexdigest() return "%s:%s:%s" % (nonce_time, nonce_value, token) - def isnonce(self, nonce, ident=None): - """ - Do a quick a stateless check for whether the provides string might - be a nonce. - @type nonce: str - @rtype: bool - """ - try: - nonce_time, nonce_value, nonce_hash = nonce.split(':') - except ValueError: - return False - token = "%s:%s:%s" % (nonce_time, nonce_value, self.server_secret) - if ident is not None: - token = "%s:%s" % (nonce, ident) - token = md5(token).hexdigest() - return nonce_hash == token - def checknonce(self, nonce, count=1, ident=None): """ - Do a thorough check for whether the provided string is a nonce and - increase usage count on returning True. + Do a check for whether the provided string is a nonce and increase usage + count on returning True. @type nonce: str @type count: int @rtype: bool @@ -367,7 +317,6 @@ class AuthDigestMiddleware: self.noncestore = MemoryNonceStore(maxage, maxuses) else: assert hasattr(store, "newnonce") - assert hasattr(store, "isnonce") assert hasattr(store, "checknonce") self.noncestore = store @@ -419,16 +368,6 @@ class AuthDigestMiddleware: "cnonce" not in credentials)): raise AuthenticationRequired - if not self.noncestore.isnonce(credentials["nonce"]): - raise AuthenticationRequired - - # raises KeyError, ValueError - response = self.auth_response(credentials, - environ["REQUEST_METHOD"]) - - if response is None or response != credentials["response"]: - raise AuthenticationRequired - noncecount = 1 if credentials.get("qop") is not None: # raises ValueError @@ -438,6 +377,13 @@ class AuthDigestMiddleware: return self.authorization_required(environ, start_response, stale=True) # stale nonce! + # raises KeyError, ValueError + response = self.auth_response(credentials, + environ["REQUEST_METHOD"]) + + if response != credentials["response"]: + raise AuthenticationRequired + except (KeyError, ValueError, AuthenticationRequired): return self.authorization_required(environ, start_response) else: -- cgit v1.2.3