Example #1
0
    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)
Example #2
0
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)
Example #3
0
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)
Example #4
0
    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)
Example #5
0
    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)
Example #6
0
    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)