diff options
-rw-r--r-- | CHANGES | 3 | ||||
-rw-r--r-- | docs/conf.py | 5 | ||||
-rw-r--r-- | docs/contents.rst | 7 | ||||
-rw-r--r-- | docs/lib/passlib.ext.django.rst | 129 | ||||
-rw-r--r-- | passlib/ext/django/__init__.py | 2 | ||||
-rw-r--r-- | passlib/ext/django/models.py | 84 | ||||
-rw-r--r-- | passlib/ext/django/utils.py | 55 |
7 files changed, 198 insertions, 87 deletions
@@ -67,6 +67,9 @@ Release History * Builtin tests now use :mod:`!unittest2` if available. * Setup script no longer requires distribute or setuptools. + * added (undocumented, experimental) Django app + for overriding Django's default hash format, + see ``docs/lib/passlib.ext.django.rst`` for more. **1.4** (2011-05-04) diff --git a/docs/conf.py b/docs/conf.py index 4167e36..29239be 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -85,7 +85,10 @@ version = cloud_sptheme.get_version(release) # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = [] +exclude_patterns = [ + #disabling documentation of this until module is more mature. + "lib/passlib.ext.django.rst" +] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None diff --git a/docs/contents.rst b/docs/contents.rst index 436b578..058361c 100644 --- a/docs/contents.rst +++ b/docs/contents.rst @@ -21,7 +21,7 @@ Table Of Contents lib/passlib.registry lib/passlib.utils - + modular_crypt_format history @@ -29,3 +29,8 @@ Table Of Contents * :ref:`General Index <genindex>` * :ref:`Module List <modindex>` + +.. + unlisted: + + lib/passlib.ext.django diff --git a/docs/lib/passlib.ext.django.rst b/docs/lib/passlib.ext.django.rst new file mode 100644 index 0000000..69e8970 --- /dev/null +++ b/docs/lib/passlib.ext.django.rst @@ -0,0 +1,129 @@ +.. index:: django; password hashing app + +================================================== +:mod:`passlib.ext.django` - Django Password Helper +================================================== + +.. module:: passlib.ext.django + +.. warning:: + + This module is currently under development. + It will probably work, but has not seen very much + testing or real-world use, and may change in future releases; + *caveat emptor*. + +.. todo:: + + This documentation needs to be cleaned up significantly + for new users. + +Overview +======== +This module is intended for use with +`Django <http://www.djangoproject.com>`_-based web applications. +It contains a Django app which allows you to override +Django's :doc:`default <passlib.hash.django_std>` password hash formats +with any passlib :doc:`CryptContext <passlib.context>`. +By default, it comes configured to add support for +:class:`~passlib.hash.pbkdf2_sha256`, and will automatically +upgrade all existing Django passwords as your users log in. + +Installation +============= +Installation is simple, just add ``passlib.ext.django`` to +``settings.INSTALLED_APPS``. This module will handle +everything else. + +Once done, when this app is imported by Django, +it will automatically monkeypatch +:class:`!django.contrib.auth.models.User` +to use a Passlib CryptContext instance in place of normal Django +password authentication. This provides hash migration, +ability to set stronger policies for superuser & staff passwords, +and stronger password hashing schemes. + +Configuration +============= +You can set the following options in django ``settings.py``: + +``PASSLIB_CONTEXT`` + This may be one of a number of values: + + * The string ``"passlib-default"``, which will cause Passlib + to replace Django's hash routines with a builtin policy + that supports all existing django hashes; but as users + log in, upgrades them all to :class:`~passlib.hash.pbkdf2_sha256`. + It also supports stronger hashing for the superuser account. + + This is the default behavior if ``PASSLIB_CONTEXT`` is not set. + + The exact default policy can be found at + :data:`passlib.ext.django.utils.DEFAULT_CTX`. + + * ``None``, in which case this app will do nothing when django is loaded. + + * A :class:`~passlib.context.CryptContext` + instance which will be used in place of the normal Django password + hash routines. + + It is *strongly* recommended to use a context which will support + the existing Django hashes. + + * A multiline config string suitable for passing to + :meth:`passlib.context.CryptPolicy.from_string`. + This will be parsed and used much like a :class:`!CryptContext` instance. + +``PASSLIB_GET_CATEGORY`` + + By default, Passlib will invoke the specified context with a category + string that's dependant on the User instance. + superusers will be assigned to the ``superuser`` category, + staff to the ``staff`` category, and all other accounts + assigned to ``None``. + + This allows overriding that logic by specifying an alternate + function of the format ``get_category(user) -> category|None``. + + .. seealso:: + + See :ref:`user-categories` for more details about + the category system in Passlib. + +Utility Functions +================= +.. module:: passlib.ext.django.utils + +Whether or not you install this application into Django, +the following utility functions are available for overriding +Django's password hashes: + +.. data:: DEFAULT_CTX + + This is a string containing the default hashing policy + that will be used by this application if none is specified + via ``settings.PASSLIB_CONTEXT``. + It defaults to the following:: + + [passlib] + schemes = + pbkdf2_sha256, + django_salted_sha1, django_salted_md5, + django_des_crypt, hex_md5, + django_disabled + + default = pbkdf2_sha256 + + deprecated = + django_salted_sha1, django_salted_md5, + django_des_crypt, hex_md5 + + all__vary_rounds = 5%% + + pbkdf2_sha256__default_rounds = 4000 + staff__pbkdf2_sha256__default_rounds = 8000 + superuser__pbkdf2_sha256__default_rounds = 10000 + +.. autofunction:: get_category + +.. autofunction:: set_django_password_context
\ No newline at end of file diff --git a/passlib/ext/django/__init__.py b/passlib/ext/django/__init__.py index 1545e9c..b4fcb2c 100644 --- a/passlib/ext/django/__init__.py +++ b/passlib/ext/django/__init__.py @@ -6,5 +6,5 @@ and not officially documented in Passlib just yet (though it should work). -see ``models`` submodule for details on how this app works. +see the Passlib documentation for details on how to use this app """ diff --git a/passlib/ext/django/models.py b/passlib/ext/django/models.py index 02b54cc..aaf13ee 100644 --- a/passlib/ext/django/models.py +++ b/passlib/ext/django/models.py @@ -6,58 +6,7 @@ and not officially documented in Passlib just yet (though it should work). -When this is imported on Django load, -it automatically monkeypatches -:class:`django.contrib.auth.models.User` -to use a Passlib CryptContext instance in place of normal Django -password authentication. This provides hash migration, -ability to set stronger policies for superuser & staff passwords, -and stronger password hashing schemes. - -You can set the following options in django ``settings.py``: - -``PASSLIB_CONTEXT`` - This may be one of a number of values: - - * The string ``"passlib-default"``, which will cause Passlib - to replace Django's hash routines with a builtin policy - that supports all existing django hashes; but as users - log in, upgrades them all to :class:`~passlib.hash.pbkdf2_sha256`. - It also supports stronger hashing for the superuser account. - - This is the default behavior if ``PASSLIB_CONTEXT`` is not set. - - The exact policy can be found at - :data:`passlib.ext.django.models.passlib_default_ctx`. - - * ``None``, in which case this app will do nothing when django is loaded. - - * A :class:`~passlib.context.CryptContext` - instance which will be used in place of the normal Django password - hash routines. - - It is *strongly* recommended to use a context which will support - the existing Django hashes. - - * A multiline config string suitable for passing to - :meth:`passlib.context.CryptPolicy.from_string`. - This will be parsed and used much like a :class:`!CryptContext` instance. - -``PASSLIB_GET_CATEGORY`` - - By default, Passlib will invoke the specified context with a category - string that's dependant on the User instance. - superusers will be assigned to the ``superuser`` category, - staff to the ``staff`` category, and all other accounts - assigned to ``None``. - - This allows overriding that logic by specifying an alternate - function of the format ``get_category(user) -> category|None``. - - .. seealso:: - - See :ref:`user-categories` for more details about - the category system in Passlib. +see the Passlib documentation for details on how to use this app """ #=================================================================== #imports @@ -67,33 +16,8 @@ from django.conf import settings #pkg from passlib.context import CryptContext, CryptPolicy from passlib.utils import is_crypt_context, bytes -from passlib.ext.django.utils import get_category, set_django_password_context - -#=================================================================== -#constants -#=================================================================== - -#: default context used by app -passlib_default_ctx = """ -[passlib] -schemes = - pbkdf2_sha256, - django_salted_sha1, django_salted_md5, - django_des_crypt, hex_md5, - django_disabled - -default = pbkdf2_sha256 - -deprecated = - django_salted_sha1, django_salted_md5, - django_des_crypt, hex_md5 - -all__vary_rounds = 5%% - -pbkdf2_sha256__default_rounds = 4000 -staff__pbkdf2_sha256__default_rounds = 8000 -superuser__pbkdf2_sha256__default_rounds = 10000 -""" +from passlib.ext.django.utils import DEFAULT_CTX, get_category, \ + set_django_password_context #=================================================================== #main @@ -107,7 +31,7 @@ def patch(): if not ctx: return if ctx == "passlib-default": - ctx = passlib_default_ctx + ctx = DEFAULT_CTX if isinstance(ctx, (unicode, bytes)): ctx = CryptPolicy.from_string(ctx) if isinstance(ctx, CryptPolicy): diff --git a/passlib/ext/django/utils.py b/passlib/ext/django/utils.py index 9285f16..41d4196 100644 --- a/passlib/ext/django/utils.py +++ b/passlib/ext/django/utils.py @@ -10,7 +10,6 @@ #imports #=================================================================== #site -from django.contrib.auth.models import User #pkg from passlib.utils import is_crypt_context, bytes #local @@ -20,6 +19,45 @@ __all__ = [ ] #=================================================================== +#lazy import +#=================================================================== +#NOTE: doing this lazily so sphinx can crawl module without +# having django import problems. + +User = None #imported from django.contrib.auth.models + +def _lazy_import(): + global User + if User is None: + from django.contrib.auth.models import User + +#=================================================================== +#constants +#=================================================================== + +#: default context used by app +DEFAULT_CTX = """ +[passlib] +schemes = + pbkdf2_sha256, + django_salted_sha1, django_salted_md5, + django_des_crypt, hex_md5, + django_disabled + +default = pbkdf2_sha256 + +deprecated = + django_salted_sha1, django_salted_md5, + django_des_crypt, hex_md5 + +all__vary_rounds = 5%% + +pbkdf2_sha256__default_rounds = 4000 +staff__pbkdf2_sha256__default_rounds = 8000 +superuser__pbkdf2_sha256__default_rounds = 10000 +""" + +#=================================================================== #monkeypatch framework #=================================================================== @@ -31,7 +69,15 @@ __all__ = [ _django_patch_state = None def get_category(user): - "default get_category() implementation used by set_django_password_context" + """default get_category() implementation used by set_django_password_context + + this is the function used if ``settings.PASSLIB_GET_CONTEXT`` is not + specified. + + it maps superusers to the ``"superuser"`` category, + staff to the ``"staff"`` category, + and all others to the default category. + """ if user.is_superuser: return "superuser" if user.is_staff: @@ -43,7 +89,7 @@ def um(func): return func.im_func def set_django_password_context(context=None, get_category=get_category): - """monkeypatches django.contrib.auth to use specified password context + """monkeypatches :mod:`!django.contrib.auth` to use specified password context. :arg context: Passlib context to use for Django password hashing. @@ -64,8 +110,9 @@ def set_django_password_context(context=None, get_category=get_category): By default, uses a function which returns ``"superuser"`` for superusers, and ``"staff"`` for staff. """ - global _django_patch_state + global _django_patch_state, User state = _django_patch_state + _lazy_import() # issue warning if something else monkeypatched User # while our patch was applied. |