diff options
Diffstat (limited to 'passlib')
| -rw-r--r-- | passlib/handlers/digests.py | 9 | ||||
| -rw-r--r-- | passlib/handlers/ldap_digests.py | 10 | ||||
| -rw-r--r-- | passlib/handlers/misc.py | 12 | ||||
| -rw-r--r-- | passlib/handlers/mysql.py | 26 | ||||
| -rw-r--r-- | passlib/handlers/oracle.py | 28 | ||||
| -rw-r--r-- | passlib/handlers/postgres.py | 25 | ||||
| -rw-r--r-- | passlib/utils/handlers.py | 21 |
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 |
