示例#1
0
    def finish_challenge_token(self):
        """
        processing of the challenge tokens
        """
        challenge_tokens = self.challenge_tokens
        options = self.options
        if not options:
            options = {}

        action_detail = 'challenge created'

        if len(challenge_tokens) == 1:
            challenge_token = challenge_tokens[0]
            _res, reply = Challenges.create_challenge(
                                challenge_token, options=options)
            return (False, reply, action_detail)

        # processing of multiple challenges
        else:
            # for each token, who can submit a challenge, we have to
            # create the challenge. To mark the challenges as depending
            # the transaction id will have an id that all sub transaction share
            # and a postfix with their enumaration. Finally the result is
            # composed by the top level transaction id and the message
            # and below in a dict for each token a challenge description -
            # the key is the token type combined with its token serial number
            all_reply = {'challenges': {}}
            challenge_count = 0
            transactionid = ''
            challenge_id = ""
            for challenge_token in challenge_tokens:
                challenge_count += 1
                id_postfix = ".%02d" % challenge_count
                if transactionid:
                    challenge_id = "%s%s" % (transactionid, id_postfix)

                (_res, reply) = Challenges.create_challenge(
                    challenge_token,
                    options=options,
                    challenge_id=challenge_id,
                    id_postfix=id_postfix
                )
                transactionid = reply.get('transactionid').rsplit('.')[0]

                # add token type and serial to ease the type specific processing
                reply['linotp_tokentype'] = challenge_token.type
                reply['linotp_tokenserial'] = challenge_token.getSerial()
                key = challenge_token.getSerial()
                all_reply['challenges'][key] = reply

            # finally add the root challenge response with top transaction id
            # and message, that indicates that 'multiple challenges have been
            # submitted
            all_reply['transactionid'] = transactionid
            all_reply['message'] = "Multiple challenges submitted."

            log.debug("Multiple challenges submitted: %d",
                      len(challenge_tokens))

            return (False, all_reply, action_detail)
示例#2
0
    def finish_challenge_token(self):
        """
        processing of the challenge tokens
        """
        challenge_tokens = self.challenge_tokens
        options = self.options
        if not options:
            options = {}

        action_detail = 'challenge created'

        if len(challenge_tokens) == 1:
            challenge_token = challenge_tokens[0]

            _res, reply = Challenges.create_challenge(challenge_token,
                                                      options=options)

            return (False, reply, action_detail)

        # processing of multiple challenges
        else:
            # for each token, who can submit a challenge, we have to
            # create the challenge. To mark the challenges as depending
            # the transaction id will have an id that all sub transaction share
            # and a postfix with their enumeration. Finally the result is
            # composed by the top level transaction id and the message
            # and below in a dict for each token a challenge description -
            # the key is the token type combined with its token serial number

            all_reply = {'challenges': {}}
            challenge_count = 0
            transactionid = ''
            challenge_id = ""
            for challenge_token in challenge_tokens:
                challenge_count += 1
                id_postfix = ".%02d" % challenge_count
                if transactionid:
                    challenge_id = "%s%s" % (transactionid, id_postfix)

                (_res, reply) = Challenges.create_challenge(
                    challenge_token,
                    options=options,
                    challenge_id=challenge_id,
                    id_postfix=id_postfix)
                transactionid = reply.get('transactionid').rsplit('.')[0]
                key = challenge_token.getSerial()
                all_reply['challenges'][key] = reply

            # finally add the root challenge response with top transaction id
            # and message, that indicates that 'multiple challenges have been
            # submitted
            all_reply['transactionid'] = transactionid
            all_reply['message'] = "Multiple challenges submitted."

            log.debug("Multiple challenges submitted: %d",
                      len(challenge_tokens))

            return (False, all_reply, action_detail)
示例#3
0
文件: validate.py 项目: soitun/LinOTP
    def checkSerialPass(self, serial, passw, options=None, user=None):
        """
        This function checks the otp for a given serial

        :attention: the parameter user must be set, as the pin policy==1 will
                    verify the user pin
        """

        token_type = options.get("token_type", None)

        tokenList = getTokens4UserOrSerial(None,
                                           serial,
                                           token_type=token_type,
                                           read_for_update=True)

        if passw is None:
            # other than zero or one token should not happen, as serial is
            # unique
            if len(tokenList) == 1:
                theToken = tokenList[0]
                tok = theToken.token
                realms = tok.getRealmNames()
                if realms is None or len(realms) == 0:
                    realm = getDefaultRealm()
                elif len(realms) > 0:
                    realm = realms[0]
                userInfo = getUserInfo(
                    tok.LinOtpUserid,
                    tok.LinOtpIdResolver,
                    tok.LinOtpIdResClass,
                )
                user = User(login=userInfo.get("username"), realm=realm)
                user.info = userInfo

                if theToken.is_challenge_request(passw, user, options=options):
                    (res, opt) = Challenges.create_challenge(theToken, options)
                    res = False
                else:
                    raise ParameterError("Missing parameter: pass", id=905)

            else:
                raise Exception("No token found: "
                                "unable to create challenge for %s" % serial)

        else:
            (res, opt) = self.checkTokenList(tokenList,
                                             passw,
                                             user=user,
                                             options=options)

        return (res, opt)
示例#4
0
    def checkSerialPass(self, serial, passw, options=None, user=None):
        """
        This function checks the otp for a given serial

        :attention: the parameter user must be set, as the pin policy==1 will
                    verify the user pin
        """

        log.debug('checking for serial %r' % serial)
        tokenList = linotp.lib.token.getTokens4UserOrSerial(
            None, serial)

        if passw is None:
            # other than zero or one token should not happen, as serial is
            # unique
            if len(tokenList) == 1:
                theToken = tokenList[0]
                tok = theToken.token
                realms = tok.getRealmNames()
                if realms is None or len(realms) == 0:
                    realm = getDefaultRealm()
                elif len(realms) > 0:
                    realm = realms[0]
                userInfo = getUserInfo(tok.LinOtpUserid, tok.LinOtpIdResolver,
                                       tok.LinOtpIdResClass)
                user = User(login=userInfo.get('username'), realm=realm)
                user.info = userInfo

                if theToken.is_challenge_request(passw, user, options=options):
                    (res, opt) = Challenges.create_challenge(
                        theToken, options)
                    res = False
                else:
                    raise ParameterError('Missing parameter: pass', id=905)

            else:
                raise Exception('No token found: '
                                'unable to create challenge for %s' % serial)

        else:
            log.debug('checking len(pass)=%r for serial %r' %
                      (len(passw), serial))

            (res, opt) = self.checkTokenList(
                tokenList, passw, user=user, options=options)

        return (res, opt)
示例#5
0
    def checkSerialPass(self, serial, passw, options=None, user=None):
        """
        This function checks the otp for a given serial

        :attention: the parameter user must be set, as the pin policy==1 will
                    verify the user pin
        """

        log.debug('checking for serial %r' % serial)
        tokenList = linotp.lib.token.getTokens4UserOrSerial(None, serial)

        if passw is None:
            # other than zero or one token should not happen, as serial is
            # unique
            if len(tokenList) == 1:
                theToken = tokenList[0]
                tok = theToken.token
                realms = tok.getRealmNames()
                if realms is None or len(realms) == 0:
                    realm = getDefaultRealm()
                elif len(realms) > 0:
                    realm = realms[0]
                userInfo = getUserInfo(tok.LinOtpUserid, tok.LinOtpIdResolver,
                                       tok.LinOtpIdResClass)
                user = User(login=userInfo.get('username'), realm=realm)
                user.info = userInfo

                if theToken.is_challenge_request(passw, user, options=options):
                    (res, opt) = Challenges.create_challenge(theToken, options)
                    res = False
                else:
                    raise ParameterError('Missing parameter: pass', id=905)

            else:
                raise Exception('No token found: '
                                'unable to create challenge for %s' % serial)

        else:
            log.debug('checking len(pass)=%r for serial %r' %
                      (len(passw), serial))

            (res, opt) = self.checkTokenList(tokenList,
                                             passw,
                                             user=user,
                                             options=options)

        return (res, opt)
示例#6
0
文件: qrtoken.py 项目: kuffz/LinOTP
    def update(self, params):

        param_keys = set(params.keys())
        init_rollout_state_keys = set(['type', 'hashlib', 'serial',
                                       'key_size', 'user.login',
                                       'user.realm', 'session'])

        # ----------------------------------------------------------------------

        if param_keys.issubset(init_rollout_state_keys):

            # if param keys are in {'type', 'hashlib'} the token is
            # initialized for the first time. this is e.g. done on the
            # manage web ui. since the token doesn't exist in the database
            # yet, its rollout state must be None (that is: they data for
            # the rollout state doesn't exist yet)

            self.ensure_state(None)

            # ------------------------------------------------------------------

            # collect data used for generating the pairing url

            serial = params.get('serial')
            hash_algorithm = params.get('hashlib')
            pub_key = get_qrtoken_public_key()

            cb_url = get_single_auth_policy('qrtoken_pairing_callback_url')
            cb_sms = get_single_auth_policy('qrtoken_pairing_callback_sms')

            # TODO: read from config
            otp_pin_length = None

            # ------------------------------------------------------------------

            pairing_url = generate_pairing_url('qrtoken',
                                          server_public_key=pub_key,
                                          serial=serial,
                                          callback_url=cb_url,
                                          callback_sms_number=cb_sms,
                                          otp_pin_length=otp_pin_length,
                                          hash_algorithm=hash_algorithm)

            # ------------------------------------------------------------------

            self.addToInfo('pairing_url', pairing_url)

            # we set the the active state of the token to False, because
            # it should not be allowed to use it for validation before the
            # pairing process is done

            self.token.LinOtpIsactive = False

            # ------------------------------------------------------------------

            self.change_state('pairing_url_sent')

        # ----------------------------------------------------------------------

        elif 'pairing_response' in params:

            # if a pairing response is in the parameters, we guess,
            # that the request refers to a token in the state
            # 'pairing_url_sent'

            self.ensure_state('pairing_url_sent')

            # ------------------------------------------------------------------

            # adding the user's public key to the token info
            # as well as the user_token_id, which is used to
            # identify the token on the user's side

            self.addToTokenInfo('user_token_id', params['user_token_id'])

            # user public key arrives in the bytes format.
            # we must convert to a string in order to be
            # able to dump it as json in the db

            b64_user_public_key = b64encode(params['user_public_key'])
            self.addToTokenInfo('user_public_key', b64_user_public_key)

            # ------------------------------------------------------------------

            # create challenge through the challenge factory

            # add the content type and the challenge data to the params
            # (needed in the createChallenge method)

            params['content_type'] = CONTENT_TYPE_PAIRING
            params['data'] = self.getSerial()

            self.change_state('pairing_response_received')

            success, challenge_dict = Challenges.create_challenge(self, params)

            if not success:
                raise Exception('Unable to create challenge from '
                                'pairing response %s' %
                                params['pairing_response'])

            challenge_url = challenge_dict['message']

            # ------------------------------------------------------------------

            self.addToInfo('pairing_challenge_url', challenge_url)

            # ------------------------------------------------------------------

            self.change_state('pairing_challenge_sent')
示例#7
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))


        '''
        log.debug('[challenge] %r: %r: %r' % (data, session, challenge))

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

        if data is None or len(data) == 0:
            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)

        log.debug('[Ocra2TokenClass] challenge: %r ' % (challenge))

        counter = self.getOtpCount()

        ## set the pin onyl in the compliant hashed mode
        pin = ''
        if ocraSuite.P is not None:
            pinObj = self.token.getUserPin()
            pin = pinObj.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:
            raise Exception('[Ocra2TokenClass] Failed to create ocrasuite '
                                                        'challenge: %r' % (ex))

        ##  create a non exisiting challenge
        try:

            (res, opt) = Challenges.create_challenge(self, self.context, options={'messgae': data})

            transid = opt.get('transactionid')
            challenge = opt.get('challenge')

        except Exception as ex:
            ##  this might happen if we have a db problem or
            ##   the uniqnes constrain does not fit
            log.exception("[Ocra2TokenClass] %r" % ex)
            raise Exception('[Ocra2TokenClass] Failed to create '
                                                'challenge object: %s' % (ex))

        realm = None
        realms = self.token.getRealms()
        if len(realms) > 0:
            realm = realms[0]

        url = ''
        if realm is not None:
            url = get_qrtan_url(realm.name, context=self.context)

        log.debug('[challenge]: %r: %r: %r' % (transid, challenge, url))
        return (transid, challenge, True, url)
示例#8
0
    def _rollout_2(self, params):
        '''
        2.

        https://linotpserver/admin/init?
            type=ocra&
            genkey=1&
            activationcode=AKTIVIERUNGSCODE&
            user=BENUTZERNAME&
            message=MESSAGE&
            session=SESSIONKEY

        =>> "serial" : SERIENNUMMER, "nonce" : DATAOBJECT, "transactionid" : "TRANSAKTIONSID, "app_import" : IMPORTURL

        - nonce - von HSM oder random ?
        - pkcs5 - kdf2
        - es darf zur einer Zeit nur eine QR Token inaktiv (== im Ausrollzustand) sein !!!!!
          der Token wird über den User gefunden
        - seed = pdkdf2(nonce + activcode + shared secret)
        - challenge generiern - von urandom oder HSM

        '''
        log.debug('[_rollout_2] %r ' % (params))

        activationcode = params.get('activationcode', None)
        if activationcode is not None:

            ##  genkey might have created a new key, so we have to rely on
            encSharedSecret = self.getFromTokenInfo('sharedSecret', None)
            if encSharedSecret is None:
                raise Exception ('missing shared secret of initialition for token %r' % (self.getSerial()))

            sharedSecret = decryptPin(encSharedSecret)

            ##  we generate a nonce, which in the end is a challenge
            nonce = createNonce()
            self.addToTokenInfo('nonce', nonce)

            ##  create a new key from the ocrasuite
            key_len = 20
            if self.ocraSuite.find('-SHA256'):
                key_len = 32
            elif self.ocraSuite.find('-SHA512'):
                key_len = 64


            newkey = kdf2(sharedSecret, nonce, activationcode, key_len)
            self.setOtpKey(binascii.hexlify(newkey))

            ##  generate challenge, which is part of the app_import
            message = params.get('message', None)

            #(transid, challenge, _ret, url) = self.challenge(message)

            #self.createChallenge()
            (res, opt) = Challenges.create_challenge(self, self.context, options=params)

            challenge = opt.get('challenge')
            url = opt.get('url')
            transid = opt.get('transactionid')

            ##  generate response
            info = {}
            uInfo = {}
            info['serial'] = self.getSerial()
            uInfo['se'] = self.getSerial()
            info['nonce'] = nonce
            uInfo['no'] = nonce
            info['transactionid'] = transid
            uInfo['tr'] = transid
            info['challenge'] = challenge
            uInfo['ch'] = challenge
            if message is not None:
                uInfo['me'] = str(message.encode("utf-8"))

            ustr = urllib.urlencode({'u':str(url.encode("utf-8"))})
            uInfo['u'] = ustr[2:]
            info['url'] = str(url.encode("utf-8"))

            app_import = 'lseqr://nonce?%s' % (urllib.urlencode(uInfo))

            ##  add a signature of the url
            signature = {'si': self.signData(app_import) }
            info['signature'] = signature.get('si')

            info['app_import'] = "%s&%s" % (app_import, urllib.urlencode(signature))
            self.info = info

            ##  setup new state
            self.addToTokenInfo('rollout', '2')
            self.enable(True)

        log.debug('[_rollout_2]:')
        return