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