def create_challenge(token, options=None, challenge_id=None, id_postfix=''): """ dedicated method to create a challenge to support the implementation of challenge policies in future :param options: optional parameters for token specific tokens eg. request a signed challenge :return: a tuple of (boolean, and a dict, which contains the {'challenge' : challenge} description) """ # response dict, describing the challenge reply challenge = {} # the allocated db challenge object challenge_obj = None retry_counter = 0 reason = None hsm = context['hsm'].get('obj') id_length = int( context.get('Config', None).get('TransactionIdLength', 12)) - \ len(id_postfix) while True: try: if not challenge_id: transactionid = "%s%s" % ( Challenge.createTransactionId(length=id_length), id_postfix) else: transactionid = challenge_id num_challenges = Session.query(Challenge). \ filter(Challenge.transid == transactionid).count() if num_challenges == 0: challenge_obj = Challenge(transid=transactionid, tokenserial=token.getSerial()) if challenge_obj is not None: break except Exception as exce: log.info("Failed to create Challenge: %r", exce) reason = exce # prevent an unlimited loop retry_counter = retry_counter + 1 if retry_counter > 100: log.info( "Failed to create Challenge for %d times: %r -quiting!", retry_counter, reason) raise Exception('Failed to create challenge %r' % reason) expired_challenges, valid_challenges = Challenges.get_challenges(token) # carefully create a new challenge try: # we got a challenge object allocated and initialize the challenge (res, open_transactionid, message, attributes) = \ token.initChallenge(transactionid, challenges=valid_challenges, options=options) if res is False: # if a different transid is returned, this indicates, that there # is already an outstanding challenge we can refere to if open_transactionid != transactionid: transactionid = open_transactionid else: # in case the init was successfull, we preserve no the # challenge data to support the implementation of a blocking # based on the previous stored data challenge_obj.setChallenge(message) challenge_obj.save() (res, message, data, attributes) = \ token.createChallenge(transactionid, options=options) if res is True: # persist the final challenge data + message challenge_obj.setChallenge(message) challenge_obj.setData(data) challenge_obj.signChallenge(hsm) challenge_obj.save() else: transactionid = '' reason = Exception(message) except Exception as exce: reason = exce res = False # if something goes wrong with the challenge, remove it if res is False and challenge_obj is not None: try: log.debug("deleting session") Session.delete(challenge_obj) Session.commit() except Exception as exx: log.debug("deleting session failed: %r" % exx) try: Session.expunge(challenge_obj) Session.commit() except Exception as exx: log.debug("expunge session failed: %r" % exx) # in case that create challenge fails, we must raise this reason if reason is not None: message = "%r" % reason log.error("Failed to create or init challenge %r " % reason) raise reason # prepare the response for the user if transactionid is not None: challenge['transactionid'] = transactionid if message is not None: challenge['message'] = message if attributes is not None and type(attributes) == dict: challenge.update(attributes) return (res, challenge)
def create_challenge(token, options=None): """ dedicated method to create a challenge to support the implementation of challenge policies in future :param options: optional parameters for token specific tokens eg. request a signed challenge :return: a tuple of (boolean, and a dict, which contains the {'challenge' : challenge} description) """ ## response dict, describing the challenge reply challenge = {} ## the allocated db challenge object challenge_obj = None retry_counter = 0 reason = None id_length = int(getFromConfig('TransactionIdLength', 12)) while True: try: transactionid = Challenge.createTransactionId(length=id_length) num_challenges = Session.query(Challenge).\ filter(Challenge.transid == transactionid).count() if num_challenges == 0: challenge_obj = Challenge(transid=transactionid, tokenserial=token.getSerial()) if challenge_obj is not None: break except Exception as exce: LOG.info("Failed to create Challenge: %r", exce) reason = exce ## prevent an unlimited loop retry_counter = retry_counter + 1 if retry_counter > 100: LOG.info("Failed to create Challenge for %d times: %r -quiting!", retry_counter, reason) raise Exception('Failed to create challenge %r' % reason) challenges = get_challenges(serial=token.getSerial()) ## carefully create a new challenge try: ## we got a challenge object allocated and initialize the challenge (res, open_transactionid, message, attributes) = \ token.initChallenge(transactionid, challenges=challenges, options=options) if res == False: ## if a different transid is returned, this indicates, that there ## is already an outstanding challenge we can refere to if open_transactionid != transactionid: transactionid = open_transactionid else: ## in case the init was successfull, we preserve no the challenge data ## to support the implementation of a blocking based on the previous ## stored data challenge_obj.setChallenge(message) challenge_obj.save() (res, message, data, attributes) = \ token.createChallenge(transactionid, options=options) if res == True: ## persist the final challenge data + message challenge_obj.setChallenge(message) challenge_obj.setData(data) challenge_obj.save() else: transactionid = '' except Exception as exce: reason = exce res = False ## if something goes wrong with the challenge, remove it if res == False and challenge_obj is not None: try: LOG.debug("deleting session") Session.delete(challenge_obj) Session.commit() except Exception as exx: LOG.debug("deleting session failed: %r" % exx) try: Session.expunge(challenge_obj) Session.commit() except Exception as exx: LOG.debug("expunge session failed: %r" % exx) ## in case that create challenge fails, we must raise this reason if reason is not None: message = "%r" % reason LOG.error("Failed to create or init challenge %r " % reason) raise reason ## prepare the response for the user if transactionid is not None: challenge['transactionid'] = transactionid if message is not None: challenge['message'] = message if attributes is not None and type(attributes) == dict: challenge.update(attributes) return (res, challenge)
def create_challenge(token, options=None): """ dedicated method to create a challenge to support the implementation of challenge policies in future :param options: optional parameters for token specific tokens eg. request a signed challenge :return: a tuple of (boolean, and a dict, which contains the {'challenge' : challenge} description) """ ## response dict, describing the challenge reply challenge = {} ## the allocated db challenge object challenge_obj = None retry_counter = 0 reason = None id_length = int(getFromConfig("TransactionIdLength", 12)) while True: try: transactionid = Challenge.createTransactionId(length=id_length) num_challenges = Session.query(Challenge).filter(Challenge.transid == transactionid).count() if num_challenges == 0: challenge_obj = Challenge(transid=transactionid, tokenserial=token.getSerial()) if challenge_obj is not None: break except Exception as exce: LOG.info("Failed to create Challenge: %r", exce) reason = exce ## prevent an unlimited loop retry_counter = retry_counter + 1 if retry_counter > 100: LOG.info("Failed to create Challenge for %d times: %r -quiting!", retry_counter, reason) raise Exception("Failed to create challenge %r" % reason) challenges = get_challenges(serial=token.getSerial()) ## carefully create a new challenge try: ## we got a challenge object allocated and initialize the challenge (res, open_transactionid, message, attributes) = token.initChallenge( transactionid, challenges=challenges, options=options ) if res == False: ## if a different transid is returned, this indicates, that there ## is already an outstanding challenge we can refere to if open_transactionid != transactionid: transactionid = open_transactionid else: ## in case the init was successfull, we preserve no the challenge data ## to support the implementation of a blocking based on the previous ## stored data challenge_obj.setChallenge(message) challenge_obj.save() (res, message, data, attributes) = token.createChallenge(transactionid, options=options) if res == True: ## persist the final challenge data + message challenge_obj.setChallenge(message) challenge_obj.setData(data) challenge_obj.save() else: transactionid = "" except Exception as exce: reason = exce res = False ## if something goes wrong with the challenge, remove it if res == False and challenge_obj is not None: try: LOG.debug("deleting session") Session.delete(challenge_obj) Session.commit() except Exception as exx: LOG.debug("deleting session failed: %r" % exx) try: Session.expunge(challenge_obj) Session.commit() except Exception as exx: LOG.debug("expunge session failed: %r" % exx) ## in case that create challenge fails, we must raise this reason if reason is not None: message = "%r" % reason LOG.error("Failed to create or init challenge %r " % reason) raise reason ## prepare the response for the user if transactionid is not None: challenge["transactionid"] = transactionid if message is not None: challenge["message"] = message if attributes is not None and type(attributes) == dict: challenge.update(attributes) return (res, challenge)
def create_challenge(token, options=None, challenge_id=None, id_postfix=''): """ dedicated method to create a challenge to support the implementation of challenge policies in future :param options: optional parameters for token specific tokens eg. request a signed challenge :return: a tuple of (boolean, and a dict, which contains the {'challenge' : challenge} description) """ # response dict, describing the challenge reply challenge = {} # the allocated db challenge object challenge_obj = None retry_counter = 0 reason = None ReasonException = Exception() hsm = context['hsm'].get('obj') transid_len = Challenges.get_tranactionid_length() id_length = transid_len - len(id_postfix) while True: try: if not challenge_id: transactionid = "%s%s" % (Challenge.createTransactionId( length=id_length), id_postfix) else: transactionid = challenge_id num_challenges = Challenge.query.filter_by( transid=transactionid).count() if num_challenges == 0: challenge_obj = Challenge(transid=transactionid, tokenserial=token.getSerial()) if challenge_obj is not None: break except Exception as exce: log.exception("Failed to create challenge: %r", exce) reason = "%r" % exce ReasonException = exce # prevent an unlimited loop retry_counter = retry_counter + 1 if retry_counter > 100: log.error( "Failed to create challenge for %d times: %r - quiting!", retry_counter, reason) raise Exception('Failed to create challenge %r' % reason) expired_challenges, valid_challenges = Challenges.get_challenges(token) # carefully create a new challenge try: # we got a challenge object allocated and initialize the challenge (res, open_transactionid, message, attributes) = \ token.initChallenge(transactionid, challenges=valid_challenges, options=options) if res is False: # if a different transid is returned, this indicates, that there # is already an outstanding challenge we can refere to if open_transactionid != transactionid: transactionid = open_transactionid else: # in case the init was successful, we preserve no the # challenge data to support the implementation of a blocking # based on the previous stored data challenge_obj.setChallenge(message) challenge_obj.save() (res, message, data, attributes) = \ token.createChallenge(transactionid, options=options) if res is True: # persist the final challenge data + message challenge_obj.setChallenge(message) challenge_obj.setData(data) challenge_obj.signChallenge(hsm) challenge_obj.save() else: transactionid = '' reason = message ReasonException = Exception(message) except Exception as exce: log.exception("Failed to create challenge: %r", exce) reason = "%r" % exce ReasonException = exce res = False # if something goes wrong with the challenge, remove it if res is False and challenge_obj is not None: try: log.debug("Deleting challenge from database session, because " "of earlier error") db.session.delete(challenge_obj) db.session.commit() except Exception as exx: log.debug( "Deleting challenge from database session failed. " "Retrying with expunge. Exception was: %r", exx) try: db.session.expunge(challenge_obj) db.session.commit() except Exception as exx: log.debug( "Expunging challenge from database session " "failed. Exception was: %r", exx) # in case that create challenge fails, we must raise this reason if reason is not None: log.error("Failed to create or init challenge. Reason was %r ", reason) raise ReasonException # prepare the response for the user if transactionid is not None: challenge['transactionid'] = transactionid if message is not None: challenge['message'] = message if attributes is not None and type(attributes) == dict: challenge.update(attributes) # # add token specific info like tokentype and serial # challenge["linotp_tokenserial"] = token.getSerial() challenge["linotp_tokentype"] = token.type return (res, challenge)
def challenge(self, data, session='', typ='raw', challenge=None): ''' the challenge method is for creating an transaction / challenge object remark: the transaction has a maximum lifetime and a reference to the OcraSuite token (serial) :param data: data, which is the base for the challenge or None :type data: string or None :param session: session support for ocratokens :type session: string :type typ: define, which kind of challenge base should be used could be raw - take the data input as is (extract chars accordind challenge definition Q) or random - will generate a random input or hased - will take the hash of the input data :return: challenge response containing the transcation id and the challenge for the ocrasuite :rtype : tuple of (transId(string), challenge(string)) ''' s_data = 'None' s_session = 'None' s_challenge = 'None' if data is not None: s_data = data if session is not None: s_session = session if challenge is None: s_challenge = challenge secObj = self._get_secret_object() ocraSuite = OcraSuite(self.getOcraSuiteSuite(), secObj) if not data: typ = 'random' if challenge is None: if typ == 'raw': challenge = ocraSuite.data2rawChallenge(data) elif typ == 'random': challenge = ocraSuite.data2randomChallenge(data) elif typ == 'hash': challenge = ocraSuite.data2hashChallenge(data) serial = self.getSerial() counter = self.getOtpCount() # set the pin onyl in the compliant hashed mode pin = '' if ocraSuite.P is not None: key, iv = self.token.getUserPin() secObj = SecretObj(key, iv, hsm=context.get('hsm')) pin = secObj.getKey() try: param = {} param['C'] = counter param['Q'] = challenge param['P'] = pin param['S'] = session if ocraSuite.T is not None: now = datetime.datetime.now() stime = now.strftime("%s") itime = int(stime) param['T'] = itime ''' verify that the data is compliant with the OcraSuitesuite and the client is able to calc the otp ''' c_data = ocraSuite.combineData(**param) ocraSuite.compute(c_data) except Exception as ex: log.exception( "[OcraTokenClass] Failed to create ocrasuite challenge") raise Exception('[OcraTokenClass] Failed to create ocrasuite' 'challenge: %r' % (ex)) # save the object digits = '0123456789' transid = '' transactionIdLen = 12 try: transactionIdLen = int(getFromConfig("OcraDefaultSuite", '12')) except: transactionIdLen = 12 log.debug("[OcraTokenClass] Failed to set transactionId length" " from config - using fallback %d" % (transactionIdLen)) # create a non exisiting challenge try: while True: for _c in range(0, transactionIdLen): transid += urandom.choice(digits) chall = OcraTokenClass.getTransaction(transid) if chall is None: break ddata = '' if data is not None: ddata = data chall = OcraChallenge(transid=transid, tokenserial=serial, challenge=typ + ':' + challenge, data=typ + ':' + ddata) chall.save() except Exception as ex: # this might happen if we have a db problem or # the uniqnes constrain does not fit log.exception("[OcraTokenClass] Failed to create challenge") raise Exception('[OcraTokenClass] Failed to create challenge' ' object: %s' % (ex)) realms = [] tokenrealms = self.token.getRealms() for realm in tokenrealms: realms.append(realm.name) url = get_qrtan_url(realms) return (transid, challenge, True, url)
def challenge(self, data, session='', typ='raw', challenge=None): ''' the challenge method is for creating an transaction / challenge object remark: the transaction has a maximum lifetime and a reference to the OcraSuite token (serial) :param data: data, which is the base for the challenge or None :type data: string or None :param session: session support for ocratokens :type session: string :type typ: define, which kind of challenge base should be used could be raw - take the data input as is (extract chars accordind challenge definition Q) or random - will generate a random input or hased - will take the hash of the input data :return: challenge response containing the transcation id and the challenge for the ocrasuite :rtype : tuple of (transId(string), challenge(string)) ''' s_data = 'None' s_session = 'None' s_challenge = 'None' if data is not None: s_data = data if session is not None: s_session = session if challenge is None: s_challenge = challenge secObj = self._get_secret_object() ocraSuite = OcraSuite(self.getOcraSuiteSuite(), secObj) if not data: typ = 'random' if challenge is None: if typ == 'raw': challenge = ocraSuite.data2rawChallenge(data) elif typ == 'random': challenge = ocraSuite.data2randomChallenge(data) elif typ == 'hash': challenge = ocraSuite.data2hashChallenge(data) serial = self.getSerial() counter = self.getOtpCount() # set the pin onyl in the compliant hashed mode pin = '' if ocraSuite.P is not None: key, iv = self.token.getUserPin() secObj = SecretObj(key, iv, hsm=context.get('hsm')) pin = secObj.getKey() try: param = {} param['C'] = counter param['Q'] = challenge param['P'] = pin param['S'] = session if ocraSuite.T is not None: now = datetime.datetime.now() stime = now.strftime("%s") itime = int(stime) param['T'] = itime ''' verify that the data is compliant with the OcraSuitesuite and the client is able to calc the otp ''' c_data = ocraSuite.combineData(**param) ocraSuite.compute(c_data) except Exception as ex: log.exception("[OcraTokenClass] Failed to create ocrasuite challenge") raise Exception('[OcraTokenClass] Failed to create ocrasuite' 'challenge: %r' % (ex)) # save the object digits = '0123456789' transid = '' transactionIdLen = 12 try: transactionIdLen = int(getFromConfig("OcraDefaultSuite", '12')) except: transactionIdLen = 12 log.debug("[OcraTokenClass] Failed to set transactionId length" " from config - using fallback %d" % (transactionIdLen)) # create a non exisiting challenge try: while True: for _c in range(0, transactionIdLen): transid += urandom.choice(digits) chall = OcraTokenClass.getTransaction(transid) if chall is None: break ddata = '' if data is not None: ddata = data chall = OcraChallenge(transid=transid, tokenserial=serial, challenge=typ + ':' + challenge, data=typ + ':' + ddata) chall.save() except Exception as ex: # this might happen if we have a db problem or # the uniqnes constrain does not fit log.exception("[OcraTokenClass] Failed to create challenge") raise Exception('[OcraTokenClass] Failed to create challenge' ' object: %s' % (ex)) realms = [] tokenrealms = self.token.getRealms() for realm in tokenrealms: realms.append(realm.name) url = get_qrtan_url(realms) return (transid, challenge, True, url)