_cred.py 2.6 KB

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