Ejemplo n.º 1
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
Ejemplo n.º 2
0
    def authenticate(self, passw, user, options=None):
        """
        do the authentication on base of password / otp and user and
        options, the request parameters.

        Here we contact the other LinOTP server to validate the OtpVal.

        :param passw: the password / otp
        :param user: the requesting user
        :param options: the additional request parameters

        :return: tupple of (success, otp_count - 0 or -1, reply)

        """
        log.debug("authenticate")

        res = False
        otp_counter = -1
        reply = None

        otpval = passw

        # should we check the pin localy??
        if self.check_pin_local():
            (res, pin, otpval) = split_pin_otp(self, passw, user,
                                               options=options)

            res = check_pin(self, pin, user=user, options=options)
            if res is False:
                return (res, otp_counter, reply)

        (res, otp_count, reply) = self.do_request(otpval, user=user)

        return (res, otp_count, reply)
Ejemplo 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
        :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
        # during the verification that

        (policy_type, pin, otp_val) = split_pin_otp(self,
                                                    passw,
                                                    user=user,
                                                    options=options)

        if policy_type >= 0 and len(otp_val) == self.getOtpLen():
            return check_pin(self, pin, user=user, options=options)

        return False
Ejemplo n.º 4
0
    def authenticate(self, passw, user, options=None):
        """
        do the authentication on base of password / otp and serial and
        options, the request parameters.

        :param passw: the password / otp
        :param user: the requesting user
        :param options: the additional request parameters

        :return: tupple of (success, otp_count - 0 or -1, reply)

        """
        log.debug("authenticate")

        otp_count = -1
        reply = None

        # we do a local pin check
        _res, pin, otpval = split_pin_otp(self, passw, user, options=options)

        res = check_pin(self, pin, user, options)
        if res is False:
            return res, otp_count, reply

        res, otp_count, reply = self.do_request(otpval, user=user)
        return res, otp_count, reply
Ejemplo n.º 5
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)
Ejemplo n.º 6
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)

        do the standard check for the response of the challenge +
        change the tokeninfo data of the last challenge
        """
        otp_count = -1
        matching = []

        tok = super(SmsTokenClass, self)
        counter = self.getOtpCount()
        window = self.getOtpCountWindow()

        now = datetime.datetime.now()
        timeScope = self.loadLinOtpSMSValidTime()

        otp_val = passw

        # # fallback: do we have pin+otp ??
        (res, pin, otp) = split_pin_otp(self, passw, user=user,
                                                            options=options)

        if res >= 0:
            res = check_pin(self, pin, user=user, options=options)
            if res == True:
                otp_val = otp

        for challenge in challenges:
            otp_count = self.checkOtp(otp_val, counter, window,
                                                            options=options)
            if otp_count > 0:
                matching.append(challenge)
                break

        return (otp_count, matching)
Ejemplo n.º 7
0
    def checkResponse4Challenge(self, user, passw, options=None, challenges=None):
        """
        verify the response of a previous challenge

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

        do the standard check for the response of the challenge +
        change the tokeninfo data of the last challenge
        """
        otp_count = -1
        matching = []

        # in var passw might be only the otp, otherwise otp_val will be
        # overwritten later.
        otp_val = passw

        # # fallback: do we have pin+otp ??
        (active_pin_policy, pin, otp) = split_pin_otp(self, passw, user=user,
                                                      options=options)

        if active_pin_policy >= 0:
            res = check_pin(self, pin, user=user, options=options)
            if res is True:
                otp_val = otp

        for challenge in challenges:
            counter_from_challenge = challenge.get('data').get('counter')
            otp_count = self.check_otp(otp_value=otp_val,
                                       counter=int(counter_from_challenge))
            if otp_count > 0:
                matching.append(challenge)
                break

        return otp_count, matching
Ejemplo n.º 8
0
    def checkResponse4Challenge(self, user, passw, options=None,
                                challenges=None):
        """
        verify the response of a previous challenge

        There are two possible cases:

        1) The 'transaction_id' (also know as 'state', which has the same
           value) is available in options
        2) No 'transaction_id'

        In the first case we can safely assume that the passw only contains
        the OTP (no pin). In the second case passw will contain both and we
        split to get the OTP.

        :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)

        """
        transaction_id = None
        otp_counter = -1
        matching_challenges = []

        if challenges is None or len(challenges) == 0:
            # There are no challenges for this token
            return -1, []

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

        if transaction_id:
            otp = passw
            # if the transaction_id is set we can assume that we have only
            # received a single challenge with that transaction_id thanks to
            # linotp.lib.validate.ValidateToken.get_challenges()
            assert(len(challenges) == 1)
            assert(Challenges.is_same_transaction(challenges[0], transaction_id))
        else:
            # If no transaction_id is set the request came through the WebUI
            # and we have to check all challenges
            split_status, _, otp = split_pin_otp(self, passw, user, options)
            if split_status < 0:
                raise Exception("Could not split passw")

        window = self.getOtpCountWindow()

        for challenge in challenges:
            challenge_data = challenge.getData()
            stored_counter = challenge_data.get("counter_value")
            temp_otp_counter = self.checkOtp(otp, int(stored_counter),
                                             window, options)
            if temp_otp_counter > 0:
                otp_counter = temp_otp_counter
                matching_challenges = [challenge]
                break

        # The matching_challenges list will either contain a single challenge
        # or will be empty. Returning multiple challenges is not useful in this
        # case because all older challenges arecleaned up anyway.
        return otp_counter, matching_challenges
Ejemplo n.º 9
0
    def checkResponse4Challenge(self,
                                user,
                                passw,
                                options=None,
                                challenges=None):
        """
        verify the response of a previous challenge

        There are two possible cases:

        1) The 'transaction_id' (also know as 'state', which has the same
           value) is available in options
        2) No 'transaction_id'

        In the first case we can safely assume that the passw only contains
        the OTP (no pin). In the second case passw will contain both and we
        split to get the OTP.

        :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)

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

        transaction_id = options and options.get("transactionid",
                                                 options.get("state", None))

        if transaction_id:
            otp = passw
            # if the transaction_id is set we can assume that we have only
            # received a single challenge with that transaction_id thanks to
            # linotp.lib.validate.ValidateToken.get_challenges()
            assert len(challenges) == 1
        else:
            # If no transaction_id is set the request came through the WebUI
            # and we have to check all challenges
            split_status, pin, otp = split_pin_otp(self, passw, user, options)
            if split_status < 0:
                raise Exception("Could not split passw")
            if not check_pin(self, pin, user, options):
                return -1, []

        window = self.getOtpCountWindow()

        otp_counter = -1
        matching_challenges = []

        for challenge in challenges:
            challenge_data = challenge.getData()
            stored_counter = int(challenge_data.get("counter_value", -1))
            _otp_counter = self.checkOtp(otp, stored_counter, window, options)

            if _otp_counter > 0 and _otp_counter == stored_counter:
                matching_challenges.append(challenge)

                # ensure that a positive otp_counter is preserved
                otp_counter = _otp_counter

        return otp_counter, matching_challenges