示例#1
0
    def test_ignore_pin(self, mocked_get_pin_policies):
        """
        test that on otppin policy 3 the pin is ignored
        """

        userObj = User(login="******", realm="mymixrealm")
        token = FakeToken()

        mocked_get_pin_policies.return_value = [3]

        res = check_pin(token, "QUATSCH", userObj, options={})
        assert res

        res = check_pin(token, "", userObj, options={})
        assert res

        token.type = "spass"
        res = check_pin(token, "bad", userObj, options={})
        assert not res

        token.type = "spass"
        res = check_pin(token, "good", userObj, options={})
        assert res

        return
示例#2
0
    def test_ignore_pin(self, mocked_get_pin_policies):
        """
        test that on otppin policy 3 the pin is ignored
        """

        userObj = User(login='******', realm='mymixrealm')
        token = FakeToken()

        mocked_get_pin_policies.return_value = [3]

        res = check_pin(token, 'QUATSCH', userObj, options={})
        self.assertTrue(res)

        res = check_pin(token, '', userObj, options={})
        self.assertTrue(res)

        token.type = 'spass'
        res = check_pin(token, 'bad', userObj, options={})
        self.assertFalse(res)

        token.type = 'spass'
        res = check_pin(token, 'good', userObj, options={})
        self.assertTrue(res)

        return
示例#3
0
    def test_ignore_pin(self, mocked_get_pin_policies):
        """
        test that on otppin policy 3 the pin is ignored
        """

        userObj = User(login='******', realm='mymixrealm')
        token = FakeToken()

        mocked_get_pin_policies.return_value = [3]

        res = check_pin(token, 'QUATSCH', userObj, options={})
        self.assertTrue(res)

        res = check_pin(token, '', userObj, options={})
        self.assertTrue(res)

        token.type = 'spass'
        res = check_pin(token, 'bad', userObj, options={})
        self.assertFalse(res)

        token.type = 'spass'
        res = check_pin(token, 'good', userObj, options={})
        self.assertTrue(res)

        return
示例#4
0
文件: __init__.py 项目: soitun/LinOTP
    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)
示例#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)
示例#6
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
示例#7
0
文件: __init__.py 项目: soitun/LinOTP
    def is_challenge_request(self, passw, user, options=None):
        """
        This method checks, if this is a request, that triggers a challenge.

        The default behaviour to trigger a challenge is,
        if the ``passw`` parameter only contains the correct token pin *and*
        the request contains a ``data`` or a ``challenge`` key i.e. if the
        ``options`` parameter contains a key ``data`` or ``challenge``.

        Each token type can decide on its own under which condition a challenge
        is triggered by overwriting this method.

        **please note**: in case of pin policy == 2 (no pin is required)
        the ``check_pin`` would always return true! Thus each request
        containing a ``data`` or ``challenge`` would trigger a challenge!

        :param passw: password, which might be pin or pin+otp
        :type passw: string
        :param user: The user from the authentication request
        :type user: User object
        :param options: dictionary of additional request parameters
        :type options: dict

        :return: true or false
        """

        request_is_valid = False

        pin_match = check_pin(self, passw, user=user, options=options)
        if pin_match is True:
            if "data" in options or "challenge" in options:
                request_is_valid = True

        return request_is_valid
示例#8
0
    def is_challenge_request(self, passw, user, options=None):
        '''
        check, if the request would start a challenge

        - default: if the passw contains only the pin, this request would
        trigger a challenge

        - in this place as well the policy for a token is checked

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

        :retrun: returns true or false
        '''

        request_is_valid = False
        # do we need to call the
        # (res, pin, otpval) = split_pin_otp(self, passw, user, options=options)
        realms = self.token.getRealmNames()
        if trigger_sms(realms):
            if 'check_s' in options.get('scope', {}) and 'challenge' in options:
                request_is_valid = True
                return request_is_valid

        # if its a challenge, the passw contains only the pin
        pin_match = check_pin(self, passw, user=user, options=options)
        if pin_match is True:
            request_is_valid = True

        return request_is_valid
示例#9
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)

        """

        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)
示例#10
0
    def is_challenge_request(self, passw, user, options=None):
        """
        check, if the request would start a challenge

        - default: if the passw contains only the pin, this request would
        trigger a challenge

        - in this place as well the policy for a token is checked

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

        :return: returns true or false
        """

        request_is_valid = False
        # do we need to call the
        # (res, pin, otpval) = split_pin_otp(self, passw, user, options=options)
        # if policy to send sms on emtpy pin is set, return true
        realms = self.token.getRealmNames()
        if trigger_sms(realms):
            if (
                "check_s" in options.get("scope", {})
                and "challenge" in options
            ):
                request_is_valid = True
                return request_is_valid

        # if its a challenge, the passw contains only the pin
        pin_match = check_pin(self, passw, user=user, options=options)
        if pin_match is True:
            request_is_valid = True

        return request_is_valid
示例#11
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
示例#12
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
示例#13
0
    def is_challenge_request(self, passw, user, options=None):
        '''
        This method checks, if this is a request, that triggers a challenge.

        The default behaviour to trigger a challenge is,
        if the ``passw`` parameter only contains the correct token pin *and*
        the request contains a ``data`` or a ``challenge`` key i.e. if the
        ``options`` parameter contains a key ``data`` or ``challenge``.

        Each token type can decide on its own under which condition a challenge
        is triggered by overwriting this method.

        **please note**: in case of pin policy == 2 (no pin is required)
        the ``check_pin`` would always return true! Thus each request
        containing a ``data`` or ``challenge`` would trigger a challenge!

        :param passw: password, which might be pin or pin+otp
        :type passw: string
        :param user: The user from the authentication request
        :type user: User object
        :param options: dictionary of additional request parameters
        :type options: dict

        :return: true or false
        '''

        request_is_valid = False

        pin_match = check_pin(self, passw, user=user, options=options)
        if pin_match is True:
            if "data" in options or "challenge" in options:
                request_is_valid = True

        return request_is_valid
示例#14
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)

        """

        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
示例#15
0
    def is_challenge_request(self, passw, user, options=None):
        """
        This method checks, if this is a request, that triggers a challenge.
        It depends on the way, the pin is checked - either locally or remote

        :param passw: password, which might be pin or pin+otp
        :type passw: string
        :param user: The user from the authentication request
        :type user: User object
        :param options: dictionary of additional request parameters
        :type options: dict

        :return: true or false
        """

        request_is_valid = False

        if self.check_pin_local():
            pin_match = check_pin(self, passw, user=user, options=options)
            if pin_match is True:
                request_is_valid = True

        elif self.isRemoteChallengeRequest:
            request_is_valid = True

        return request_is_valid
示例#16
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)
示例#17
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
示例#18
0
    def is_challenge_request(self, passw, user, options=None):
        """
        This method checks, if this is a request, that triggers a challenge.
        It depends on the way, the pin is checked - either locally or remote

        :param passw: password, which might be pin or pin+otp
        :type passw: string
        :param user: The user from the authentication request
        :type user: User object
        :param options: dictionary of additional request parameters
        :type options: dict

        :return: true or false
        """

        request_is_valid = False

        if self.check_pin_local():
            pin_match = check_pin(self, passw, user=user, options=options)
            if pin_match is True:
                request_is_valid = True

        elif self.isRemoteChallengeRequest:
            request_is_valid = True

        return request_is_valid
示例#19
0
文件: u2ftoken.py 项目: soitun/LinOTP
    def update(self, param, reset_failcount=False):
        self.setSyncWindow(0)
        self.setOtpLen(32)
        self.setCounterWindow(0)

        tdesc = param.get("description")
        if tdesc is not None:
            self.token.setDescription(tdesc)

        # requested_phase must be either "registration1" or "registration2"
        # current_phase is either "registration" or "authentication"
        requested_phase = param.get("phase")
        current_phase = self.getFromTokenInfo("phase", None)

        if requested_phase == "registration1" and current_phase is None:
            # This initial registration phase triggers a challenge
            # which is sent to the FIDO U2F compatible client device

            # Set the optional token pin in this first phase
            pin = param.get("pin")
            if pin is not None:
                TokenClass.setPin(self, pin)

            # preserve the registration state
            self.addToTokenInfo("phase", "registration")
            self.token.LinOtpIsactive = False
        elif (
            requested_phase == "registration2"
            and current_phase == "registration"
        ):
            # Check the token pin
            pin = param.get("pin")
            if pin is None:
                pin = ""
            if check_pin(self, pin) is False:
                raise ValueError("Wrong token pin!")
        # check for set phases which are not "registration1" or "registration2"
        elif (
            requested_phase != "registration2" and requested_phase is not None
        ):
            raise Exception("Wrong phase parameter!")
        # only allow empty phase parameters once the token is registered
        # successfully
        elif current_phase != "authentication" and requested_phase is None:
            raise Exception("Wrong phase parameter!")
        # only allow "registration2" if the token already completed
        # "registration1"
        elif (
            current_phase != "registration"
            and requested_phase == "registration2"
        ):
            raise Exception(
                "Phase 'registration2' requested but we are not in the correct phase \
                to process the request."
            )
        else:
            raise Exception(
                'Unknown "phase" and "current_phase" parameter combination!'
            )
示例#20
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
        """

        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 is True:
                otp_val = otp

        if otp_val and not challenges:
            otp_count = self.checkOtp(
                otp_val, counter, window, options=options
            )
            return otp_count, []

        otp_count = -1
        matching = []

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

                # ensure that a positive otp_counter is preserved
                otp_count = _otp_count

        return (otp_count, matching)
示例#21
0
文件: u2ftoken.py 项目: smshen/LinOTP
    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)
示例#22
0
 def authenticate(self, passw, user, options=None):
     """
     in case of a wrong passw, we return a bad matching pin,
     so the result will be an invalid token
     """
     otp_count = -1
     pin_match = check_pin(self, passw, user=user, options=options)
     if pin_match == True:
         otp_count = 0
     return (pin_match, otp_count, None)
示例#23
0
 def authenticate(self, passw, user, options=None):
     '''
     in case of a wrong passw, we return a bad matching pin,
     so the result will be an invalid token
     '''
     otp_count = -1
     pin_match = check_pin(self, passw, user=user, options=options)
     if pin_match == True:
         otp_count = 0
         self.auth_info = {'auth_info': [('pin_length', len(passw))]}
     return (pin_match, otp_count, None)
示例#24
0
 def authenticate(self, passw, user, options=None):
     '''
     in case of a wrong passw, we return a bad matching pin,
     so the result will be an invalid token
     '''
     otp_count = -1
     pin_match = check_pin(self, passw, user=user, options=options)
     if pin_match is True:
         otp_count = 0
         self.auth_info = {'auth_info': [('pin_length', len(passw))]}
     return (pin_match, otp_count, None)
示例#25
0
文件: u2ftoken.py 项目: gsnbng/LinOTP
    def update(self, param, reset_failcount=False):
        self.setSyncWindow(0)
        self.setOtpLen(32)
        self.setCounterWindow(0)

        tdesc = getParam(param, "description", optional)
        if tdesc is not None:
            self.token.setDescription(tdesc)

        # requested_phase must be either "registration1" or "registration2"
        # current_phase is either "registration" or "authentication"
        requested_phase = getParam(param, "phase", optional)
        current_phase = self.getFromTokenInfo('phase', None)

        if requested_phase == "registration1" and current_phase is None:
            # This initial registration phase triggers a challenge
            # which is sent to the FIDO U2F compatible client device

            # Set the optional token pin in this first phase
            pin = getParam(param, "pin", optional)
            if pin is not None:
                TokenClass.setPin(self, pin)

            # preserve the registration state
            self.addToTokenInfo('phase', 'registration')
            self.token.LinOtpIsactive = False
        elif requested_phase == "registration2" and current_phase == "registration":
            # Check the token pin
            pin = getParam(param, "pin", optional)
            if pin is None:
                pin = ''
            if check_pin(self, pin) is False:
                log.error("Wrong token pin!")
                raise ValueError("Wrong token pin!")
        # check for set phases which are not "registration1" or "registration2"
        elif requested_phase != "registration2" and requested_phase is not None:
            log.error('Wrong phase parameter!')
            raise Exception('Wrong phase parameter!')
        # only allow empty phase parameters once the token is registered successfully
        elif current_phase != "authentication" and requested_phase is None:
            log.error('Wrong phase parameter!')
            raise Exception('Wrong phase parameter!')
        # only allow "registration2" if the token already completed "registration1"
        elif current_phase != "registration" and requested_phase == "registration2":
            log.error(
                "Phase 'registration2' requested but we are not in the correct phase \
                to process the request.")
            raise Exception(
                "Phase 'registration2' requested but we are not in the correct phase \
                to process the request.")
        else:
            log.error('Unknown "phase" and "current_phase" parameter combination!')
            raise Exception('Unknown "phase" and "current_phase" parameter combination!')
示例#26
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)
示例#27
0
文件: u2ftoken.py 项目: soitun/LinOTP
    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
示例#28
0
    def is_challenge_request(self, passw, user, options=None):
        """
        check if the request would start a challenge

        - default: if the passw contains only the pin, this request would
        trigger a challenge

        - in this place as well the policy for a token is checked

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

        :return: returns true or false
        """
        return check_pin(self, passw, user=user, options=options)
示例#29
0
文件: u2ftoken.py 项目: smshen/LinOTP
    def is_challenge_request(self, passw, user, options=None):
        """
        check if the request would start a challenge

        - default: if the passw contains only the pin, this request would
        trigger a challenge

        - in this place as well the policy for a token is checked

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

        :return: returns true or false
        """
        return check_pin(self, passw, user=user, options=options)
示例#30
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)
示例#31
0
    def is_challenge_request(self, passw, user, options=None):
        """
        This method checks, if this is a request, that triggers a challenge.
        The pin is checked locally only

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

        :return: true or false
        """

        request_is_valid = False

        pin_match = check_pin(self, passw, user=user, options=options)
        if pin_match is True:
            request_is_valid = True

        return request_is_valid
示例#32
0
    def is_challenge_request(self, passw, user, options=None):
        """
        This method checks, if this is a request, that triggers a challenge.
        The pin is checked locally only

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

        :return: true or false
        """

        request_is_valid = False

        pin_match = check_pin(self, passw, user=user, options=options)
        if pin_match is True:
            request_is_valid = True

        return request_is_valid
示例#33
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
示例#34
0
    def is_challenge_request(self, passw, user, options=None):
        '''
        This method checks, if this is a request, that triggers a challenge.

        :param passw: password, which might be pin or pin+otp
        :type passw: string
        :param user: The user from the authentication request
        :type user: User object
        :param options: dictionary of additional request parameters
        :type options: dict

        :return: true or false
        '''

        request_is_valid = False

        pin_match = check_pin(self, passw, user=user, options=options)
        if pin_match is True:
            request_is_valid = True

        return request_is_valid
示例#35
0
    def is_challenge_request(self, passw, user, options=None):
        '''
        This method checks, if this is a request, that triggers a challenge.

        :param passw: password, which might be pin or pin+otp
        :type passw: string
        :param user: The user from the authentication request
        :type user: User object
        :param options: dictionary of additional request parameters
        :type options: dict

        :return: true or false
        '''

        request_is_valid = False

        pin_match = check_pin(self, passw, user=user, options=options)
        if pin_match is True:
            request_is_valid = True

        return request_is_valid
示例#36
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
示例#37
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, 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()

        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