コード例 #1
0
def generic_challenge_response_resync(wrapped_function, *args, **kwds):
    """
    Check if the authentication request results in an autosync

    Conditions: To do so we check for "otp1c" in the tokeninfo data.

    Policies: A policy defines that the token resync should be allowed this way.
    Note: The general config "autoresync" needs to be set anyways.

    args are:
    :param tokenobject_list: The list of all the tokens of the user, that will be checked
    :param passw: The password presented in the authentication.

    kwds are:
    :param options: options dictionary containing g
    :param user: The user_obj
    """
    success, reply_dict = wrapped_function(*args, **kwds)

    options = kwds.get("options") or {}
    # After a failed authentication, we check if the token has an otp1c
    if not success and reply_dict.get("serial"):
        # FIXME: Only works if the one token has a unique PIN
        serial = reply_dict.get("serial")
        g = options.get("g")
        # The tokenlist can contain more than one token. So we get the matching token object
        token_obj = next(t for t in args[0] if t.token.serial == serial)
        if token_obj and token_obj.get_tokeninfo("otp1c"):
            # We have an entry for resync
            if g and Match.token(g,
                                 scope=SCOPE.AUTH,
                                 action=ACTION.RESYNC_VIA_MULTICHALLENGE,
                                 token_obj=token_obj).any():
                reply_dict = _create_challenge(
                    token_obj, CHALLENGE_TYPE.RESYNC,
                    _("To resync your token, please enter the next OTP value"))

    return success, reply_dict
コード例 #2
0
def generic_challenge_response_reset_pin(wrapped_function, *args, **kwds):
    """
    Check if the authentication was successful, but if the token needs to reset
    its PIN.

    Conditions: To do so we check for "next_pin_change" in the tokeninfo data. This
    is however easily done using token.is_pin_change().

    Policies: A policy defines, if this PIN reset functionality should be active
    at all. scope=AUTH, action=CHANGE_PIN_VIA_VALIDATE

    args are:
    :param tokenobject_list: The list of all the tokens of the user, that will be checked
    :param passw: The password presented in the authentication. We need this for the PIN reset.

    kwds are:
    :param options: options dictionary containing g
    :param user: The user_obj
    """

    # Before we call the wrapped function, we need to check, if we have a generic challenge
    # for the given transaction_id and if the token serial matches a given token
    options = kwds.get("options") or {}
    user_obj = kwds.get("user")
    transaction_id = options.get("transaction_id") or options.get("state")
    if transaction_id:
        challenges = get_challenges(transaction_id=transaction_id,
                                    challenge=CHALLENGE_TYPE.PIN_RESET)
        if len(challenges) == 1:
            challenge = challenges[0]
            # check if challenge matches a token and if it is valid
            token_obj = next(t for t in args[0]
                             if t.token.serial == challenge.serial)
            if token_obj:
                # Then either verify the PIN or set the PIN the first time. The
                # PIN from the 1st response is stored in challenge.data
                if challenge.data:
                    # Verify the password
                    if verify_pass_hash(args[1], challenge.data):
                        g = options.get("g")
                        challenge.set_otp_status(True)
                        token_obj.challenge_janitor()
                        # Success, set new PIN and return success
                        token_obj.set_pin(args[1])
                        pinpol = Match.token(
                            g,
                            scope=SCOPE.ENROLL,
                            action=ACTION.CHANGE_PIN_EVERY,
                            token_obj=token_obj).action_values(unique=True)
                        # Set a new next_pin_change
                        if pinpol:
                            # Set a new next pin change
                            token_obj.set_next_pin_change(diff=list(pinpol)[0])
                        else:
                            # Obviously the admin removed the policy for changing pins,
                            # so we will not require to change the PIN again
                            token_obj.del_tokeninfo("next_pin_change")
                        return True, {
                            "message": "PIN successfully set.",
                            "serial": token_obj.token.serial
                        }
                    else:
                        return False, {
                            "serial": token_obj.token.serial,
                            "message": "PINs do not match"
                        }
                else:
                    # The PIN is presented the first time.
                    # Verify if the PIN adheres to the PIN policies. This is always in the normal user context
                    g = options.get("g")
                    g.logged_in_user = {"role": SCOPE.USER}
                    if user_obj:
                        # check_pin below originally works for logged in users, since only logged in users
                        # are allowed to change the pin. So we need to construct a logged_in_user object, otherwise
                        # check_pin would fail.
                        g.logged_in_user["username"] = user_obj.login
                        g.logged_in_user["realm"] = user_obj.realm
                    check_pin(g, args[1], token_obj.token.tokentype, user_obj)
                    # We need to ask for a 2nd time
                    challenge.set_otp_status(True)
                    seed = get_rand_digit_str(SEED_LENGTH)
                    reply_dict = _create_pin_reset_challenge(
                        token_obj, _("Please enter the new PIN again"),
                        pass_hash(args[1]))
                    return False, reply_dict

    success, reply_dict = wrapped_function(*args, **kwds)

    # After a successful authentication, we might start the PIN change process
    if success and reply_dict.get("pin_change"):
        g = options.get("g")
        # Determine the realm by the serial
        serial = reply_dict.get("serial")
        # The tokenlist can contain more than one token. So we get the matching token object
        token_obj = next(t for t in args[0] if t.token.serial == serial)
        if g and Match.token(g,
                             scope=SCOPE.AUTH,
                             action=ACTION.CHANGE_PIN_VIA_VALIDATE,
                             token_obj=token_obj).any():
            reply_dict = _create_pin_reset_challenge(
                token_obj, _("Please enter a new PIN"))
            return False, reply_dict

    return success, reply_dict