password_hashers.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import hashlib
  2. import hmac
  3. from persistent.mapping import PersistentMapping
  4. from zope.annotation.interfaces import IAnnotations
  5. from zope.interface import implements
  6. from AccessControl.AuthEncoding import pw_encrypt
  7. from AccessControl.AuthEncoding import pw_validate
  8. from Products.remember.config import ANNOT_KEY
  9. from Products.remember.interfaces import IHashPW
  10. class BaseHash(object):
  11. """
  12. Abstract base class for actual hashing implementations.
  13. """
  14. implements(IHashPW)
  15. def __init__(self, context):
  16. self.context = context
  17. def isAvailable(self):
  18. return True
  19. def hashPassword(self, password):
  20. raise NotImplementedError
  21. def validate(self, reference, attempt):
  22. """
  23. Check to see if the reference is a hash of the attempt.
  24. """
  25. return self.hashPassword(attempt) == reference
  26. class BCryptHash(BaseHash):
  27. """
  28. Adapts from IAnnotatable to IHashPW. Uses bcrypt to hash the
  29. password
  30. """
  31. try:
  32. import bcrypt
  33. except ImportError:
  34. bcrypt = None
  35. def __init__(self, context):
  36. self.context = context
  37. if self.bcrypt is None:
  38. return
  39. annotations = IAnnotations(context)
  40. storage = annotations.setdefault(ANNOT_KEY,
  41. PersistentMapping())
  42. storage.setdefault('bcrypt_salt', self.bcrypt.gensalt())
  43. self.storage = storage
  44. def isAvailable(self):
  45. return self.bcrypt is not None
  46. def hashPassword(self, password):
  47. """
  48. Return a hashed version of password using bcrypt
  49. """
  50. return self.bcrypt.hashpw(password, self.storage['bcrypt_salt'])
  51. class SHAHash(BaseHash):
  52. """
  53. Adapts from IAnnotatable to IHashPW. Uses SHA to hash the password
  54. """
  55. def hashPassword(self, password):
  56. """
  57. Return a hashed version of password using SHA
  58. """
  59. return hashlib.sha1(password).hexdigest()
  60. class HMACHash(BaseHash):
  61. """
  62. Adapts from IAnnotatable to IHashPW. Uses SHA to hash the password
  63. """
  64. def __init__(self, context):
  65. self.context = context
  66. key = str(context)
  67. annotations = IAnnotations(context)
  68. storage = annotations.setdefault(ANNOT_KEY,
  69. PersistentMapping())
  70. storage.setdefault('hmac_key', key)
  71. self.storage = storage
  72. def hashPassword(self, password):
  73. """
  74. Return a hashed version of password using SHA
  75. """
  76. return hmac.new(self.storage['hmac_key'], password, hashlib.sha1
  77. ).hexdigest()
  78. class ZAuthHash(BaseHash):
  79. """
  80. Adapts from IAnnotatable to IHashPW. Uses Zope 2's
  81. AccessControl.AuthEncoding module to hash the password.
  82. """
  83. def hashPassword(self, password):
  84. """
  85. Delegate to AccessControl.AuthEncoding.
  86. """
  87. return pw_encrypt(password)
  88. def validate(self, reference, attempt):
  89. """
  90. Check to see if the reference is a hash of the attempt.
  91. """
  92. return pw_validate(reference, attempt)