Exemplo n.º 1
0
    def authenticate(self, passw, user, options=None):
        """
        This is the method that verifies single shot authentication like
        they are done with push button tokens.

        It is a high level interface to support as well other tokens, which
        do not have a pin and otp seperation - they could overwrite
        this method

        **remarks:** we have to call the global methods (check_pin,++) as they
        take the pin policies into account

        :param passw: the passw which could be pin+otp
        :type passw: string
        :param user: The authenticating user
        :type user: User object
        :param options: dictionary of additional request parameters
        :type options: (dict)

        :return: returns tuple true or false for the pin match, the otpcounter
                 (int) and the reply (dict) that will be added as additional
                 information in the JSON response of ``/validate/check``.
        """

        pin_match = False
        otp_counter = -1
        reply = None

        (res, pin, otpval) = split_pin_otp(self, passw, user, options=options)
        if res != -1:
            pin_policies = get_pin_policies(user)
            if 1 in pin_policies:
                otp_counter = check_otp(self, otpval, options=options)
                if otp_counter >= 0:
                    pin_match = check_pin(self,
                                          pin,
                                          user=user,
                                          options=options)
                    if not pin_match:
                        otp_counter = -1
            else:
                pin_match = check_pin(self, pin, user=user, options=options)
                if pin_match is True:
                    otp_counter = check_otp(self, otpval, options=options)

        # for special token that have no otp like passwordtoken
        if not self.auth_info and pin_match is True and otp_counter == 0:
            self.auth_info = {"auth_info": [("pin_length", len(passw))]}

        return (pin_match, otp_counter, reply)
Exemplo n.º 2
0
    def authenticate(self, passw, user, options=None):
        '''
        This is the method that verifies single shot authentication like
        they are done with push button tokens.

        It is a high level interface to support as well other tokens, which
        do not have a pin and otp seperation - they could overwrite
        this method

        **remarks:** we have to call the global methods (check_pin,++) as they
        take the pin policies into account

        :param passw: the passw which could be pin+otp
        :type passw: string
        :param user: The authenticating user
        :type user: User object
        :param options: dictionary of additional request parameters
        :type options: (dict)

        :return: returns tuple true or false for the pin match, the otpcounter
                 (int) and the reply (dict) that will be added as additional
                 information in the JSON response of ``/validate/check``.
        '''

        pin_match = False
        otp_counter = -1
        reply = None

        (res, pin, otpval) = split_pin_otp(self, passw, user, options=options)
        if res != -1:
            pin_policies = get_pin_policies(user)
            if 1 in pin_policies:
                otp_counter = check_otp(self, otpval, options=options)
                if otp_counter >= 0:
                    pin_match = check_pin(
                        self, pin, user=user, options=options)
                    if not pin_match:
                        otp_counter = -1
            else:
                pin_match = check_pin(self, pin, user=user, options=options)
                if pin_match is True:
                    otp_counter = check_otp(self, otpval, options=options)

        # for special token that have no otp like passwordtoken
        if not self.auth_info and pin_match is True and otp_counter == 0:
            self.auth_info = {'auth_info': [('pin_length', len(passw))]}

        return (pin_match, otp_counter, reply)
Exemplo n.º 3
0
    def is_challenge_response(
        self, passw, user, options=None, challenges=None
    ):
        """
        check, if the request contains the result of a challenge

        :param passw: password, which might be pin or pin+otp
        :param user: the requesting user
        :param options: dictionary of additional request parameters

        :return: returns true or false
        """

        if "state" in options or "transactionid" in options:
            return True

        # it as well might be a challenge response,
        # if the passw is longer than the pin
        (res, pin, otpval) = split_pin_otp(
            self, passw, user=user, options=options
        )
        if res >= 0:
            otp_counter = check_otp(self, otpval, options=options)
            if otp_counter >= 1:
                pin_match = check_pin(self, pin, user=user, options=options)
                if not pin_match:
                    return False
            if otp_counter >= 0:
                return True

        return False
Exemplo n.º 4
0
    def is_challenge_response(self, passw, user, options=None,
                              challenges=None):
        '''
        check, if the request contains the result of a challenge

        :param passw: password, which might be pin or pin+otp
        :param user: the requesting user
        :param options: dictionary of additional request parameters

        :return: returns true or false
        '''

        if "state" in options or "transactionid" in options:
            return True

        # it as well might be a challenge response,
        # if the passw is longer than the pin
        (res, pin, otpval) = split_pin_otp(self, passw, user=user,
                                           options=options)
        if res >= 0:
            otp_counter = check_otp(self, otpval, options=options)
            if otp_counter >= 1:
                pin_match = check_pin(self, pin, user=user, options=options)
                if not pin_match:
                    return False
            if otp_counter >= 0:
                return True

        return False
Exemplo n.º 5
0
    def checkResponse4Challenge(self, user, passw, options=None, challenges=None):
        '''
        verify the response of a previous challenge

        :param user:     the requesting user
        :param passw:    the to be checked pass (pin+otp)
        :param options:  options an additional argument, which could be token
                          specific
        :param challenges: the list of challenges, where each challenge is
                            described as dict
        :return: tuple of (otpcounter and the list of matching challenges)

        '''
        otp_counter = -1
        transid = None
        matching = None
        matchin_challenges = []

        if 'transactionid' in options or 'state' in options:
            ## fetch the transactionid
            transid = options.get('transactionid', options.get('state', None))

        # check if the transactionid is in the list of challenges
        if transid is not None:
            for challenge in challenges:
                if Challenges.is_same_transaction(challenge, transid):
                    matching = challenge
                    break
            if matching is not None:
                otp_counter = check_otp(self, passw, options=options)
                if otp_counter >= 0:
                    matchin_challenges.append(matching)

        return (otp_counter, matchin_challenges)
Exemplo n.º 6
0
    def is_challenge_response(self, passw, user, options=None,
                              challenges=None):
        """
        check if the request contains the result of a challenge

        :param passw: password, which might be pin or pin+otp
        :param user: the requesting user
        :param options: dictionary of additional request parameters
        :param challenges: Not used in this method #TODO
        :return: returns true or false
        """

        if "state" in options or "transactionid" in options:
            return True

        # LEGACY: some client applications can not process transaction ids.
        # to support them, we provide a workaround heuristic with pin+otp

        (policy_type, pin, otp_val) = split_pin_otp(self, passw, user=user,
                                           options=options)
        if policy_type >= 0:
            otp_counter = check_otp(self, otp_val, options=options)
            if otp_counter >= 1:
                pin_match = check_pin(self, pin, user=user, options=options)
                if not pin_match:
                    return False
            if otp_counter >= 0:
                return True

        return False
Exemplo n.º 7
0
    def checkResponse4Challenge(self,
                                user,
                                passw,
                                options=None,
                                challenges=None):
        """
        This method verifies if the given ``passw`` matches any existing ``challenge``
        of the token.

        It then returns the new otp_counter of the token and the
        list of the matching challenges.

        In case of success the otp_counter needs to be > 0.
        The matching_challenges is passed to the method
        :py:meth:`~linotp.tokens.base.TokenClass.challenge_janitor`
        to clean up challenges.

        :param user: the requesting user
        :type user: User object
        :param passw: the password (pin+otp)
        :type passw: string
        :param options:  additional arguments from the request, which could be token specific
        :type options: dict
        :param challenges: A sorted list of valid challenges for this token.
        :type challenges: list
        :return: tuple of (otpcounter and the list of matching challenges)
        """
        otp_counter = -1
        transid = None
        matching = None
        matching_challenges = []

        # fetch the transactionid
        if 'transactionid' in options:
            transid = options.get('transactionid', None)

        # check if the transactionid is in the list of challenges
        if transid is not None:
            for challenge in challenges:
                if Challenges.is_same_transaction(challenge, transid):
                    matching = challenge
                    break
            if matching is not None:
                # Split pin from otp and check the resulting pin and otpval
                (pin, otpval) = self.splitPinPass(passw)
                if not check_pin(self, pin, user=user, options=options):
                    otpval = passw
                # The U2F checkOtp functions needs to know the saved challenge
                # to compare the received challenge value to the saved one,
                # thus we add the transactionid to the options
                options['transactionid'] = transid
                options['challenges'] = challenges
                otp_counter = check_otp(self, otpval, options=options)
                if otp_counter >= 0:
                    matching_challenges.append(matching)

        return (otp_counter, matching_challenges)
Exemplo n.º 8
0
    def checkResponse4Challenge(self, user, passw, options=None, challenges=None):
        """
        This method verifies if the given ``passw`` matches any existing ``challenge``
        of the token.

        It then returns the new otp_counter of the token and the
        list of the matching challenges.

        In case of success the otp_counter needs to be > 0.
        The matching_challenges is passed to the method
        :py:meth:`~linotp.tokens.base.TokenClass.challenge_janitor`
        to clean up challenges.

        :param user: the requesting user
        :type user: User object
        :param passw: the password (pin+otp)
        :type passw: string
        :param options:  additional arguments from the request, which could be token specific
        :type options: dict
        :param challenges: A sorted list of valid challenges for this token.
        :type challenges: list
        :return: tuple of (otpcounter and the list of matching challenges)
        """
        otp_counter = -1
        transid = None
        matching = None
        matching_challenges = []

        # fetch the transactionid
        if 'transactionid' in options:
            transid = options.get('transactionid', None)

        # check if the transactionid is in the list of challenges
        if transid is not None:
            for challenge in challenges:
                if Challenges.is_same_transaction(challenge, transid):
                    matching = challenge
                    break
            if matching is not None:
                # Split pin from otp and check the resulting pin and otpval
                (pin, otpval) = self.splitPinPass(passw)
                if not check_pin(self, pin, user=user, options=options):
                    otpval = passw
                # The U2F checkOtp functions needs to know the saved challenge
                # to compare the received challenge value to the saved one,
                # thus we add the transactionid to the options
                options['transactionid'] = transid
                options['challenges'] = challenges
                otp_counter = check_otp(self, otpval, options=options)
                if otp_counter >= 0:
                    matching_challenges.append(matching)

        return (otp_counter, matching_challenges)
Exemplo n.º 9
0
    def checkResponse4Challenge(self,
                                user,
                                passw,
                                options=None,
                                challenges=None):
        '''
        This method verifies if the given ``passw`` matches any existing
        ``challenge`` of the token.

        It then returns the new otp_counter of the token and the
        list of the matching challenges.

        In case of success the otp_counter needs to be > 0.
        The matching_challenges is passed to the method
        :py:meth:`~linotp.tokens.base.TokenClass.challenge_janitor`
        to clean up challenges.

        :param user: the requesting user
        :type user: User object
        :param passw: the password (pin+otp)
        :type passw: string
        :param options:  additional arguments from the request, which could
                         be token specific
        :type options: dict
        :param challenges: A sorted list of valid challenges for this token.
        :type challenges: list
        :return: tuple of (otpcounter and the list of matching challenges)

        '''
        otp_counter = -1
        transid = None
        matching = None
        matching_challenges = []

        if 'transactionid' in options or 'state' in options:
            # fetch the transactionid
            transid = options.get('transactionid', None)
            if transid is None:
                transid = options.get('state', None)

        # check if the transactionid is in the list of challenges
        if transid is not None:
            for challenge in challenges:
                if Challenges.is_same_transaction(challenge, transid):
                    matching = challenge
                    break
            if matching is not None:
                otp_counter = check_otp(self, passw, options=options)
                if otp_counter >= 0:
                    matching_challenges.append(matching)

        return (otp_counter, matching_challenges)
Exemplo n.º 10
0
    def checkResponse4Challenge(
        self, user, passw, options=None, challenges=None
    ):
        """
        This method verifies if the given ``passw`` matches any existing ``challenge``
        of the token.

        It then returns the new otp_counter of the token and the
        list of the matching challenges.

        In case of success the otp_counter needs to be > 0.
        The matching_challenges is passed to the method
        :py:meth:`~linotp.tokens.base.TokenClass.challenge_janitor`
        to clean up challenges.

        :param user: the requesting user
        :type user: User object
        :param passw: the password (pin+otp)
        :type passw: string
        :param options:  additional arguments from the request, which could be token specific
        :type options: dict
        :param challenges: A sorted list of valid challenges for this token.
        :type challenges: list
        :return: tuple of (otpcounter and the list of matching challenges)
        """
        if not challenges:
            return -1, []

        otp_counter = -1
        matching_challenges = []

        for challenge in challenges:
            # Split pin from otp and check the resulting pin and otpval
            (pin, otpval) = self.splitPinPass(passw)
            if not check_pin(self, pin, user=user, options=options):
                otpval = passw
            # The U2F checkOtp functions needs to know the saved challenge
            # to compare the received challenge value to the saved one,
            # thus we add the transactionid to the options
            options["transactionid"] = challenge.transid
            options["challenges"] = challenges

            _otp_counter = check_otp(self, otpval, options=options)
            if _otp_counter >= 0:
                matching_challenges.append(challenge)

                # ensure that a positive otp_counter is preserved
                otp_counter = _otp_counter

        return otp_counter, matching_challenges
Exemplo n.º 11
0
    def checkResponse4Challenge(self, user, passw, options=None,
                                challenges=None):
        '''
        This method verifies if the given ``passw`` matches any existing
        ``challenge`` of the token.

        It then returns the new otp_counter of the token and the
        list of the matching challenges.

        In case of success the otp_counter needs to be > 0.
        The matching_challenges is passed to the method
        :py:meth:`~linotp.tokens.base.TokenClass.challenge_janitor`
        to clean up challenges.

        :param user: the requesting user
        :type user: User object
        :param passw: the password (pin+otp)
        :type passw: string
        :param options:  additional arguments from the request, which could
                         be token specific
        :type options: dict
        :param challenges: A sorted list of valid challenges for this token.
        :type challenges: list
        :return: tuple of (otpcounter and the list of matching challenges)

        '''
        otp_counter = -1
        transid = None
        matching = None
        matching_challenges = []

        if 'transactionid' in options or 'state' in options:
            # fetch the transactionid
            transid = options.get('transactionid', None)
            if transid is None:
                transid = options.get('state', None)

        # check if the transactionid is in the list of challenges
        if transid is not None:
            for challenge in challenges:
                if Challenges.is_same_transaction(challenge, transid):
                    matching = challenge
                    break
            if matching is not None:
                otp_counter = check_otp(self, passw, options=options)
                if otp_counter >= 0:
                    matching_challenges.append(matching)

        return (otp_counter, matching_challenges)
Exemplo n.º 12
0
    def checkResponse4Challenge(self,
                                user,
                                passw,
                                options=None,
                                challenges=None):
        """
        This method verifies if the given ``passw`` matches any existing
        ``challenge`` of the token.

        It then returns the new otp_counter of the token and the
        list of the matching challenges.

        In case of success the otp_counter needs to be > 0.
        The matching_challenges is passed to the method
        :py:meth:`~linotp.tokens.base.TokenClass.challenge_janitor`
        to clean up challenges.

        :param user: the requesting user
        :type user: User object
        :param passw: the password (pin+otp)
        :type passw: string
        :param options:  additional arguments from the request, which could
                         be token specific
        :type options: dict
        :param challenges: A sorted list of valid challenges for this token.
        :type challenges: list
        :return: tuple of (otpcounter and the list of matching challenges)

        """
        if not challenges:
            return -1, []

        otp_counter = -1
        matching_challenges = []

        for challenge in challenges:
            _otp_counter = check_otp(self, passw, options=options)
            if _otp_counter >= 0:
                matching_challenges.append(challenge)

                # ensure that a positive otp_counter is preserved
                otp_counter = _otp_counter

        return (otp_counter, matching_challenges)
Exemplo n.º 13
0
    def checkResponse4Challenge(self,
                                user,
                                passw,
                                options=None,
                                challenges=None):
        '''
        verify the response of a previous challenge

        :param user:     the requesting user
        :param passw:    the to be checked pass (pin+otp)
        :param options:  options an additional argument, which could be token
                          specific
        :param challenges: the list of challenges, where each challenge is
                            described as dict
        :return: tuple of (otpcounter and the list of matching challenges)

        '''
        otp_counter = -1
        transid = None
        matching = None
        matching_challenges = []

        if 'transactionid' in options or 'state' in options:
            ## fetch the transactionid
            transid = options.get('transactionid', options.get('state', None))

        if not transid and self.authenticated is not None:
            pin_match, otp_counter, reply = self.authenticated
            return otp_counter, matching_challenges

        # check if the transactionid is in the list of challenges
        if transid is not None:
            for challenge in challenges:
                if Challenges.is_same_transaction(challenge, transid):
                    matching = challenge
                    break
            if matching is not None:
                otp_counter = check_otp(self, passw, options=options)
                if otp_counter >= 0:
                    matching_challenges.append(matching)

        return (otp_counter, matching_challenges)
Exemplo n.º 14
0
    def checkResponse4Challenge(self,
                                user,
                                passw,
                                options=None,
                                challenges=None):
        """
        verify the response of a previous challenge

        :param user:     the requesting user
        :param passw:    the to be checked pass (pin+otp)
        :param options:  options an additional argument, which could be token
                          specific
        :param challenges: the list of challenges, where each challenge is
                            described as dict
        :return: tuple of (otpcounter and the list of matching challenges)

        """

        # fetch the transactionid
        transid = options.get("transactionid", options.get("state", None))

        # in case of no transaction id, we do a direct authentication
        if not transid and self.authenticated is not None:
            _pin_match, otp_counter, _reply = self.authenticated
            return otp_counter, []

        if not challenges:
            return -1, []

        # otherwise we autheticate by the transaction id / challenges
        otp_counter = -1
        matching_challenges = []

        for challenge in challenges:
            _otp_counter = check_otp(self, passw, options=options)
            if _otp_counter >= 0:
                matching_challenges.append(challenge)

                # ensure that a positive otp_counter is preserved
                otp_counter = _otp_counter

        return otp_counter, matching_challenges