summaryrefslogtreecommitdiff
path: root/passlib
diff options
context:
space:
mode:
Diffstat (limited to 'passlib')
-rw-r--r--passlib/handlers/digests.py9
-rw-r--r--passlib/handlers/ldap_digests.py10
-rw-r--r--passlib/handlers/misc.py12
-rw-r--r--passlib/handlers/mysql.py26
-rw-r--r--passlib/handlers/oracle.py28
-rw-r--r--passlib/handlers/postgres.py25
-rw-r--r--passlib/utils/handlers.py21
7 files changed, 64 insertions, 67 deletions
diff --git a/passlib/handlers/digests.py b/passlib/handlers/digests.py
index 0d10801..fb70fe5 100644
--- a/passlib/handlers/digests.py
+++ b/passlib/handlers/digests.py
@@ -54,11 +54,10 @@ class HexDigestHash(uh.StaticHandler):
return to_hash_str(cls._hash_func(secret).hexdigest())
@classmethod
- def verify(cls, secret, hash):
- if hash is None:
- raise ValueError("no hash specified")
- hash = to_hash_str(hash)
- return cls.genhash(secret, hash) == hash.lower()
+ def _norm_hash(cls, hash):
+ if isinstance(hash, bytes):
+ hash = hash.decode("ascii")
+ return hash.lower()
def create_hex_hash(hash, digest_name):
#NOTE: could set digest_name=hash.name for cpython, but not for some other platforms.
diff --git a/passlib/handlers/ldap_digests.py b/passlib/handlers/ldap_digests.py
index 9a12160..2a7d826 100644
--- a/passlib/handlers/ldap_digests.py
+++ b/passlib/handlers/ldap_digests.py
@@ -197,6 +197,16 @@ class ldap_plaintext(uh.StaticHandler):
raise TypeError("secret must be string")
return to_hash_str(secret, "utf-8")
+ @classmethod
+ def _norm_hash(cls, hash):
+ if isinstance(hash, bytes):
+ #XXX: current code uses utf-8
+ # if existing hashes use something else,
+ # probably have to modify this code to allow hash_encoding
+ # to be specified as an option.
+ hash = hash.decode("utf-8")
+ return hash
+
#=========================================================
#{CRYPT} wrappers
#=========================================================
diff --git a/passlib/handlers/misc.py b/passlib/handlers/misc.py
index 8ac8b2e..f6784cf 100644
--- a/passlib/handlers/misc.py
+++ b/passlib/handlers/misc.py
@@ -61,7 +61,7 @@ class plaintext(uh.StaticHandler):
Unicode passwords will be encoded using utf-8.
"""
name = "plaintext"
-
+
@classmethod
def identify(cls, hash):
return hash is not None
@@ -72,6 +72,16 @@ class plaintext(uh.StaticHandler):
raise TypeError("secret must be string")
return to_hash_str(secret, "utf-8")
+ @classmethod
+ def _norm_hash(cls, hash):
+ if isinstance(hash, bytes):
+ #XXX: current code uses utf-8
+ # if existing hashes use something else,
+ # probably have to modify this code to allow hash_encoding
+ # to be specified as an option.
+ hash = hash.decode("utf-8")
+ return hash
+
#=========================================================
#eof
#=========================================================
diff --git a/passlib/handlers/mysql.py b/passlib/handlers/mysql.py
index 138d970..5a947f6 100644
--- a/passlib/handlers/mysql.py
+++ b/passlib/handlers/mysql.py
@@ -65,8 +65,8 @@ class mysql323(uh.StaticHandler):
@classmethod
def genhash(cls, secret, config):
- if config and not cls.identify(config):
- raise ValueError("not a mysql-41 hash")
+ if config is not None and not cls.identify(config):
+ raise ValueError("not a mysql-3.2.3 hash")
#FIXME: no idea if mysql has a policy about handling unicode passwords
if isinstance(secret, unicode):
@@ -89,11 +89,10 @@ class mysql323(uh.StaticHandler):
return to_hash_str(hash)
@classmethod
- def verify(cls, secret, hash):
- if not hash:
- raise ValueError("no hash specified")
- hash = to_hash_str(hash)
- return hash.lower() == cls.genhash(secret, hash)
+ def _norm_hash(cls, hash):
+ if isinstance(hash, bytes):
+ hash = hash.decode("ascii")
+ return hash.lower()
#=========================================================
#eoc
@@ -125,19 +124,18 @@ class mysql41(uh.StaticHandler):
@classmethod
def genhash(cls, secret, config):
- if config and not cls.identify(config):
- raise ValueError("not a mysql-41 hash")
+ if config is not None and not cls.identify(config):
+ raise ValueError("not a mysql-4.1 hash")
#FIXME: no idea if mysql has a policy about handling unicode passwords
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
return '*' + sha1(sha1(secret).digest()).hexdigest().upper()
@classmethod
- def verify(cls, secret, hash):
- if not hash:
- raise ValueError("no hash specified")
- hash = to_hash_str(hash)
- return hash.upper() == cls.genhash(secret, hash)
+ def _norm_hash(cls, hash):
+ if isinstance(hash, bytes):
+ hash = hash.decode("ascii")
+ return hash.upper()
#=========================================================
#eoc
diff --git a/passlib/handlers/oracle.py b/passlib/handlers/oracle.py
index 2f48615..2f0e2bc 100644
--- a/passlib/handlers/oracle.py
+++ b/passlib/handlers/oracle.py
@@ -49,7 +49,7 @@ def des_cbc_encrypt(key, value, iv=b('\x00') * 8, pad=b('\x00')):
#: magic string used as initial des key by oracle10
ORACLE10_MAGIC = b("\x01\x23\x45\x67\x89\xAB\xCD\xEF")
-class oracle10(object):
+class oracle10(uh.StaticHandler):
"""This class implements the password hash used by Oracle up to version 10g, and follows the :ref:`password-hash-api`.
It has no salt and a single fixed round.
@@ -81,20 +81,9 @@ class oracle10(object):
#primary interface
#=========================================================
@classmethod
- def genconfig(cls):
- return None
-
- @classmethod
def genhash(cls, secret, config, user):
- if config and not cls.identify(config):
- raise ValueError("not a oracle10g hash")
- return cls.encrypt(secret, user)
-
- #=========================================================
- #secondary interface
- #=========================================================
- @classmethod
- def encrypt(cls, secret, user):
+ if config is not None and not cls.identify(config):
+ raise ValueError("not an oracle-10g hash")
if secret is None:
raise TypeError("secret must be specified")
if not user:
@@ -127,11 +116,10 @@ class oracle10(object):
return to_hash_str(hexlify(hash)).upper()
@classmethod
- def verify(cls, secret, hash, user):
- if not hash:
- raise ValueError("no hash specified")
- hash = to_hash_str(hash)
- return cls.genhash(secret, hash, user) == hash.upper()
+ def _norm_hash(cls, hash):
+ if isinstance(hash, bytes):
+ hash = hash.decode("ascii")
+ return hash.upper()
#=========================================================
#eoc
@@ -185,7 +173,7 @@ class oracle11(uh.HasSalt, uh.GenericHandler):
hash = hash.decode("ascii")
m = cls._pat.match(hash)
if not m:
- raise ValueError("invalid oracle11 hash")
+ raise ValueError("invalid oracle-11g hash")
salt, chk = m.group("salt", "chk")
return cls(salt=salt, checksum=chk.upper(), strict=True)
diff --git a/passlib/handlers/postgres.py b/passlib/handlers/postgres.py
index 8447616..32b0e3e 100644
--- a/passlib/handlers/postgres.py
+++ b/passlib/handlers/postgres.py
@@ -19,7 +19,7 @@ __all__ = [
#=========================================================
#handler
#=========================================================
-class postgres_md5(object):
+class postgres_md5(uh.StaticHandler):
"""This class implements the Postgres MD5 Password hash, and follows the :ref:`password-hash-api`.
It has no salt and a single fixed round.
@@ -51,37 +51,18 @@ class postgres_md5(object):
#primary interface
#=========================================================
@classmethod
- def genconfig(cls):
- return None
-
- @classmethod
def genhash(cls, secret, config, user):
- if config and not cls.identify(config):
+ if config is not None and not cls.identify(config):
raise ValueError("not a postgres-md5 hash")
- return cls.encrypt(secret, user)
-
- #=========================================================
- #secondary interface
- #=========================================================
- @classmethod
- def encrypt(cls, secret, user):
- #FIXME: not sure what postgres' policy is for unicode
if not user:
raise ValueError("user keyword must be specified for this algorithm")
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
if isinstance(user, unicode):
user = user.encode("utf-8")
- hash = u"md5" + to_unicode(md5(secret + user).hexdigest(), "ascii")
+ hash = u"md5" + md5(secret + user).hexdigest().encode("ascii")
return to_hash_str(hash)
- @classmethod
- def verify(cls, secret, hash, user):
- if not hash:
- raise ValueError("no hash specified")
- hash = to_hash_str(hash)
- return hash == cls.genhash(secret, hash, user)
-
#=========================================================
#eoc
#=========================================================
diff --git a/passlib/utils/handlers.py b/passlib/utils/handlers.py
index d8a9c3a..cfa9381 100644
--- a/passlib/utils/handlers.py
+++ b/passlib/utils/handlers.py
@@ -199,16 +199,27 @@ class StaticHandler(object):
raise NotImplementedError("%s subclass must implement genhash()" % (cls,))
@classmethod
- def encrypt(cls, secret, **context):
+ def encrypt(cls, secret, *cargs, **context):
+ #NOTE: subclasses generally won't need to override this.
config = cls.genconfig()
- return cls.genhash(secret, config, **context)
+ return cls.genhash(secret, config, *cargs, **context)
@classmethod
- def verify(cls, secret, hash, **context):
+ def verify(cls, secret, hash, *cargs, **context):
+ #NOTE: subclasses generally won't need to override this.
if hash is None:
raise ValueError("no hash specified")
- hash = to_hash_str(hash) #so equality works
- return cls.genhash(secret, hash, **context) == hash
+ hash = cls._norm_hash(hash)
+ result = cls.genhash(secret, hash, *cargs, **context)
+ return cls._norm_hash(result) == hash
+
+ @classmethod
+ def _norm_hash(cls, hash):
+ """[helper for verify] normalize hash for comparsion purposes"""
+ #NOTE: this is mainly provided for case-insenstive subclasses to override.
+ if isinstance(hash, bytes):
+ hash = hash.decode("ascii")
+ return hash
#=====================================================
#eoc