Ejemplo n.º 1
0
 def test_is_crypt_context(self):
     "test is_crypt_context()"
     from passlib.utils import is_crypt_context
     from passlib.context import CryptContext
     cc = CryptContext(["des_crypt"])
     self.assertTrue(is_crypt_context(cc))
     self.assertFalse(not is_crypt_context(cc))
Ejemplo n.º 2
0
 def test_is_crypt_context(self):
     "test is_crypt_context()"
     from passlib.utils import is_crypt_context
     from passlib.context import CryptContext
     cc = CryptContext(["des_crypt"])
     self.assertTrue(is_crypt_context(cc))
     self.assertFalse(not is_crypt_context(cc))
def patch():
    #get config
    ctx = getattr(settings, "PASSLIB_CONTEXT", "passlib-default")
    catfunc = getattr(settings, "PASSLIB_GET_CATEGORY", get_category)

    #parse & validate input value
    if not ctx:
        # remove any patching that was already set, just in case.
        set_django_password_context(None)
        return
    if ctx == "passlib-default":
        ctx = DEFAULT_CTX
    if isinstance(ctx, (unicode, bytes)):
        ctx = CryptPolicy.from_string(ctx)
    if isinstance(ctx, CryptPolicy):
        ctx = CryptContext(policy=ctx)
    if not is_crypt_context(ctx):
        raise TypeError("django settings.PASSLIB_CONTEXT must be CryptContext instance or config string: %r" % (ctx,))

    #monkeypatch django.contrib.auth.models:User
    set_django_password_context(ctx, get_category=catfunc)
Ejemplo n.º 4
0
def patch():
    #get config
    ctx = getattr(settings, "PASSLIB_CONTEXT", "passlib-default")
    catfunc = getattr(settings, "PASSLIB_GET_CATEGORY", get_category)

    #parse & validate input value
    if not ctx:
        # remove any patching that was already set, just in case.
        set_django_password_context(None)
        return
    if ctx == "passlib-default":
        ctx = DEFAULT_CTX
    if isinstance(ctx, (unicode, bytes)):
        ctx = CryptPolicy.from_string(ctx)
    if isinstance(ctx, CryptPolicy):
        ctx = CryptContext(policy=ctx)
    if not is_crypt_context(ctx):
        raise TypeError(
            "django settings.PASSLIB_CONTEXT must be CryptContext instance or config string: %r"
            % (ctx, ))

    #monkeypatch django.contrib.auth.models:User
    set_django_password_context(ctx, get_category=catfunc)
Ejemplo n.º 5
0
 def test_is_crypt_context(self):
     "test is_crypt_context()"
     cc = CryptContext(["des_crypt"])
     self.assertTrue(utils.is_crypt_context(cc))
     self.assertFalse(not utils.is_crypt_context(cc))
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
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
Ejemplo n.º 8
0
 def test_is_crypt_context(self):
     "test is_crypt_context()"
     cc = CryptContext(["des_crypt"])
     self.assertTrue(utils.is_crypt_context(cc))
     self.assertFalse(not utils.is_crypt_context(cc))