diff options
Diffstat (limited to 'lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/test/test_digestauth.py')
-rwxr-xr-x | lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/test/test_digestauth.py | 671 |
1 files changed, 0 insertions, 671 deletions
diff --git a/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/test/test_digestauth.py b/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/test/test_digestauth.py deleted file mode 100755 index 41368a02..00000000 --- a/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/test/test_digestauth.py +++ /dev/null @@ -1,671 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.cred._digest} and the associated bits in -L{twisted.cred.credentials}. -""" - -from zope.interface.verify import verifyObject -from twisted.trial.unittest import TestCase -from twisted.python.hashlib import md5, sha1 -from twisted.internet.address import IPv4Address -from twisted.cred.error import LoginFailed -from twisted.cred.credentials import calcHA1, calcHA2, IUsernameDigestHash -from twisted.cred.credentials import calcResponse, DigestCredentialFactory - -def b64encode(s): - return s.encode('base64').strip() - - -class FakeDigestCredentialFactory(DigestCredentialFactory): - """ - A Fake Digest Credential Factory that generates a predictable - nonce and opaque - """ - def __init__(self, *args, **kwargs): - super(FakeDigestCredentialFactory, self).__init__(*args, **kwargs) - self.privateKey = "0" - - - def _generateNonce(self): - """ - Generate a static nonce - """ - return '178288758716122392881254770685' - - - def _getTime(self): - """ - Return a stable time - """ - return 0 - - - -class DigestAuthTests(TestCase): - """ - L{TestCase} mixin class which defines a number of tests for - L{DigestCredentialFactory}. Because this mixin defines C{setUp}, it - must be inherited before L{TestCase}. - """ - def setUp(self): - """ - Create a DigestCredentialFactory for testing - """ - self.username = "foobar" - self.password = "bazquux" - self.realm = "test realm" - self.algorithm = "md5" - self.cnonce = "29fc54aa1641c6fa0e151419361c8f23" - self.qop = "auth" - self.uri = "/write/" - self.clientAddress = IPv4Address('TCP', '10.2.3.4', 43125) - self.method = 'GET' - self.credentialFactory = DigestCredentialFactory( - self.algorithm, self.realm) - - - def test_MD5HashA1(self, _algorithm='md5', _hash=md5): - """ - L{calcHA1} accepts the C{'md5'} algorithm and returns an MD5 hash of - its parameters, excluding the nonce and cnonce. - """ - nonce = 'abc123xyz' - hashA1 = calcHA1(_algorithm, self.username, self.realm, self.password, - nonce, self.cnonce) - a1 = '%s:%s:%s' % (self.username, self.realm, self.password) - expected = _hash(a1).hexdigest() - self.assertEqual(hashA1, expected) - - - def test_MD5SessionHashA1(self): - """ - L{calcHA1} accepts the C{'md5-sess'} algorithm and returns an MD5 hash - of its parameters, including the nonce and cnonce. - """ - nonce = 'xyz321abc' - hashA1 = calcHA1('md5-sess', self.username, self.realm, self.password, - nonce, self.cnonce) - a1 = '%s:%s:%s' % (self.username, self.realm, self.password) - ha1 = md5(a1).digest() - a1 = '%s:%s:%s' % (ha1, nonce, self.cnonce) - expected = md5(a1).hexdigest() - self.assertEqual(hashA1, expected) - - - def test_SHAHashA1(self): - """ - L{calcHA1} accepts the C{'sha'} algorithm and returns a SHA hash of its - parameters, excluding the nonce and cnonce. - """ - self.test_MD5HashA1('sha', sha1) - - - def test_MD5HashA2Auth(self, _algorithm='md5', _hash=md5): - """ - L{calcHA2} accepts the C{'md5'} algorithm and returns an MD5 hash of - its arguments, excluding the entity hash for QOP other than - C{'auth-int'}. - """ - method = 'GET' - hashA2 = calcHA2(_algorithm, method, self.uri, 'auth', None) - a2 = '%s:%s' % (method, self.uri) - expected = _hash(a2).hexdigest() - self.assertEqual(hashA2, expected) - - - def test_MD5HashA2AuthInt(self, _algorithm='md5', _hash=md5): - """ - L{calcHA2} accepts the C{'md5'} algorithm and returns an MD5 hash of - its arguments, including the entity hash for QOP of C{'auth-int'}. - """ - method = 'GET' - hentity = 'foobarbaz' - hashA2 = calcHA2(_algorithm, method, self.uri, 'auth-int', hentity) - a2 = '%s:%s:%s' % (method, self.uri, hentity) - expected = _hash(a2).hexdigest() - self.assertEqual(hashA2, expected) - - - def test_MD5SessHashA2Auth(self): - """ - L{calcHA2} accepts the C{'md5-sess'} algorithm and QOP of C{'auth'} and - returns the same value as it does for the C{'md5'} algorithm. - """ - self.test_MD5HashA2Auth('md5-sess') - - - def test_MD5SessHashA2AuthInt(self): - """ - L{calcHA2} accepts the C{'md5-sess'} algorithm and QOP of C{'auth-int'} - and returns the same value as it does for the C{'md5'} algorithm. - """ - self.test_MD5HashA2AuthInt('md5-sess') - - - def test_SHAHashA2Auth(self): - """ - L{calcHA2} accepts the C{'sha'} algorithm and returns a SHA hash of - its arguments, excluding the entity hash for QOP other than - C{'auth-int'}. - """ - self.test_MD5HashA2Auth('sha', sha1) - - - def test_SHAHashA2AuthInt(self): - """ - L{calcHA2} accepts the C{'sha'} algorithm and returns a SHA hash of - its arguments, including the entity hash for QOP of C{'auth-int'}. - """ - self.test_MD5HashA2AuthInt('sha', sha1) - - - def test_MD5HashResponse(self, _algorithm='md5', _hash=md5): - """ - L{calcResponse} accepts the C{'md5'} algorithm and returns an MD5 hash - of its parameters, excluding the nonce count, client nonce, and QoP - value if the nonce count and client nonce are C{None} - """ - hashA1 = 'abc123' - hashA2 = '789xyz' - nonce = 'lmnopq' - - response = '%s:%s:%s' % (hashA1, nonce, hashA2) - expected = _hash(response).hexdigest() - - digest = calcResponse(hashA1, hashA2, _algorithm, nonce, None, None, - None) - self.assertEqual(expected, digest) - - - def test_MD5SessionHashResponse(self): - """ - L{calcResponse} accepts the C{'md5-sess'} algorithm and returns an MD5 - hash of its parameters, excluding the nonce count, client nonce, and - QoP value if the nonce count and client nonce are C{None} - """ - self.test_MD5HashResponse('md5-sess') - - - def test_SHAHashResponse(self): - """ - L{calcResponse} accepts the C{'sha'} algorithm and returns a SHA hash - of its parameters, excluding the nonce count, client nonce, and QoP - value if the nonce count and client nonce are C{None} - """ - self.test_MD5HashResponse('sha', sha1) - - - def test_MD5HashResponseExtra(self, _algorithm='md5', _hash=md5): - """ - L{calcResponse} accepts the C{'md5'} algorithm and returns an MD5 hash - of its parameters, including the nonce count, client nonce, and QoP - value if they are specified. - """ - hashA1 = 'abc123' - hashA2 = '789xyz' - nonce = 'lmnopq' - nonceCount = '00000004' - clientNonce = 'abcxyz123' - qop = 'auth' - - response = '%s:%s:%s:%s:%s:%s' % ( - hashA1, nonce, nonceCount, clientNonce, qop, hashA2) - expected = _hash(response).hexdigest() - - digest = calcResponse( - hashA1, hashA2, _algorithm, nonce, nonceCount, clientNonce, qop) - self.assertEqual(expected, digest) - - - def test_MD5SessionHashResponseExtra(self): - """ - L{calcResponse} accepts the C{'md5-sess'} algorithm and returns an MD5 - hash of its parameters, including the nonce count, client nonce, and - QoP value if they are specified. - """ - self.test_MD5HashResponseExtra('md5-sess') - - - def test_SHAHashResponseExtra(self): - """ - L{calcResponse} accepts the C{'sha'} algorithm and returns a SHA hash - of its parameters, including the nonce count, client nonce, and QoP - value if they are specified. - """ - self.test_MD5HashResponseExtra('sha', sha1) - - - def formatResponse(self, quotes=True, **kw): - """ - Format all given keyword arguments and their values suitably for use as - the value of an HTTP header. - - @types quotes: C{bool} - @param quotes: A flag indicating whether to quote the values of each - field in the response. - - @param **kw: Keywords and C{str} values which will be treated as field - name/value pairs to include in the result. - - @rtype: C{str} - @return: The given fields formatted for use as an HTTP header value. - """ - if 'username' not in kw: - kw['username'] = self.username - if 'realm' not in kw: - kw['realm'] = self.realm - if 'algorithm' not in kw: - kw['algorithm'] = self.algorithm - if 'qop' not in kw: - kw['qop'] = self.qop - if 'cnonce' not in kw: - kw['cnonce'] = self.cnonce - if 'uri' not in kw: - kw['uri'] = self.uri - if quotes: - quote = '"' - else: - quote = '' - return ', '.join([ - '%s=%s%s%s' % (k, quote, v, quote) - for (k, v) - in kw.iteritems() - if v is not None]) - - - def getDigestResponse(self, challenge, ncount): - """ - Calculate the response for the given challenge - """ - nonce = challenge.get('nonce') - algo = challenge.get('algorithm').lower() - qop = challenge.get('qop') - - ha1 = calcHA1( - algo, self.username, self.realm, self.password, nonce, self.cnonce) - ha2 = calcHA2(algo, "GET", self.uri, qop, None) - expected = calcResponse(ha1, ha2, algo, nonce, ncount, self.cnonce, qop) - return expected - - - def test_response(self, quotes=True): - """ - L{DigestCredentialFactory.decode} accepts a digest challenge response - and parses it into an L{IUsernameHashedPassword} provider. - """ - challenge = self.credentialFactory.getChallenge(self.clientAddress.host) - - nc = "00000001" - clientResponse = self.formatResponse( - quotes=quotes, - nonce=challenge['nonce'], - response=self.getDigestResponse(challenge, nc), - nc=nc, - opaque=challenge['opaque']) - creds = self.credentialFactory.decode( - clientResponse, self.method, self.clientAddress.host) - self.assertTrue(creds.checkPassword(self.password)) - self.assertFalse(creds.checkPassword(self.password + 'wrong')) - - - def test_responseWithoutQuotes(self): - """ - L{DigestCredentialFactory.decode} accepts a digest challenge response - which does not quote the values of its fields and parses it into an - L{IUsernameHashedPassword} provider in the same way it would a - response which included quoted field values. - """ - self.test_response(False) - - - def test_caseInsensitiveAlgorithm(self): - """ - The case of the algorithm value in the response is ignored when - checking the credentials. - """ - self.algorithm = 'MD5' - self.test_response() - - - def test_md5DefaultAlgorithm(self): - """ - The algorithm defaults to MD5 if it is not supplied in the response. - """ - self.algorithm = None - self.test_response() - - - def test_responseWithoutClientIP(self): - """ - L{DigestCredentialFactory.decode} accepts a digest challenge response - even if the client address it is passed is C{None}. - """ - challenge = self.credentialFactory.getChallenge(None) - - nc = "00000001" - clientResponse = self.formatResponse( - nonce=challenge['nonce'], - response=self.getDigestResponse(challenge, nc), - nc=nc, - opaque=challenge['opaque']) - creds = self.credentialFactory.decode(clientResponse, self.method, None) - self.assertTrue(creds.checkPassword(self.password)) - self.assertFalse(creds.checkPassword(self.password + 'wrong')) - - - def test_multiResponse(self): - """ - L{DigestCredentialFactory.decode} handles multiple responses to a - single challenge. - """ - challenge = self.credentialFactory.getChallenge(self.clientAddress.host) - - nc = "00000001" - clientResponse = self.formatResponse( - nonce=challenge['nonce'], - response=self.getDigestResponse(challenge, nc), - nc=nc, - opaque=challenge['opaque']) - - creds = self.credentialFactory.decode(clientResponse, self.method, - self.clientAddress.host) - self.assertTrue(creds.checkPassword(self.password)) - self.assertFalse(creds.checkPassword(self.password + 'wrong')) - - nc = "00000002" - clientResponse = self.formatResponse( - nonce=challenge['nonce'], - response=self.getDigestResponse(challenge, nc), - nc=nc, - opaque=challenge['opaque']) - - creds = self.credentialFactory.decode(clientResponse, self.method, - self.clientAddress.host) - self.assertTrue(creds.checkPassword(self.password)) - self.assertFalse(creds.checkPassword(self.password + 'wrong')) - - - def test_failsWithDifferentMethod(self): - """ - L{DigestCredentialFactory.decode} returns an L{IUsernameHashedPassword} - provider which rejects a correct password for the given user if the - challenge response request is made using a different HTTP method than - was used to request the initial challenge. - """ - challenge = self.credentialFactory.getChallenge(self.clientAddress.host) - - nc = "00000001" - clientResponse = self.formatResponse( - nonce=challenge['nonce'], - response=self.getDigestResponse(challenge, nc), - nc=nc, - opaque=challenge['opaque']) - creds = self.credentialFactory.decode(clientResponse, 'POST', - self.clientAddress.host) - self.assertFalse(creds.checkPassword(self.password)) - self.assertFalse(creds.checkPassword(self.password + 'wrong')) - - - def test_noUsername(self): - """ - L{DigestCredentialFactory.decode} raises L{LoginFailed} if the response - has no username field or if the username field is empty. - """ - # Check for no username - e = self.assertRaises( - LoginFailed, - self.credentialFactory.decode, - self.formatResponse(username=None), - self.method, self.clientAddress.host) - self.assertEqual(str(e), "Invalid response, no username given.") - - # Check for an empty username - e = self.assertRaises( - LoginFailed, - self.credentialFactory.decode, - self.formatResponse(username=""), - self.method, self.clientAddress.host) - self.assertEqual(str(e), "Invalid response, no username given.") - - - def test_noNonce(self): - """ - L{DigestCredentialFactory.decode} raises L{LoginFailed} if the response - has no nonce. - """ - e = self.assertRaises( - LoginFailed, - self.credentialFactory.decode, - self.formatResponse(opaque="abc123"), - self.method, self.clientAddress.host) - self.assertEqual(str(e), "Invalid response, no nonce given.") - - - def test_noOpaque(self): - """ - L{DigestCredentialFactory.decode} raises L{LoginFailed} if the response - has no opaque. - """ - e = self.assertRaises( - LoginFailed, - self.credentialFactory.decode, - self.formatResponse(), - self.method, self.clientAddress.host) - self.assertEqual(str(e), "Invalid response, no opaque given.") - - - def test_checkHash(self): - """ - L{DigestCredentialFactory.decode} returns an L{IUsernameDigestHash} - provider which can verify a hash of the form 'username:realm:password'. - """ - challenge = self.credentialFactory.getChallenge(self.clientAddress.host) - - nc = "00000001" - clientResponse = self.formatResponse( - nonce=challenge['nonce'], - response=self.getDigestResponse(challenge, nc), - nc=nc, - opaque=challenge['opaque']) - - creds = self.credentialFactory.decode(clientResponse, self.method, - self.clientAddress.host) - self.assertTrue(verifyObject(IUsernameDigestHash, creds)) - - cleartext = '%s:%s:%s' % (self.username, self.realm, self.password) - hash = md5(cleartext) - self.assertTrue(creds.checkHash(hash.hexdigest())) - hash.update('wrong') - self.assertFalse(creds.checkHash(hash.hexdigest())) - - - def test_invalidOpaque(self): - """ - L{DigestCredentialFactory.decode} raises L{LoginFailed} when the opaque - value does not contain all the required parts. - """ - credentialFactory = FakeDigestCredentialFactory(self.algorithm, - self.realm) - challenge = credentialFactory.getChallenge(self.clientAddress.host) - - exc = self.assertRaises( - LoginFailed, - credentialFactory._verifyOpaque, - 'badOpaque', - challenge['nonce'], - self.clientAddress.host) - self.assertEqual(str(exc), 'Invalid response, invalid opaque value') - - badOpaque = 'foo-' + b64encode('nonce,clientip') - - exc = self.assertRaises( - LoginFailed, - credentialFactory._verifyOpaque, - badOpaque, - challenge['nonce'], - self.clientAddress.host) - self.assertEqual(str(exc), 'Invalid response, invalid opaque value') - - exc = self.assertRaises( - LoginFailed, - credentialFactory._verifyOpaque, - '', - challenge['nonce'], - self.clientAddress.host) - self.assertEqual(str(exc), 'Invalid response, invalid opaque value') - - badOpaque = ( - 'foo-' + b64encode('%s,%s,foobar' % ( - challenge['nonce'], - self.clientAddress.host))) - exc = self.assertRaises( - LoginFailed, - credentialFactory._verifyOpaque, - badOpaque, - challenge['nonce'], - self.clientAddress.host) - self.assertEqual( - str(exc), 'Invalid response, invalid opaque/time values') - - - def test_incompatibleNonce(self): - """ - L{DigestCredentialFactory.decode} raises L{LoginFailed} when the given - nonce from the response does not match the nonce encoded in the opaque. - """ - credentialFactory = FakeDigestCredentialFactory(self.algorithm, self.realm) - challenge = credentialFactory.getChallenge(self.clientAddress.host) - - badNonceOpaque = credentialFactory._generateOpaque( - '1234567890', - self.clientAddress.host) - - exc = self.assertRaises( - LoginFailed, - credentialFactory._verifyOpaque, - badNonceOpaque, - challenge['nonce'], - self.clientAddress.host) - self.assertEqual( - str(exc), - 'Invalid response, incompatible opaque/nonce values') - - exc = self.assertRaises( - LoginFailed, - credentialFactory._verifyOpaque, - badNonceOpaque, - '', - self.clientAddress.host) - self.assertEqual( - str(exc), - 'Invalid response, incompatible opaque/nonce values') - - - def test_incompatibleClientIP(self): - """ - L{DigestCredentialFactory.decode} raises L{LoginFailed} when the - request comes from a client IP other than what is encoded in the - opaque. - """ - credentialFactory = FakeDigestCredentialFactory(self.algorithm, self.realm) - challenge = credentialFactory.getChallenge(self.clientAddress.host) - - badAddress = '10.0.0.1' - # Sanity check - self.assertNotEqual(self.clientAddress.host, badAddress) - - badNonceOpaque = credentialFactory._generateOpaque( - challenge['nonce'], badAddress) - - self.assertRaises( - LoginFailed, - credentialFactory._verifyOpaque, - badNonceOpaque, - challenge['nonce'], - self.clientAddress.host) - - - def test_oldNonce(self): - """ - L{DigestCredentialFactory.decode} raises L{LoginFailed} when the given - opaque is older than C{DigestCredentialFactory.CHALLENGE_LIFETIME_SECS} - """ - credentialFactory = FakeDigestCredentialFactory(self.algorithm, - self.realm) - challenge = credentialFactory.getChallenge(self.clientAddress.host) - - key = '%s,%s,%s' % (challenge['nonce'], - self.clientAddress.host, - '-137876876') - digest = md5(key + credentialFactory.privateKey).hexdigest() - ekey = b64encode(key) - - oldNonceOpaque = '%s-%s' % (digest, ekey.strip('\n')) - - self.assertRaises( - LoginFailed, - credentialFactory._verifyOpaque, - oldNonceOpaque, - challenge['nonce'], - self.clientAddress.host) - - - def test_mismatchedOpaqueChecksum(self): - """ - L{DigestCredentialFactory.decode} raises L{LoginFailed} when the opaque - checksum fails verification. - """ - credentialFactory = FakeDigestCredentialFactory(self.algorithm, - self.realm) - challenge = credentialFactory.getChallenge(self.clientAddress.host) - - key = '%s,%s,%s' % (challenge['nonce'], - self.clientAddress.host, - '0') - - digest = md5(key + 'this is not the right pkey').hexdigest() - badChecksum = '%s-%s' % (digest, b64encode(key)) - - self.assertRaises( - LoginFailed, - credentialFactory._verifyOpaque, - badChecksum, - challenge['nonce'], - self.clientAddress.host) - - - def test_incompatibleCalcHA1Options(self): - """ - L{calcHA1} raises L{TypeError} when any of the pszUsername, pszRealm, - or pszPassword arguments are specified with the preHA1 keyword - argument. - """ - arguments = ( - ("user", "realm", "password", "preHA1"), - (None, "realm", None, "preHA1"), - (None, None, "password", "preHA1"), - ) - - for pszUsername, pszRealm, pszPassword, preHA1 in arguments: - self.assertRaises( - TypeError, - calcHA1, - "md5", - pszUsername, - pszRealm, - pszPassword, - "nonce", - "cnonce", - preHA1=preHA1) - - - def test_noNewlineOpaque(self): - """ - L{DigestCredentialFactory._generateOpaque} returns a value without - newlines, regardless of the length of the nonce. - """ - opaque = self.credentialFactory._generateOpaque( - "long nonce " * 10, None) - self.assertNotIn('\n', opaque) |