Exemplo n.º 1
0
    def checkOtp(self, passw , counter, window, options=None):
        '''
        checkOtp - standard callback of linotp to verify the token

        :param passw:      the passw / otp, which has to be checked
        :type passw:       string
        :param counter:    the start counter
        :type counter:     int
        :param  window:    the window, in which the token is valid
        :type  window:     int
        :param options:    options contains the transaction id,
                            eg. if check_t checks one transaction
                            this will support assynchreonous otp checks
                            (when check_t is used)
        :type options:     dict

        :return:           verification counter or -1
        :rtype:            int (-1)

        '''
        log.debug('[checkOtp] %r: %r: %r' % (passw, counter, window))
        ret = -1

        challenges = []
        serial = self.getSerial()

        if options is None:
            options = {}

        maxRequests = int(getFromConfig("Ocra2MaxChallengeRequests", '3'))

        if 'transactionid' in options:
            transid = options.get('transactionid', None)
            challs = get_challenges(serial=serial, transid=transid)
            for chall in challs:
                (rec_tan, rec_valid) = chall.getTanStatus()
                if rec_tan == False:
                    challenges.append(chall)
                elif rec_valid == False:
                    ## add all touched but failed challenges
                    if chall.getTanCount() <= maxRequests:
                        challenges.append(chall)

        if 'challenge' in options:
            ## direct challenge - there might be addtionalget info like
            ## session data in the options
            challenges.append(options)

        if len(challenges) == 0:
            challs = get_challenges(serial=serial)
            for chall in challs:
                (rec_tan, rec_valid) = chall.getTanStatus()
                if rec_tan == False:
                    ## add all untouched challenges
                    challenges.append(chall)
                elif rec_valid == False:
                    ## add all touched but failed challenges
                    if chall.getTanCount() <= maxRequests:
                        challenges.append(chall)

        if len(challenges) == 0:
            err = 'No open transaction found for token %s' % serial
            log.error(err)  ##TODO should log and fail!!
            raise Exception(err)

        ## prepare the challenge check - do the ocra setup
        secretHOtp = self.token.getHOtpKey()
        ocraSuite = OcraSuite(self.getOcraSuiteSuite(), secretHOtp)

        ## set the ocra token pin
        ocraPin = ''
        if ocraSuite.P is not None:
            ocraPinObj = self.token.getUserPin()
            ocraPin = ocraPinObj.getKey()

            if ocraPin is None or len(ocraPin) == 0:
                ocraPin = ''

        timeShift = 0
        if  ocraSuite.T is not None:
            defTimeWindow = int(getFromConfig("ocra.timeWindow", 180))
            window = int(self.getFromTokenInfo('timeWindow', defTimeWindow)) / ocraSuite.T
            defTimeShift = int(getFromConfig("ocra.timeShift", 0))
            timeShift = int(self.getFromTokenInfo("timeShift", defTimeShift))

        default_retry_window = int(getFromConfig("ocra2.max_check_challenge_retry", 0))
        retry_window = int(self.getFromTokenInfo("max_check_challenge_retry", default_retry_window))

        ## now check the otp for each challenge

        for ch in challenges:
            challenge = {}

            ##  preserve transaction context, so we could use this in the status callback
            self.transId = ch.get('transid', None)
            challenge['transid'] = self.transId
            challenge['session'] = ch.get('session', None)

            ## we saved the 'real' challenge in the data
            data = ch.get('data', None)
            if data is not None:
                challenge['challenge'] = data.get('challenge')
            elif 'challenge' in ch:
                ## handle explicit challenge requests
                challenge['challenge'] = ch.get('challenge')

            if challenge.get('challenge') is None:
                raise Exception('could not checkOtp due to missing challenge'
                                ' in request: %r' % ch)

            ret = ocraSuite.checkOtp(passw, counter, window, challenge, pin=ocraPin , options=options, timeshift=timeShift)
            log.debug('[checkOtp]: %r' % (ret))

            ## due to the assynchronous challenge verification of the checkOtp
            ## it might happen, that the found counter is lower than the given
            ## one. Thus we fix this here to deny assynchronous verification

            # we do not support retry checks anymore:
            # which means, that ret might be smaller than the actual counter
            if ocraSuite.T is None:
                if ret + retry_window < counter:
                    ret = -1

            if ret != -1:
                break

        if -1 == ret:
            ##  autosync: test if two consecutive challenges + it's counter match
            ret = self.autosync(ocraSuite, passw, challenge)


        return ret
Exemplo n.º 2
0
    def resync(self, otp1, otp2, options=None):
        '''
        - for the resync to work, we take the last two transactions and their challenges
        - for each challenge, we search forward the sync window length

        '''
        log.debug('[resync] %r : %r' % (otp1, otp2))

        ret = False
        challenges = []

        ## the challenges are orderd, the first one is the newest
        challenges = get_challenges(self.getSerial())

        ##  check if there are enough challenges around
        if len(challenges) < 2:
            return False

        challenge1 = {}
        challenge2 = {}

        if options is None:

            ## the newer one
            ch1 = challenges[0]
            challenge1['challenge'] = ch1.get('data').get('challenge')
            challenge1['transid'] = ch1.get('transid')
            challenge1['session'] = ch1.get('session')
            challenge1['id'] = ch1.get('id')


            ## the elder one
            ch2 = challenges[0]
            challenge2['challenge'] = ch2.get('data').get('challenge')
            challenge2['transid'] = ch2.get('transid')
            challenge2['session'] = ch2.get('session')
            challenge2['id'] = ch2.get('id')

        else:
            if options.has_key('challenge1'):
                challenge1['challenge'] = options.get('challenge1')
            if options.has_key('challenge2'):
                challenge2['challenge'] = options.get('challenge2')


        if len(challenge1) == 0 or len(challenge2) == 0:
            error = "No challeges found!"
            log.error('[Ocra2TokenClass:resync] %s' % (error))
            raise Exception('[Ocra2TokenClass:resync] %s' % (error))



        secretHOtp = self.token.getHOtpKey()
        ocraSuite = OcraSuite(self.getOcraSuiteSuite(), secretHOtp)

        syncWindow = self.token.getSyncWindow()
        if  ocraSuite.T is not None:
            syncWindow = syncWindow / 10

        counter = self.token.getOtpCounter()

        ## set the ocra token pin
        ocraPin = ''
        if ocraSuite.P is not None:
            ocraPinObj = self.token.getUserPin()
            ocraPin = ocraPinObj.getKey()

            if ocraPin is None or len(ocraPin) == 0:
                ocraPin = ''

        timeShift = 0
        if  ocraSuite.T is not None:
            timeShift = int(self.getFromTokenInfo("timeShift", 0))

        try:

            count_1 = ocraSuite.checkOtp(otp1, counter, syncWindow, challenge1, pin=ocraPin, timeshift=timeShift)
            if count_1 == -1:
                log.info('[resync] lookup for first otp value failed!')
                ret = False
            else:
                count_2 = ocraSuite.checkOtp(otp2, counter, syncWindow, challenge2, pin=ocraPin, timeshift=timeShift)
                if count_2 == -1:
                    log.info('[resync] lookup for second otp value failed!')
                    ret = False
                else:
                    if ocraSuite.C is not None:
                        if count_1 + 1 == count_2:
                            self.setOtpCount(count_2)
                            ret = True

                    if  ocraSuite.T is not None:
                        if count_1 - count_2 <= ocraSuite.T * 2:
                            ##  callculate the timeshift
                            date = datetime.datetime.fromtimestamp(count_2)
                            log.info('[resync] syncing token to new timestamp: %r' % (date))

                            now = datetime.datetime.now()
                            stime = now.strftime("%s")
                            timeShift = count_2 - int(stime)
                            self.addToTokenInfo('timeShift', timeShift)
                            ret = True

        except Exception as ex:
            log.error('[Ocra2TokenClass:resync] unknown error: %r' % (ex))
            raise Exception('[Ocra2TokenClass:resync] unknown error: %s' % (ex))

        log.debug('[resync]: %r ' % (ret))
        return ret