summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Collins <elic@assurancetechnologies.com>2011-03-15 01:40:03 -0400
committerEli Collins <elic@assurancetechnologies.com>2011-03-15 01:40:03 -0400
commit2d2f1d0f53e79945288db8d05baf6a4cf07fdd66 (patch)
tree48e6c58decb3a42245af5d0465083fa4e6df879a
parent1d0a05a785795bd85708d49c7dfa27fbaf4a03c7 (diff)
downloadpasslib-2d2f1d0f53e79945288db8d05baf6a4cf07fdd66.tar.gz
added ldap's {MD5} {SHA} {SMD5} {SSHA} formats (still needs docs & UTs)
-rw-r--r--passlib/base.py4
-rw-r--r--passlib/drivers/ldap.py122
2 files changed, 126 insertions, 0 deletions
diff --git a/passlib/base.py b/passlib/base.py
index fc8e8ee..76935bb 100644
--- a/passlib/base.py
+++ b/passlib/base.py
@@ -98,6 +98,10 @@ _driver_locations = {
"hex_sha1": ("passlib.drivers.digests", "hex_sha1"),
"hex_sha256": ("passlib.drivers.digests", "hex_sha256"),
"hex_sha512": ("passlib.drivers.digests", "hex_sha512"),
+ "ldap_md5": ("passlib.drivers.ldap", "ldap_md5"),
+ "ldap_sha1": ("passlib.drivers.ldap", "ldap_sha1"),
+ "ldap_salted_md5": ("passlib.drivers.ldap", "ldap_salted_md5"),
+ "ldap_salted_sha1": ("passlib.drivers.ldap", "ldap_salted_sha1"),
"md5_crypt": ("passlib.drivers.md5_crypt", "md5_crypt"),
"mysql323": ("passlib.drivers.mysql", "mysql323"),
"mysql41": ("passlib.drivers.mysql", "mysql41"),
diff --git a/passlib/drivers/ldap.py b/passlib/drivers/ldap.py
new file mode 100644
index 0000000..f242567
--- /dev/null
+++ b/passlib/drivers/ldap.py
@@ -0,0 +1,122 @@
+"""passlib.drivers.digests - plain hash digests
+"""
+#=========================================================
+#imports
+#=========================================================
+#core
+from hashlib import md5, sha1
+import logging; log = logging.getLogger(__name__)
+import re
+from warnings import warn
+#site
+#libs
+from passlib.utils.drivers import ExtHash, BaseHash
+#pkg
+#local
+__all__ = [
+ "ldap_md5",
+ "ldap_sha1",
+ "ldap_salted_md5",
+ "ldap_salted_sha1",
+]
+
+#=========================================================
+#ldap helpers
+#=========================================================
+#reference - http://www.openldap.org/doc/admin24/security.html
+
+class _Base64DigestHelper(BaseHash):
+ "helper for ldap_md5 / ldap_sha1"
+
+ #_ident
+ #_hash
+ #_pat
+
+ @classmethod
+ def identify(cls, hash):
+ return bool(hash and cls._pat.match(hash))
+
+ @classmethod
+ def genhash(cls, secret, hash):
+ if secret is None:
+ raise TypeError, "no secret provided"
+ if isinstance(secret, unicode):
+ secret = secret.encode("utf-8")
+ if hash is not None and not cls.identify(hash):
+ raise ValueError, "not a %s hash" % (cls.name,)
+ return cls._ident + cls._hash(secret).digest().encode("base64").strip()
+
+class _SaltedBase64DigestHelper(ExtHash):
+ "helper for ldap_salted_md5 / ldap_salted_sha1"
+ setting_kwds = ("salt",)
+
+ #_ident
+ #_hash
+ #_pat
+ #_default_chk
+ min_salt_chars = max_salt_chars = 4
+ salt_charset = ''.join(chr(x) for x in xrange(256))
+
+ @classmethod
+ def identify(cls, hash):
+ return bool(hash and cls._pat.match(hash))
+
+ @classmethod
+ def from_string(cls, hash):
+ if not hash:
+ raise ValueError, "no hash specified"
+ m = cls._pat.match(hash)
+ if not m:
+ raise ValueError, "not a %s hash" % (cls.name,)
+ tmp = m.group("tmp").decode("base64")
+ chk, salt = tmp[:-4], tmp[-4:]
+ return cls(checksum=chk, salt=salt, strict=True)
+
+ def to_string(self):
+ return self._ident + ((self.checksum or self._default_chk) + self.salt).encode("base64").strip()
+
+ def calc_checksum(self, secret):
+ if secret is None:
+ raise TypeError, "no secret provided"
+ if isinstance(secret, unicode):
+ secret = secret.encode("utf-8")
+ return self._hash(secret + self.salt).digest()
+
+#=========================================================
+#implementations
+#=========================================================
+class ldap_md5(_Base64DigestHelper):
+ name = "ldap_md5"
+ setting_kwds = ()
+
+ _ident = "{MD5}"
+ _hash = hashlib.md5
+ _pat = re.compile(r"^\{MD5\}(?P<chk>[+/a-zA-Z0-9]{22}==)$")
+
+class ldap_sha1(_Base64DigestHelper):
+ name = "ldap_sha1"
+ setting_kwds = ()
+
+ _ident = "{SHA}"
+ _hash = hashlib.sha1
+ _pat = re.compile(r"^\{SHA\}(?P<chk>[+/a-zA-Z0-9]{27}=)$")
+
+class ldap_salted_md5(_SaltedBase64DigestHelper):
+ name = "ldap_salted_md5"
+ _ident = "{SMD5}"
+ _hash = hashlib.md5
+ _pat = re.compile(r"^\{SMD5\}(?P<tmp>[+/a-zA-Z0-9]{27}=)$")
+ _default_chk = '\x00' * 16
+
+class ldap_salted_sha1(_SaltedBase64DigestHelper):
+ name = "ldap_salted_sha1"
+ _ident = "{SSHA}"
+ _hash = hashlib.sha1
+ _pat = re.compile(r"^\{SSHA\}(?P<tmp>[+/a-zA-Z0-9]{32})$")
+ _default_chk = '\x00' * 20
+
+#TODO: support {CRYPT} somehow (adapt per host?)
+
+#=========================================================
+#eof
+#=========================================================