/usr/lib/python2.7/dist-packages/passlib/ext/django/utils.py is in python-passlib 1.5.3-0ubuntu3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | """passlib.ext.django.utils - helper functions for patching Django hashing
.. warning::
This code is experimental and subject to change,
and not officially documented in Passlib just yet
(though it should work).
"""
#===================================================================
#imports
#===================================================================
#site
from warnings import warn
#pkg
from passlib.utils import is_crypt_context, bytes
#local
__all__ = [
"get_category",
"set_django_password_context",
]
#===================================================================
#lazy imports
#===================================================================
_has_django0 = None # old 0.9 django - lacks unusable_password support
_dam = None #django.contrib.auth.models reference
def _import_django():
global _dam, _has_django0
if _dam is None:
import django.contrib.auth.models as _dam
from django import VERSION
_has_django0 = VERSION < (1,0)
return _dam
#===================================================================
#constants
#===================================================================
#: base context mirroring django's setup
STOCK_CTX = """
[passlib]
schemes =
django_salted_sha1, django_salted_md5,
django_des_crypt, hex_md5,
django_disabled
default = django_salted_sha1
deprecated = hex_md5
"""
#: default context used by app
DEFAULT_CTX = """
[passlib]
schemes =
sha512_crypt,
pbkdf2_sha256,
django_salted_sha1, django_salted_md5,
django_des_crypt, hex_md5,
django_disabled
default = sha512_crypt
deprecated =
pbkdf2_sha256,
django_salted_sha1, django_salted_md5,
django_des_crypt, hex_md5
all__vary_rounds = 5%%
sha512_crypt__default_rounds = 15000
staff__sha512_crypt__default_rounds = 25000
superuser__sha512_crypt__default_rounds = 35000
"""
#===================================================================
# helpers
#===================================================================
def get_category(user):
"""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:
return "staff"
return None
def um(func):
"unwrap method (eg User.set_password -> orig func)"
return func.im_func
#===================================================================
# monkeypatch framework
#===================================================================
# NOTE: this moneypatcher was written to be useful
# outside of this module, and re-invokable,
# which is why it tries so hard to maintain
# sanity about it's patch state.
_django_patch_state = None #dict holding refs to undo patch
def set_django_password_context(context=None, get_category=get_category):
"""monkeypatches :mod:`!django.contrib.auth` to use specified password context.
:arg context:
Passlib context to use for Django password hashing.
If ``None``, restores original Django functions.
In order to support existing hashes,
any context specified should include
all the hashes in :data:`django_context`
in addition to custom hashes.
:param get_category:
Optional function to use when mapping Django user ->
CryptContext category.
If a function, should have syntax ``catfunc(user) -> category|None``.
If ``None``, no function is used.
By default, uses a function which returns ``"superuser"``
for superusers, and ``"staff"`` for staff.
This function monkeypatches the following parts of Django:
* :func:`!django.contrib.auth.models.check_password`
* :meth:`!django.contrib.auth.models.User.check_password`
* :meth:`!django.contrib.auth.models.User.set_password`
It also stores the provided context in
:data:`!django.contrib.auth.models.User.password_context`,
for easy access.
"""
global _django_patch_state, _dam, _has_django0
_import_django()
state = _django_patch_state
User = _dam.User
# issue warning if something else monkeypatched User
# while our patch was applied.
if state is not None:
if um(User.set_password) is not state['user_set_password']:
warn("another library has patched "
"django.contrib.auth.models:User.set_password")
if um(User.check_password) is not state['user_check_password']:
warn("another library has patched"
"django.contrib.auth.models:User.check_password")
if _dam.check_password is not state['models_check_password']:
warn("another library has patched"
"django.contrib.auth.models:check_password")
#check if we should just restore original state
if context is None:
if state is not None:
del User.password_context
_dam.check_password = state['orig_models_check_password']
User.set_password = state['orig_user_set_password']
User.check_password = state['orig_user_check_password']
_django_patch_state = None
return
#validate inputs
if not is_crypt_context(context):
raise TypeError("context must be CryptContext instance or None: %r" %
(type(context),))
#backup original state if this is first call
if state is None:
_django_patch_state = state = dict(
orig_user_check_password = um(User.check_password),
orig_user_set_password = um(User.set_password),
orig_models_check_password = _dam.check_password,
)
#prepare replacements
if _has_django0:
UNUSABLE_PASSWORD = "!"
else:
UNUSABLE_PASSWORD = _dam.UNUSABLE_PASSWORD
def set_password(user, raw_password):
"passlib replacement for User.set_password()"
if raw_password is None:
if _has_django0:
# django 0.9
user.password = UNUSABLE_PASSWORD
else:
user.set_unusable_password()
else:
cat = get_category(user) if get_category else None
user.password = context.encrypt(raw_password, category=cat)
def check_password(user, raw_password):
"passlib replacement for User.check_password()"
if raw_password is None:
return False
hash = user.password
if not hash or hash == UNUSABLE_PASSWORD:
return False
cat = get_category(user) if get_category else None
ok, new_hash = context.verify_and_update(raw_password, hash,
category=cat)
if ok and new_hash is not None:
user.password = new_hash
user.save()
return ok
def raw_check_password(raw_password, enc_password):
"passlib replacement for check_password()"
if not enc_password or enc_password == UNUSABLE_PASSWORD:
raise ValueError("no password hash specified")
return context.verify(raw_password, enc_password)
#set new state
User.password_context = context
User.set_password = state['user_set_password'] = set_password
User.check_password = state['user_check_password'] = check_password
_dam.check_password = state['models_check_password'] = raw_check_password
state['context' ] = context
state['get_category'] = get_category
##def get_django_password_context():
## """return current django password context
##
## This returns the current :class:`~passlib.context.CryptContext` instance
## set by :func:`set_django_password_context`.
## If not context has been set, returns ``None``.
## """
## global _django_patch_state
## if _django_patch_state:
## return _django_patch_state['context']
## else:
## return None
#===================================================================
#eof
#===================================================================
|