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