_cred.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Credential managers for L{twisted.mail}.
  5. """
  6. from __future__ import absolute_import, division
  7. import hmac
  8. import hashlib
  9. from zope.interface import implementer
  10. from twisted.cred import credentials
  11. from twisted.python.compat import nativeString
  12. from twisted.mail._except import IllegalClientResponse
  13. from twisted.mail.interfaces import IClientAuthentication, IChallengeResponse
  14. @implementer(IClientAuthentication)
  15. class CramMD5ClientAuthenticator:
  16. def __init__(self, user):
  17. self.user = user
  18. def getName(self):
  19. return b"CRAM-MD5"
  20. def challengeResponse(self, secret, chal):
  21. response = hmac.HMAC(secret, chal, digestmod=hashlib.md5).hexdigest()
  22. return self.user + b' ' + response.encode('ascii')
  23. @implementer(IClientAuthentication)
  24. class LOGINAuthenticator:
  25. def __init__(self, user):
  26. self.user = user
  27. self.challengeResponse = self.challengeUsername
  28. def getName(self):
  29. return b"LOGIN"
  30. def challengeUsername(self, secret, chal):
  31. # Respond to something like "Username:"
  32. self.challengeResponse = self.challengeSecret
  33. return self.user
  34. def challengeSecret(self, secret, chal):
  35. # Respond to something like "Password:"
  36. return secret
  37. @implementer(IClientAuthentication)
  38. class PLAINAuthenticator:
  39. def __init__(self, user):
  40. self.user = user
  41. def getName(self):
  42. return b"PLAIN"
  43. def challengeResponse(self, secret, chal):
  44. return b'\0' + self.user + b'\0' + secret
  45. @implementer(IChallengeResponse)
  46. class LOGINCredentials(credentials.UsernamePassword):
  47. def __init__(self):
  48. self.challenges = [b'Password\0', b'User Name\0']
  49. self.responses = [b'password', b'username']
  50. credentials.UsernamePassword.__init__(self, None, None)
  51. def getChallenge(self):
  52. return self.challenges.pop()
  53. def setResponse(self, response):
  54. setattr(self, nativeString(self.responses.pop()), response)
  55. def moreChallenges(self):
  56. return bool(self.challenges)
  57. @implementer(IChallengeResponse)
  58. class PLAINCredentials(credentials.UsernamePassword):
  59. def __init__(self):
  60. credentials.UsernamePassword.__init__(self, None, None)
  61. def getChallenge(self):
  62. return b''
  63. def setResponse(self, response):
  64. parts = response.split(b'\0')
  65. if len(parts) != 3:
  66. raise IllegalClientResponse(
  67. "Malformed Response - wrong number of parts")
  68. useless, self.username, self.password = parts
  69. def moreChallenges(self):
  70. return False
  71. __all__ = [
  72. "CramMD5ClientAuthenticator",
  73. "LOGINCredentials", "LOGINAuthenticator",
  74. "PLAINCredentials", "PLAINAuthenticator",
  75. ]