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
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 ''' challenge_response = False if "state" in options or "transactionid" in options: challenge_response = True # # it as well might be a challenge response, # # if the passw is longer than the pin if challenge_response == False: (res, pin, otpval) = split_pin_otp(self, passw, user=user, options=options) if res >= 0: res = check_pin(self, pin, user=user, options=options) if res == True and len(otpval) > 0: challenge_response = True return challenge_response
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 ''' challenge_response = False if "state" in options or "transactionid" in options: challenge_response = True ## it as well might be a challenge response, ## if the passw is longer than the pin if challenge_response == False: (res, pin, otpval) = split_pin_otp(self, passw, user=user, options=options) if res >= 0 : res = check_pin(self, pin, user=user, options=options) if res == True and len(otpval) > 0: challenge_response = True return challenge_response
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_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 pin_match = check_pin(self, passw, user=user, options=options) if pin_match is True: request_is_valid = True return request_is_valid
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, context=self.context): if 'check_s' in options.get('scope', {}) and 'challenge' in options: request_is_valid = True return request_is_valid pin_match = check_pin(self, passw, user=user, options=options) if pin_match is True: request_is_valid = True return request_is_valid
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.lib.tokenclass.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 is_same_transaction(challenge, transid): matching = challenge break if matching is not None: # Split pin from otp and check the resulting pin and otpval (res, 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 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)
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!')
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!')
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 """ log.debug("[checkResponse4Challenge] entering function") 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, pin=pin) if otp_count > 0: matching.append(challenge) break return (otp_count, matching)
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)
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
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) pin_match = check_pin(self, passw, user=user, options=options) if pin_match is True: request_is_valid = True return request_is_valid