diff -r ef4d1846c09a Lib/imaplib.py --- a/Lib/imaplib.py Tue Jan 03 22:31:23 2012 +0200 +++ b/Lib/imaplib.py Tue Jan 03 23:22:17 2012 +0200 @@ -538,7 +538,7 @@ def _CRAM_MD5_AUTH(self, challenge): """ Authobject to use with CRAM-MD5 authentication. """ import hmac - return self.user + " " + hmac.HMAC(self.password, challenge).hexdigest() + return self.user + " " + hmac.HMAC(self.password.encode(), challenge).hexdigest() def logout(self): diff -r ef4d1846c09a Lib/test/test_imaplib.py --- a/Lib/test/test_imaplib.py Tue Jan 03 22:31:23 2012 +0200 +++ b/Lib/test/test_imaplib.py Tue Jan 03 23:22:17 2012 +0200 @@ -242,6 +242,48 @@ self.assertRaises(imaplib.IMAP4.abort, self.imap_class, *server.server_address) + @reap_threads + def test_login_cram_md5(self): + """ Tests CRAM-MD5 authentication and logging out """ + + class AuthHandler(SimpleIMAPHandler): + + def cmd_CAPABILITY(self, tag, args): + self._send(b'* CAPABILITY IMAP4rev1 LOGINDISABLED AUTH=CRAM-MD5\r\n') + self._send('{} OK Capability completed.\r\n'.format(tag).encode('ASCII')) + + def cmd_AUTHENTICATE(self, tag, args): + self._send(b'+ PDE4OTYuNjk3MTcwOTUyQHBvc3RvZmZpY2UucmVzdG9uLm1jaS5uZXQ+\r\n') + self._contcmd = self._cmd_AUTHENTICATE_CONT + + def _cmd_AUTHENTICATE_CONT(self, tag, args): + if args == b"dGltIGI5MTNhNjAyYzdlZGE3YTQ5NWI0ZTZlNzMzNGQzODkw\r\n": + self._send('{} OK CRAM-MD5 authentication successful\r\n' + .format(tag).encode('ASCII')) + else: + self._send('{} NO No access\r\n'.format(tag).encode('ASCII')) + self._contcmd = None + + def cmd_LOGOUT(self, tag, args): + self._send(b'* BYE Logging out\r\n') + self._send('{} OK Logout completed.\r\n'.format(tag).encode('ASCII')) + + with self.reaped_server(AuthHandler) as server: + try: + client = self.imap_class(*server.server_address) + except imaplib.IMAP4.abort: + self.fail("IMAP4 connection failed") + + self.assertTrue('AUTH=CRAM-MD5' in client.capabilities) + + try: + ret, data = client.login_cram_md5("tim", "tanstaaftanstaaf") + self.assertEqual(ret, "OK") + except imaplib.error: + self.fail("CRAM-MD5 authentication failed") + + ret, data = client.logout() + self.assertEqual(ret, "BYE") class ThreadedNetworkedTests(BaseThreadedNetworkedTests):