diff options
| -rw-r--r-- | docs/lib/passlib.context.rst (renamed from docs/lib/passlib.base.rst) | 7 | ||||
| -rw-r--r-- | docs/lib/passlib.hash.hex_digests.rst | 2 | ||||
| -rw-r--r-- | docs/lib/passlib.hash.ldap_digests.rst | 2 | ||||
| -rw-r--r-- | docs/lib/passlib.hash.plaintext.rst | 2 | ||||
| -rw-r--r-- | docs/lib/passlib.hash.unix_fallback.rst | 2 | ||||
| -rw-r--r-- | docs/overview.rst | 2 | ||||
| -rw-r--r-- | docs/password_hash_api.rst | 2 | ||||
| -rw-r--r-- | passlib/apache.py | 2 | ||||
| -rw-r--r-- | passlib/context.py (renamed from passlib/base.py) | 253 | ||||
| -rw-r--r-- | passlib/hash.py | 2 | ||||
| -rw-r--r-- | passlib/hosts.py | 2 | ||||
| -rw-r--r-- | passlib/registry.py | 257 | ||||
| -rw-r--r-- | passlib/servers.py | 2 | ||||
| -rw-r--r-- | passlib/tests/_test_bad_register.py | 4 | ||||
| -rw-r--r-- | passlib/tests/genconfig.py | 2 | ||||
| -rw-r--r-- | passlib/tests/test_context.py (renamed from passlib/tests/test_base.py) | 126 | ||||
| -rw-r--r-- | passlib/tests/test_registry.py | 145 | ||||
| -rw-r--r-- | passlib/tests/test_utils.py | 2 |
18 files changed, 425 insertions, 391 deletions
diff --git a/docs/lib/passlib.base.rst b/docs/lib/passlib.context.rst index 9c09eb2..138452e 100644 --- a/docs/lib/passlib.base.rst +++ b/docs/lib/passlib.context.rst @@ -1,8 +1,11 @@ ============================================= -:mod:`passlib.base` - Crypt Contexts +:mod:`passlib.context` - CryptContext class ============================================= -.. module:: passlib.base +.. module:: passlib.context + +The :mod:`!passlib.base` module contains a number of core + .. autoclass:: CryptContext diff --git a/docs/lib/passlib.hash.hex_digests.rst b/docs/lib/passlib.hash.hex_digests.rst index cbd1b1a..9bc3653 100644 --- a/docs/lib/passlib.hash.hex_digests.rst +++ b/docs/lib/passlib.hash.hex_digests.rst @@ -14,7 +14,7 @@ PassLib provides wrappers for few of the common hashes. Usage ===== These classes all wrap the underlying hashlib implementations, -and are mainly useful only for plugging them into a :class:`passlib.base.CryptContext`. +and are mainly useful only for plugging them into a :class:`~passlib.context.CryptContext`. However, they can be used directly as follows:: >>> from passlib.hash import hex_sha1 as hs diff --git a/docs/lib/passlib.hash.ldap_digests.rst b/docs/lib/passlib.hash.ldap_digests.rst index 7b9f418..a0730b7 100644 --- a/docs/lib/passlib.hash.ldap_digests.rst +++ b/docs/lib/passlib.hash.ldap_digests.rst @@ -17,7 +17,7 @@ are very insecure, and should not be used except when required. Usage ===== These classes all wrap the underlying hashlib implementations, -and are mainly useful only for plugging them into a :class:`passlib.base.CryptContext`. +and are mainly useful only for plugging them into a :class:`~passlib.context.CryptContext`. However, they can be used directly as follows:: >>> from passlib.hash import ldap_salted_md5 as lsm diff --git a/docs/lib/passlib.hash.plaintext.rst b/docs/lib/passlib.hash.plaintext.rst index d0ad62d..d8ad3ac 100644 --- a/docs/lib/passlib.hash.plaintext.rst +++ b/docs/lib/passlib.hash.plaintext.rst @@ -11,7 +11,7 @@ existing applications. *It should not be used* for any other purpose. Usage ===== -This class is mainly useful only for plugging into a :class:`passlib.base.CryptContext`. +This class is mainly useful only for plugging into a :class:`~passlib.context.CryptContext`. When used, it should always be the last scheme in the list, as it will recognize all hashes. It can be used directly as follows:: diff --git a/docs/lib/passlib.hash.unix_fallback.rst b/docs/lib/passlib.hash.unix_fallback.rst index d534546..982e55f 100644 --- a/docs/lib/passlib.hash.unix_fallback.rst +++ b/docs/lib/passlib.hash.unix_fallback.rst @@ -10,7 +10,7 @@ password fields as found in unix ``/etc/shadow`` files. Usage ===== -This class is mainly useful only for plugging into a :class:`passlib.base.CryptContext`. +This class is mainly useful only for plugging into a :class:`~passlib.context.CryptContext`. When used, it should always be the last scheme in the list, as it is designed to provide a fallback behavior. It can be used directly as follows:: diff --git a/docs/overview.rst b/docs/overview.rst index 8102020..c9ce82a 100644 --- a/docs/overview.rst +++ b/docs/overview.rst @@ -52,7 +52,7 @@ deprecated schemes, hashes using strong schemes but weak individual configuratio and other border cases. PassLib provides an advanced support framework, based around -the :doc:`CryptContext <lib/passlib.base>` class, which takes care of +the :doc:`CryptContext <lib/passlib.context>` class, which takes care of many of these issues. Each :class:`!CryptContext` instance can be configured with a list of known hashes, as well as configuration of policy requirements such as which hash is the default, which ones are deprecated, and other features. diff --git a/docs/password_hash_api.rst b/docs/password_hash_api.rst index b932096..37e36fc 100644 --- a/docs/password_hash_api.rst +++ b/docs/password_hash_api.rst @@ -34,7 +34,7 @@ The `optional informational attributes`_ Usage ===== -While most uses of PassLib are done through a :class:`~passlib.base.CryptContext` class, +While most uses of PassLib are done through a :class:`~passlib.context.CryptContext` class, the various :class:`!PasswordHash` classes can be used directly to manipulate passwords:: diff --git a/passlib/apache.py b/passlib/apache.py index 0f8ba8d..9b99203 100644 --- a/passlib/apache.py +++ b/passlib/apache.py @@ -31,7 +31,7 @@ import logging; log = logging.getLogger(__name__) import os #site #libs -from passlib.base import CryptContext +from passlib.context import CryptContext #pkg #local __all__ = [ diff --git a/passlib/base.py b/passlib/context.py index 6345c3c..0658c33 100644 --- a/passlib/base.py +++ b/passlib/context.py @@ -1,14 +1,4 @@ -"""passlib - implementation of various password hashing functions - -Context options - - schemes - list of names or handler instances which should be recognized by context - deprecated - list names of handlers which should context should only use to validate *old* hashes - default - optional name of handler to use for encrypting new hashes. - -Many schemes support their own options, such as min/max/default rounds. - -""" +"""passlib.context - CryptContext implementation""" #========================================================= #imports #========================================================= @@ -27,255 +17,16 @@ from warnings import warn #site from pkg_resources import resource_string #libs +from passlib.registry import get_crypt_handler from passlib.utils import Undef, is_crypt_handler, splitcomma, rng #pkg #local __all__ = [ - #registry interface - "register_crypt_handler_path", - "register_crypt_handler", - "get_crypt_handler", - "list_crypt_handlers", - - #contexts 'CryptPolicy', 'CryptContext', ] #========================================================= -#registry proxy object -#========================================================= -class PasslibRegistryProxy(object): - """proxy module passlib.hash - - this module is in fact an object which lazy-loads - the requested password hash algorithm from wherever it has been stored. - it acts as a thin wrapper around :func:`passlib.base.get_crypt_handler`. - """ - __name__ = "passlib.hash" - __package__ = None - - def __getattr__(self, attr): - if attr.startswith("_"): - raise AttributeError, "missing attribute: %r" % (attr,) - handler = get_crypt_handler(attr, None) - if handler: - return handler - else: - raise AttributeError, "unknown password hash: %r" % (attr,) - - def __setattr__(self, attr, value): - register_crypt_handler(value, name=attr) - - def __repr__(self): - return "<proxy module 'passlib.hash'>" - - def __dir__(self): - #add in handlers that will be lazy-loaded, - #otherwise this is std dir implementation - attrs = set(dir(self.__class__)) - attrs.update(self.__dict__) - attrs.update(_handler_locations) - return sorted(attrs) - - #========================================================= - #eoc - #========================================================= - -#singleton instance -_proxy = PasslibRegistryProxy() - -#========================================================== -#internal registry state -#========================================================== - -#: dict mapping name -> handler for all loaded handlers. uses proxy's dict so they stay in sync. -_handlers = _proxy.__dict__ - -#: dict mapping name -> (module path, attribute) for lazy-loading of handlers -_handler_locations = { - #NOTE: this is a hardcoded list of the handlers built into passlib, - #applications should call register_crypt_handler_location() to add their own - "apr_md5_crypt": ("passlib.drivers.md5_crypt", "apr_md5_crypt"), - "bcrypt": ("passlib.drivers.bcrypt", "bcrypt"), - "bigcrypt": ("passlib.drivers.des_crypt", "bigcrypt"), - "bsdi_crypt": ("passlib.drivers.des_crypt", "bsdi_crypt"), - "crypt16": ("passlib.drivers.des_crypt", "crypt16"), - "des_crypt": ("passlib.drivers.des_crypt", "des_crypt"), - "hex_md4": ("passlib.drivers.digests", "hex_md4"), - "hex_md5": ("passlib.drivers.digests", "hex_md5"), - "hex_sha1": ("passlib.drivers.digests", "hex_sha1"), - "hex_sha256": ("passlib.drivers.digests", "hex_sha256"), - "hex_sha512": ("passlib.drivers.digests", "hex_sha512"), - "ldap_cleartext": ("passlib.drivers.ldap_digests","ldap_cleartext"), - "ldap_md5": ("passlib.drivers.ldap_digests","ldap_md5"), - "ldap_sha1": ("passlib.drivers.ldap_digests","ldap_sha1"), - "ldap_salted_md5": ("passlib.drivers.ldap_digests","ldap_salted_md5"), - "ldap_salted_sha1": ("passlib.drivers.ldap_digests","ldap_salted_sha1"), - "md5_crypt": ("passlib.drivers.md5_crypt", "md5_crypt"), - "mysql323": ("passlib.drivers.mysql", "mysql323"), - "mysql41": ("passlib.drivers.mysql", "mysql41"), - "nthash": ("passlib.drivers.nthash", "nthash"), - "oracle10": ("passlib.drivers.oracle", "oracle10"), - "oracle11": ("passlib.drivers.oracle", "oracle11"), - "phpass": ("passlib.drivers.phpass", "phpass"), - "plaintext": ("passlib.drivers.misc", "plaintext"), - "postgres_md5": ("passlib.drivers.postgres", "postgres_md5"), - "sha1_crypt": ("passlib.drivers.sha1_crypt", "sha1_crypt"), - "sha256_crypt": ("passlib.drivers.sha2_crypt", "sha256_crypt"), - "sha512_crypt": ("passlib.drivers.sha2_crypt", "sha512_crypt"), - "sun_md5_crypt": ("passlib.drivers.sun_md5_crypt","sun_md5_crypt"), - "unix_fallback": ("passlib.drivers.misc", "unix_fallback"), -} - -#: master regexp for detecting valid handler names -_name_re = re.compile("^[a-z][_a-z0-9]{2,}$") - -#========================================================== -#registry frontend functions -#========================================================== -def register_crypt_handler_path(name, path): - """register location to lazy-load handler when requested. - - custom hashes may be registered via :func:`register_crypt_handler`, - or they may be registered by this function, - which will delay actually importing and loading the handler - until a call to :func:`get_crypt_handler` is made for the specified name. - - :arg name: name of handler - :arg path: module import path - - the specified module path should contain a password hash handler - called :samp:`{name}`, or the path may contain a semicolon, - specifying the module and module attribute to use. - """ - global _handler_locations - if ':' in path: - modname, modattr = path.split(":") - else: - modname, modattr = path, name - _handler_locations[name] = (modname, modattr) - -def register_crypt_handler(handler, force=False, name=None): - """register password hash handler. - - this method registers a handler with the internal passlib registry, - so that it will be returned by :func:`get_crypt_handler` when requested. - - :arg handler: the password hash handler to register - :param force: force override of existing handler (defaults to False) - - :raises KeyError: - if a (different) handler was already registered with - the same name, and ``force=True`` was not specified. - """ - global _handlers, _name_re - - #validate handler - if not is_crypt_handler(handler): - raise TypeError, "object does not appear to be a crypt handler: %r" % (handler,) - assert handler, "crypt handlers must be boolean True: %r" % (handler,) - - #if name specified, make sure it matched - #(this is mainly used as a check to help __setattr__) - if name: - if name != handler.name: - raise ValueError, "handlers must be stored only under their own name" - else: - name = handler.name - - #validate name - if not name: - raise ValueError, "name is null: %r" % (name,) - if name.lower() != name: - raise ValueError, "name must be lower-case: %r" % (name,) - if not _name_re.match(name): - raise ValueError, "invalid characters in name (must be 3+ characters, begin with a-z, and contain only underscore, a-z, 0-9): %r" % (name,) - - #check for existing handler - other = _handlers.get(name) - if other: - if other is handler: - return #already registered - if force: - log.warning("overriding previous handler registered to name %r: %r", name, other) - else: - raise KeyError, "a handler has already registered for the name %r: %r (use force=True to override)" % (name, other) - - #register handler in dict - _handlers[name] = handler - log.info("registered crypt handler %r: %r", name, handler) - -def get_crypt_handler(name, default=Undef): - """return handler for specified password hash scheme. - - this method looks up a handler for the specified scheme. - if the handler is not already loaded, - it checks if the location of one is known (:func:`register_crypt_handler`) - and loads it first. - - :arg name: name of handler to return - :param default: if specified, returns default value if no handler found. - - :raises KeyError: if no handler matching that name is found, and no default specified - - :returns: handler attached to name, or default if specified - """ - global _handlers, _handler_locations - - #check if handler loaded - handler = _handlers.get(name, None) - if handler: - return handler - - #normalize name (and if changed, check dict again) - alt = name.replace("-","_").lower() - if alt != name: - warn("handler names be lower-case, and use underscores instead of hyphens: %r => %r" % (name, alt)) - name = alt - - #check if handler loaded - handler = _handlers.get(name) - if handler: - return handler - - #check if lazy load mapping has been specified for this driver - route = _handler_locations.get(name) - if route: - modname, modattr = route - - #try to load the module - any import errors indicate runtime config, - # either missing packages, or bad path provided to register_crypt_handler_path() - mod = __import__(modname, None, None, ['dummy'], 0) - - #first check if importing module triggered register_crypt_handler(), - #(though this is discouraged due to it's magical implicitness) - handler = _handlers.get(name) - if handler: - #XXX: issue deprecation warning here? - assert is_crypt_handler(handler), "unexpected object: name=%r object=%r" % (name, handler) - return handler - - #then get real handler & register it - handler = getattr(mod, modattr) - register_crypt_handler(handler, name=name) - return handler - - #fail! - if default is Undef: - raise KeyError, "no crypt handler found for algorithm: %r" % (name,) - else: - return default - -def list_crypt_handlers(loaded_only=False): - "return sorted list of all known crypt handler names" - global _handlers, _handler_locations - names = set(_handlers) - if not loaded_only: - names.update(_handler_locations) - return sorted(names) - -#========================================================= #crypt policy #========================================================= def _parse_policy_key(key): diff --git a/passlib/hash.py b/passlib/hash.py index a246996..176dbfc 100644 --- a/passlib/hash.py +++ b/passlib/hash.py @@ -19,7 +19,7 @@ NOTE: #import proxy object, and replace this module with it. #this should cause any import commands to return that object, #not this module -from passlib.base import _proxy +from passlib.registry import _proxy import sys sys.modules['passlib.hash'] = _proxy del sys, _proxy diff --git a/passlib/hosts.py b/passlib/hosts.py index 78ae649..b6a3d03 100644 --- a/passlib/hosts.py +++ b/passlib/hosts.py @@ -3,7 +3,7 @@ #imports #========================================================= #pkg -from passlib.base import CryptContext +from passlib.context import CryptContext #local __all__ = [ "default_context", diff --git a/passlib/registry.py b/passlib/registry.py new file mode 100644 index 0000000..e7a8c3e --- /dev/null +++ b/passlib/registry.py @@ -0,0 +1,257 @@ +"""passlib.registry - registry for password hash handlers""" +#========================================================= +#imports +#========================================================= +#core +import inspect +import re +import logging; log = logging.getLogger(__name__) +from warnings import warn +#site +#libs +from passlib.utils import Undef, is_crypt_handler +#pkg +#local +__all__ = [ + "register_crypt_handler_path", + "register_crypt_handler", + "get_crypt_handler", + "list_crypt_handlers", +] + +#========================================================= +#registry proxy object +#========================================================= +class PasslibRegistryProxy(object): + """proxy module passlib.hash + + this module is in fact an object which lazy-loads + the requested password hash algorithm from wherever it has been stored. + it acts as a thin wrapper around :func:`passlib.registry.get_crypt_handler`. + """ + __name__ = "passlib.hash" + __package__ = None + + def __getattr__(self, attr): + if attr.startswith("_"): + raise AttributeError, "missing attribute: %r" % (attr,) + handler = get_crypt_handler(attr, None) + if handler: + return handler + else: + raise AttributeError, "unknown password hash: %r" % (attr,) + + def __setattr__(self, attr, value): + register_crypt_handler(value, name=attr) + + def __repr__(self): + return "<proxy module 'passlib.hash'>" + + def __dir__(self): + #add in handlers that will be lazy-loaded, + #otherwise this is std dir implementation + attrs = set(dir(self.__class__)) + attrs.update(self.__dict__) + attrs.update(_handler_locations) + return sorted(attrs) + + #========================================================= + #eoc + #========================================================= + +#singleton instance +_proxy = PasslibRegistryProxy() + +#========================================================== +#internal registry state +#========================================================== + +#: dict mapping name -> handler for all loaded handlers. uses proxy's dict so they stay in sync. +_handlers = _proxy.__dict__ + +#: dict mapping name -> (module path, attribute) for lazy-loading of handlers +_handler_locations = { + #NOTE: this is a hardcoded list of the handlers built into passlib, + #applications should call register_crypt_handler_location() to add their own + "apr_md5_crypt": ("passlib.drivers.md5_crypt", "apr_md5_crypt"), + "bcrypt": ("passlib.drivers.bcrypt", "bcrypt"), + "bigcrypt": ("passlib.drivers.des_crypt", "bigcrypt"), + "bsdi_crypt": ("passlib.drivers.des_crypt", "bsdi_crypt"), + "crypt16": ("passlib.drivers.des_crypt", "crypt16"), + "des_crypt": ("passlib.drivers.des_crypt", "des_crypt"), + "hex_md4": ("passlib.drivers.digests", "hex_md4"), + "hex_md5": ("passlib.drivers.digests", "hex_md5"), + "hex_sha1": ("passlib.drivers.digests", "hex_sha1"), + "hex_sha256": ("passlib.drivers.digests", "hex_sha256"), + "hex_sha512": ("passlib.drivers.digests", "hex_sha512"), + "ldap_cleartext": ("passlib.drivers.ldap_digests","ldap_cleartext"), + "ldap_md5": ("passlib.drivers.ldap_digests","ldap_md5"), + "ldap_sha1": ("passlib.drivers.ldap_digests","ldap_sha1"), + "ldap_salted_md5": ("passlib.drivers.ldap_digests","ldap_salted_md5"), + "ldap_salted_sha1": ("passlib.drivers.ldap_digests","ldap_salted_sha1"), + "md5_crypt": ("passlib.drivers.md5_crypt", "md5_crypt"), + "mysql323": ("passlib.drivers.mysql", "mysql323"), + "mysql41": ("passlib.drivers.mysql", "mysql41"), + "nthash": ("passlib.drivers.nthash", "nthash"), + "oracle10": ("passlib.drivers.oracle", "oracle10"), + "oracle11": ("passlib.drivers.oracle", "oracle11"), + "phpass": ("passlib.drivers.phpass", "phpass"), + "plaintext": ("passlib.drivers.misc", "plaintext"), + "postgres_md5": ("passlib.drivers.postgres", "postgres_md5"), + "sha1_crypt": ("passlib.drivers.sha1_crypt", "sha1_crypt"), + "sha256_crypt": ("passlib.drivers.sha2_crypt", "sha256_crypt"), + "sha512_crypt": ("passlib.drivers.sha2_crypt", "sha512_crypt"), + "sun_md5_crypt": ("passlib.drivers.sun_md5_crypt","sun_md5_crypt"), + "unix_fallback": ("passlib.drivers.misc", "unix_fallback"), +} + +#: master regexp for detecting valid handler names +_name_re = re.compile("^[a-z][_a-z0-9]{2,}$") + +#========================================================== +#registry frontend functions +#========================================================== +def register_crypt_handler_path(name, path): + """register location to lazy-load handler when requested. + + custom hashes may be registered via :func:`register_crypt_handler`, + or they may be registered by this function, + which will delay actually importing and loading the handler + until a call to :func:`get_crypt_handler` is made for the specified name. + + :arg name: name of handler + :arg path: module import path + + the specified module path should contain a password hash handler + called :samp:`{name}`, or the path may contain a semicolon, + specifying the module and module attribute to use. + """ + global _handler_locations + if ':' in path: + modname, modattr = path.split(":") + else: + modname, modattr = path, name + _handler_locations[name] = (modname, modattr) + +def register_crypt_handler(handler, force=False, name=None): + """register password hash handler. + + this method registers a handler with the internal passlib registry, + so that it will be returned by :func:`get_crypt_handler` when requested. + + :arg handler: the password hash handler to register + :param force: force override of existing handler (defaults to False) + + :raises KeyError: + if a (different) handler was already registered with + the same name, and ``force=True`` was not specified. + """ + global _handlers, _name_re + + #validate handler + if not is_crypt_handler(handler): + raise TypeError, "object does not appear to be a crypt handler: %r" % (handler,) + assert handler, "crypt handlers must be boolean True: %r" % (handler,) + + #if name specified, make sure it matched + #(this is mainly used as a check to help __setattr__) + if name: + if name != handler.name: + raise ValueError, "handlers must be stored only under their own name" + else: + name = handler.name + + #validate name + if not name: + raise ValueError, "name is null: %r" % (name,) + if name.lower() != name: + raise ValueError, "name must be lower-case: %r" % (name,) + if not _name_re.match(name): + raise ValueError, "invalid characters in name (must be 3+ characters, begin with a-z, and contain only underscore, a-z, 0-9): %r" % (name,) + + #check for existing handler + other = _handlers.get(name) + if other: + if other is handler: + return #already registered + if force: + log.warning("overriding previous handler registered to name %r: %r", name, other) + else: + raise KeyError, "a handler has already registered for the name %r: %r (use force=True to override)" % (name, other) + + #register handler in dict + _handlers[name] = handler + log.info("registered crypt handler %r: %r", name, handler) + +def get_crypt_handler(name, default=Undef): + """return handler for specified password hash scheme. + + this method looks up a handler for the specified scheme. + if the handler is not already loaded, + it checks if the location of one is known (:func:`register_crypt_handler`) + and loads it first. + + :arg name: name of handler to return + :param default: if specified, returns default value if no handler found. + + :raises KeyError: if no handler matching that name is found, and no default specified + + :returns: handler attached to name, or default if specified + """ + global _handlers, _handler_locations + + #check if handler loaded + handler = _handlers.get(name, None) + if handler: + return handler + + #normalize name (and if changed, check dict again) + alt = name.replace("-","_").lower() + if alt != name: + warn("handler names be lower-case, and use underscores instead of hyphens: %r => %r" % (name, alt)) + name = alt + + #check if handler loaded + handler = _handlers.get(name) + if handler: + return handler + + #check if lazy load mapping has been specified for this driver + route = _handler_locations.get(name) + if route: + modname, modattr = route + + #try to load the module - any import errors indicate runtime config, + # either missing packages, or bad path provided to register_crypt_handler_path() + mod = __import__(modname, None, None, ['dummy'], 0) + + #first check if importing module triggered register_crypt_handler(), + #(though this is discouraged due to it's magical implicitness) + handler = _handlers.get(name) + if handler: + #XXX: issue deprecation warning here? + assert is_crypt_handler(handler), "unexpected object: name=%r object=%r" % (name, handler) + return handler + + #then get real handler & register it + handler = getattr(mod, modattr) + register_crypt_handler(handler, name=name) + return handler + + #fail! + if default is Undef: + raise KeyError, "no crypt handler found for algorithm: %r" % (name,) + else: + return default + +def list_crypt_handlers(loaded_only=False): + "return sorted list of all known crypt handler names" + global _handlers, _handler_locations + names = set(_handlers) + if not loaded_only: + names.update(_handler_locations) + return sorted(names) + +#========================================================= +# eof +#========================================================= diff --git a/passlib/servers.py b/passlib/servers.py index f0243a4..ef5ee12 100644 --- a/passlib/servers.py +++ b/passlib/servers.py @@ -7,7 +7,7 @@ import platform import logging; log = logging.getLogger(__name__) #site #libs -from passlib.base import CryptContext +from passlib.context import CryptContext #pkg #local __all__ = [ diff --git a/passlib/tests/_test_bad_register.py b/passlib/tests/_test_bad_register.py index 8554ee5..1a4a861 100644 --- a/passlib/tests/_test_bad_register.py +++ b/passlib/tests/_test_bad_register.py @@ -1,6 +1,6 @@ -"helper for method in test_base.py" +"helper for method in test_registry.py" -from passlib.base import register_crypt_handler +from passlib.registry import register_crypt_handler from passlib.utils.drivers import BaseHash class dummy_bad(BaseHash): diff --git a/passlib/tests/genconfig.py b/passlib/tests/genconfig.py index 257282c..c836b80 100644 --- a/passlib/tests/genconfig.py +++ b/passlib/tests/genconfig.py @@ -15,7 +15,7 @@ import time import sys #site #pkg -from passlib.base import get_crypt_handler +from passlib.registry import get_crypt_handler #local log = logging.getLogger(__name__) #========================================================= diff --git a/passlib/tests/test_base.py b/passlib/tests/test_context.py index ba0132b..1870c80 100644 --- a/passlib/tests/test_base.py +++ b/passlib/tests/test_context.py @@ -12,10 +12,8 @@ import warnings import sys #site #pkg -from passlib import hash, base -from passlib.base import CryptContext, CryptPolicy, \ - register_crypt_handler, register_crypt_handler_path, \ - get_crypt_handler, list_crypt_handlers +from passlib import hash +from passlib.context import CryptContext, CryptPolicy from passlib.utils.drivers import BaseHash from passlib.tests.utils import TestCase, mktemp, catch_warnings from passlib.drivers.md5_crypt import md5_crypt as AnotherHash @@ -24,126 +22,6 @@ from passlib.tests.test_utils_drivers import UnsaltedHash, SaltedHash log = getLogger(__name__) #========================================================= -#test registry -#========================================================= -class dummy_0(BaseHash): - name = "dummy_0" - setting_kwds = () - -class alt_dummy_0(BaseHash): - name = "dummy_0" - setting_kwds = () - -dummy_x = 1 - -def unload_handler_name(name): - if hasattr(hash, name): - delattr(hash, name) - - #NOTE: this messes w/ internals of registry, shouldn't be used publically. - paths = base._handler_locations - if name in paths: - del paths[name] - -class RegistryTest(TestCase): - - case_prefix = "passlib registry" - - def tearDown(self): - for name in ("dummy_0", "dummy_1", "dummy_x", "dummy_bad"): - unload_handler_name(name) - - def test_hash_proxy(self): - "test passlib.hash proxy object" - dir(hash) - repr(hash) - self.assertRaises(AttributeError, getattr, hash, 'fooey') - - def test_register_crypt_handler_path(self): - "test register_crypt_handler_path()" - - #NOTE: this messes w/ internals of registry, shouldn't be used publically. - paths = base._handler_locations - - #check namespace is clear - self.assertTrue('dummy_0' not in paths) - self.assertFalse(hasattr(hash, 'dummy_0')) - - #try lazy load - register_crypt_handler_path('dummy_0', 'passlib.tests.test_base') - self.assertTrue('dummy_0' in list_crypt_handlers()) - self.assertTrue('dummy_0' not in list_crypt_handlers(loaded_only=True)) - self.assertIs(hash.dummy_0, dummy_0) - self.assertTrue('dummy_0' in list_crypt_handlers(loaded_only=True)) - unload_handler_name('dummy_0') - - #try lazy load w/ alt - register_crypt_handler_path('dummy_0', 'passlib.tests.test_base:alt_dummy_0') - self.assertIs(hash.dummy_0, alt_dummy_0) - unload_handler_name('dummy_0') - - #check lazy load w/ wrong type fails - register_crypt_handler_path('dummy_x', 'passlib.tests.test_base') - self.assertRaises(TypeError, get_crypt_handler, 'dummy_x') - - #check lazy load w/ wrong name fails - register_crypt_handler_path('alt_dummy_0', 'passlib.tests.test_base') - self.assertRaises(ValueError, get_crypt_handler, "alt_dummy_0") - - #TODO: check lazy load which calls register_crypt_handler (warning should be issued) - sys.modules.pop("passlib.tests._test_bad_register", None) - register_crypt_handler_path("dummy_bad", "passlib.tests._test_bad_register") - with catch_warnings(): - warnings.filterwarnings("ignore", "xxxxxxxxxx", DeprecationWarning) - h = get_crypt_handler("dummy_bad") - from passlib.tests import _test_bad_register as tbr - self.assertIs(h, tbr.alt_dummy_bad) - - def test_register_crypt_handler(self): - "test register_crypt_handler()" - - self.assertRaises(TypeError, register_crypt_handler, {}) - - self.assertRaises(ValueError, register_crypt_handler, BaseHash) - self.assertRaises(ValueError, register_crypt_handler, type('x', (BaseHash,), dict(name="AB_CD"))) - self.assertRaises(ValueError, register_crypt_handler, type('x', (BaseHash,), dict(name="ab-cd"))) - - class dummy_1(BaseHash): - name = "dummy_1" - - class dummy_1b(BaseHash): - name = "dummy_1" - - self.assertTrue('dummy_1' not in list_crypt_handlers()) - - register_crypt_handler(dummy_1) - register_crypt_handler(dummy_1) - self.assertIs(get_crypt_handler("dummy_1"), dummy_1) - - self.assertRaises(KeyError, register_crypt_handler, dummy_1b) - self.assertIs(get_crypt_handler("dummy_1"), dummy_1) - - register_crypt_handler(dummy_1b, force=True) - self.assertIs(get_crypt_handler("dummy_1"), dummy_1b) - - self.assertTrue('dummy_1' in list_crypt_handlers()) - - def test_get_crypt_handler(self): - "test get_crypt_handler()" - - class dummy_1(BaseHash): - name = "dummy_1" - - self.assertRaises(KeyError, get_crypt_handler, "dummy_1") - - register_crypt_handler(dummy_1) - self.assertIs(get_crypt_handler("dummy_1"), dummy_1) - - with catch_warnings(): - warnings.filterwarnings("ignore", "handler names be lower-case, and use underscores instead of hyphens:.*", UserWarning) - self.assertIs(get_crypt_handler("DUMMY-1"), dummy_1) - -#========================================================= # #========================================================= class CryptPolicyTest(TestCase): diff --git a/passlib/tests/test_registry.py b/passlib/tests/test_registry.py new file mode 100644 index 0000000..e5999d7 --- /dev/null +++ b/passlib/tests/test_registry.py @@ -0,0 +1,145 @@ +"""tests for passlib.pwhash -- (c) Assurance Technologies 2003-2009""" +#========================================================= +#imports +#========================================================= +from __future__ import with_statement +#core +import hashlib +from logging import getLogger +import os +import time +import warnings +import sys +#site +#pkg +from passlib import hash, registry +from passlib.registry import register_crypt_handler, register_crypt_handler_path, \ + get_crypt_handler, list_crypt_handlers +from passlib.utils.drivers import BaseHash +from passlib.tests.utils import TestCase, mktemp, catch_warnings +#module +log = getLogger(__name__) + +#========================================================= +#test registry +#========================================================= +class dummy_0(BaseHash): + name = "dummy_0" + setting_kwds = () + +class alt_dummy_0(BaseHash): + name = "dummy_0" + setting_kwds = () + +dummy_x = 1 + +def unload_handler_name(name): + if hasattr(hash, name): + delattr(hash, name) + + #NOTE: this messes w/ internals of registry, shouldn't be used publically. + paths = registry._handler_locations + if name in paths: + del paths[name] + +class RegistryTest(TestCase): + + case_prefix = "passlib registry" + + def tearDown(self): + for name in ("dummy_0", "dummy_1", "dummy_x", "dummy_bad"): + unload_handler_name(name) + + def test_hash_proxy(self): + "test passlib.hash proxy object" + dir(hash) + repr(hash) + self.assertRaises(AttributeError, getattr, hash, 'fooey') + + def test_register_crypt_handler_path(self): + "test register_crypt_handler_path()" + + #NOTE: this messes w/ internals of registry, shouldn't be used publically. + paths = registry._handler_locations + + #check namespace is clear + self.assertTrue('dummy_0' not in paths) + self.assertFalse(hasattr(hash, 'dummy_0')) + + #try lazy load + register_crypt_handler_path('dummy_0', 'passlib.tests.test_registry') + self.assertTrue('dummy_0' in list_crypt_handlers()) + self.assertTrue('dummy_0' not in list_crypt_handlers(loaded_only=True)) + self.assertIs(hash.dummy_0, dummy_0) + self.assertTrue('dummy_0' in list_crypt_handlers(loaded_only=True)) + unload_handler_name('dummy_0') + + #try lazy load w/ alt + register_crypt_handler_path('dummy_0', 'passlib.tests.test_registry:alt_dummy_0') + self.assertIs(hash.dummy_0, alt_dummy_0) + unload_handler_name('dummy_0') + + #check lazy load w/ wrong type fails + register_crypt_handler_path('dummy_x', 'passlib.tests.test_registry') + self.assertRaises(TypeError, get_crypt_handler, 'dummy_x') + + #check lazy load w/ wrong name fails + register_crypt_handler_path('alt_dummy_0', 'passlib.tests.test_registry') + self.assertRaises(ValueError, get_crypt_handler, "alt_dummy_0") + + #TODO: check lazy load which calls register_crypt_handler (warning should be issued) + sys.modules.pop("passlib.tests._test_bad_register", None) + register_crypt_handler_path("dummy_bad", "passlib.tests._test_bad_register") + with catch_warnings(): + warnings.filterwarnings("ignore", "xxxxxxxxxx", DeprecationWarning) + h = get_crypt_handler("dummy_bad") + from passlib.tests import _test_bad_register as tbr + self.assertIs(h, tbr.alt_dummy_bad) + + def test_register_crypt_handler(self): + "test register_crypt_handler()" + + self.assertRaises(TypeError, register_crypt_handler, {}) + + self.assertRaises(ValueError, register_crypt_handler, BaseHash) + self.assertRaises(ValueError, register_crypt_handler, type('x', (BaseHash,), dict(name="AB_CD"))) + self.assertRaises(ValueError, register_crypt_handler, type('x', (BaseHash,), dict(name="ab-cd"))) + + class dummy_1(BaseHash): + name = "dummy_1" + + class dummy_1b(BaseHash): + name = "dummy_1" + + self.assertTrue('dummy_1' not in list_crypt_handlers()) + + register_crypt_handler(dummy_1) + register_crypt_handler(dummy_1) + self.assertIs(get_crypt_handler("dummy_1"), dummy_1) + + self.assertRaises(KeyError, register_crypt_handler, dummy_1b) + self.assertIs(get_crypt_handler("dummy_1"), dummy_1) + + register_crypt_handler(dummy_1b, force=True) + self.assertIs(get_crypt_handler("dummy_1"), dummy_1b) + + self.assertTrue('dummy_1' in list_crypt_handlers()) + + def test_get_crypt_handler(self): + "test get_crypt_handler()" + + class dummy_1(BaseHash): + name = "dummy_1" + + self.assertRaises(KeyError, get_crypt_handler, "dummy_1") + + register_crypt_handler(dummy_1) + self.assertIs(get_crypt_handler("dummy_1"), dummy_1) + + with catch_warnings(): + warnings.filterwarnings("ignore", "handler names be lower-case, and use underscores instead of hyphens:.*", UserWarning) + self.assertIs(get_crypt_handler("DUMMY-1"), dummy_1) + +#========================================================= +#EOF +#========================================================= diff --git a/passlib/tests/test_utils.py b/passlib/tests/test_utils.py index ad9dfaf..f0a5686 100644 --- a/passlib/tests/test_utils.py +++ b/passlib/tests/test_utils.py @@ -10,7 +10,7 @@ import random #pkg #module from passlib import utils -from passlib.base import CryptContext +from passlib.context import CryptContext from passlib.utils import h64, des, Undef from passlib.utils.md4 import md4 from passlib.tests.utils import TestCase, Params as ak, enable_option |
