Ticket #5066: 5066_patch_4.diff

File 5066_patch_4.diff, 5.7 KB (added by Dmitry, 9 years ago)
  • twisted/words/test/test_jabbersaslmechanisms.py

     
    55Tests for L{twisted.words.protocols.jabber.sasl_mechanisms}.
    66"""
    77
     8import binascii
     9
    810from twisted.trial import unittest
    911
    1012from twisted.words.protocols.jabber import sasl_mechanisms
     13from twisted.python.hashlib import md5
    1114
    1215class PlainTest(unittest.TestCase):
    1316    def test_getInitialResponse(self):
     
    7275        directives = self.mechanism._parse(self.mechanism.getResponse(challenge))
    7376        self.assertEqual(directives['realm'], 'example.org')
    7477
     78    def test__calculate_response(self):
     79        """
     80        Tests the response calculation.
     81
     82        Values were taken from RFC-2831 with additional unicode characters.
     83        """
     84
     85        charset = 'utf-8'
     86        nonce = 'OA6MG9tEQGm2hh'
     87        nc = '%08x' % 1
     88        cnonce = 'OA6MHXh6VqTrRk'
     89
     90        username = u'\u0418chris'.encode(charset)
     91        password = u'\u0418secret'.encode(charset)
     92        realm = u'\u0418elwood.innosoft.com'.encode(charset)
     93        digest_uri = u'imap/\u0418elwood.innosoft.com'.encode(charset)
     94       
     95        mechanism = sasl_mechanisms.DigestMD5('imap', realm, None,
     96                                            username, password)
     97        response = mechanism._calculate_response(cnonce, nc, nonce,
     98                                                 username, password,
     99                                                 realm, digest_uri)
     100        self.assertEqual(response, '7928f233258be88392424d094453c5e3')
     101
    75102    def test__parse(self):
    76103        """
    77104        Test challenge decoding.
  • twisted/words/protocols/jabber/sasl_mechanisms.py

     
    8585    name = 'DIGEST-MD5'
    8686
    8787    def __init__(self, serv_type, host, serv_name, username, password):
     88        """
     89        @type serv_type: C{unicode}
     90
     91        @type host: C{unicode}
     92
     93        @type serv_name: C{unicode}
     94
     95        @type username: C{unicode}
     96
     97        @type password: C{unicode}
     98        """
    8899        self.username = username
    89100        self.password = password
    90101        self.defaultRealm = host
    91102
    92         self.digest_uri = '%s/%s' % (serv_type, host)
     103        self.digest_uri = u'%s/%s' % (serv_type, host)
    93104        if serv_name is not None:
    94             self.digest_uri += '/%s' % serv_name
     105            self.digest_uri += u'/%s' % serv_name
    95106
    96107
    97108    def getInitialResponse(self):
     
    183194
    184195        return ','.join(directive_list)
    185196
    186 
    187     def _gen_response(self, charset, realm, nonce):
     197    def _calculate_response(self, cnonce, nc, nonce,
     198                            username, password, realm, uri):
    188199        """
    189         Generate response-value.
    190 
    191         Creates a response to a challenge according to section 2.1.2.1 of
    192         RFC 2831 using the C{charset}, C{realm} and C{nonce} directives
    193         from the challenge.
     200        Calculates response with given encoded parameters.
    194201        """
    195 
    196202        def H(s):
    197203            return md5(s).digest()
    198204
     
    202208        def KD(k, s):
    203209            return H('%s:%s' % (k, s))
    204210
     211        a1 = "%s:%s:%s" % (H("%s:%s:%s" % (username, realm, password)),
     212                                nonce, cnonce)
     213        a2 = "AUTHENTICATE:%s" % uri
     214        response = HEX( KD ( HEX(H(a1)),
     215                             "%s:%s:%s:%s:%s" % (nonce, nc,
     216                                        cnonce, "auth", HEX(H(a2)))))
     217        return response
     218
     219    def _gen_response(self, charset, realm, nonce):
     220        """
     221        Generate response-value.
     222
     223        Creates a response to a challenge according to section 2.1.2.1 of
     224        RFC 2831 using the C{charset}, C{realm} and C{nonce} directives
     225        from the challenge.
     226        """
     227
    205228        try:
    206229            username = self.username.encode(charset)
    207230            password = self.password.encode(charset)
     231            realm = realm.encode(charset)
     232            digest_uri = self.digest_uri.encode(charset)
    208233        except UnicodeError:
    209234            # TODO - add error checking
    210235            raise
     
    214239        qop = 'auth'
    215240
    216241        # TODO - add support for authzid
    217         a1 = "%s:%s:%s" % (H("%s:%s:%s" % (username, realm, password)),
    218                            nonce,
    219                            cnonce)
    220         a2 = "AUTHENTICATE:%s" % self.digest_uri
     242        response = self._calculate_response(cnonce, nc, nonce,
     243                                            username, password, realm,
     244                                            digest_uri)
    221245
    222         response = HEX( KD ( HEX(H(a1)),
    223                              "%s:%s:%s:%s:%s" % (nonce, nc,
    224                                                  cnonce, "auth", HEX(H(a2)))))
    225 
    226246        directives = {'username': username,
    227247                      'realm' : realm,
    228248                      'nonce' : nonce,
    229249                      'cnonce' : cnonce,
    230250                      'nc' : nc,
    231251                      'qop' : qop,
    232                       'digest-uri': self.digest_uri,
     252                      'digest-uri': digest_uri,
    233253                      'response': response,
    234254                      'charset': charset}
    235255
     
    237257
    238258
    239259    def _gen_nonce(self):
    240         return md5("%s:%s:%s" % (str(random.random()) , str(time.gmtime()),str(os.getpid()))).hexdigest()
     260        return md5("%s:%s:%s" % (random.random(),
     261                                 time.gmtime(),
     262                                 os.getpid())).hexdigest()