Esempio n. 1
0
def getTokenForUser(user, active=None, exclude_rollout=True):
    """
    should be moved to token.py
    """
    tokenArray = []

    log.debug("[getTokenForUser] iterating tokens for user...")
    log.debug("[getTokenForUser] ...user %s in realm %s.",
              user.login, user.realm)

    tokens = getTokens4UserOrSerial(user=user, serial=None, _class=True,
                                    active=active)

    for token in tokens:

        tok = token.token.get_vars()
        if tok.get('LinOtp.TokenInfo', None):
            token_info = json.loads(tok.get('LinOtp.TokenInfo'))

            # skip the rollout tokens from the selfservice token list

            path = token_info.get('scope', {}).get('path', [])

            if len(path) == 1 and path[0] == 'userservice' and exclude_rollout:
                continue

            tok['LinOtp.TokenInfo'] = token_info

        tok['Enrollment'] = token.get_enrollment_status()

        tokenArray.append(tok)

    log.debug("[getTokenForUser] found tokenarray: %r" % tokenArray)
    return tokenArray
Esempio n. 2
0
def getTokenForUser(user, active=None):
    """
    should be moved to token.py
    """
    tokenArray = []

    log.debug("[getTokenForUser] iterating tokens for user...")
    log.debug("[getTokenForUser] ...user %s in realm %s.", user.login,
              user.realm)

    tokens = getTokens4UserOrSerial(user=user,
                                    serial=None,
                                    _class=True,
                                    active=active)

    for token in tokens:

        tok = token.token.get_vars()
        if tok.get('LinOtp.TokenInfo', None):
            token_info = json.loads(tok.get('LinOtp.TokenInfo'))
            tok['LinOtp.TokenInfo'] = token_info

        tok['Enrollment'] = token.get_enrollment_status()

        tokenArray.append(tok)

    log.debug("[getTokenForUser] found tokenarray: %r" % tokenArray)
    return tokenArray
Esempio n. 3
0
    def pair(self):

        try:

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

            params = dict(**request.params)

            enc_response = params.get('pairing_response')

            if enc_response is None:
                raise Exception('Parameter missing')

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

            dec_response = decrypt_pairing_response(enc_response)
            token_type = dec_response.token_type
            pairing_data = dec_response.pairing_data

            if not hasattr(pairing_data, 'serial') or \
               pairing_data.serial is None:

                raise ValidateError(
                    'Pairing responses with no serial attached '
                    'are currently not implemented.')

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

            # TODO: pairing policy
            tokens = getTokens4UserOrSerial(None, pairing_data.serial)

            if not tokens:
                raise Exception('Invalid serial in pairing response')

            if len(tokens) > 1:
                raise Exception('Multiple tokens found. Pairing not possible')

            token = tokens[0]

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

            if token.type != token_type:
                raise Exception('Serial in pairing response doesn\'t match '
                                'supplied token_type')

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

            token.pair(pairing_data)

            Session.commit()
            return sendResult(response, False)

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

        except Exception:
            Session.rollback()
            return sendResult(response, False, 0, status=False)

        finally:
            Session.close()
Esempio n. 4
0
def getTokenForUser(user, active=None):
    """
    should be moved to token.py
    """
    tokenArray = []

    log.debug("[getTokenForUser] iterating tokens for user...")
    log.debug("[getTokenForUser] ...user %s in realm %s.", user.login,
              user.realm)

    tokens = getTokens4UserOrSerial(user=user,
                                    serial=None,
                                    _class=True,
                                    active=active)

    for token in tokens:

        tok = token.token.get_vars()
        if tok.get('LinOtp.TokenInfo', None):
            token_info = json.loads(tok.get('LinOtp.TokenInfo'))

            # skip the rollout tokens from the selfservice token list

            path = token_info.get('scope', {}).get('path', [])
            if len(path) == 1 and path[0] == 'userservice':
                continue

            tok['LinOtp.TokenInfo'] = token_info

        tok['Enrollment'] = token.get_enrollment_status()

        tokenArray.append(tok)

    log.debug("[getTokenForUser] found tokenarray: %r" % tokenArray)
    return tokenArray
Esempio n. 5
0
    def pair(self):

        try:

            params = dict(**request.params)
            enc_response = params.get('pairing_response')
            if enc_response is None:
                raise Exception('Parameter missing')

            dec_response = decrypt_pairing_response(enc_response)

            if not dec_response.serial:
                raise ValidateError(
                    'Pairing responses with no serial attached '
                    'are currently not implemented.')

            serial = dec_response.serial
            user_public_key = dec_response.user_public_key
            user_token_id = dec_response.user_token_id
            user = dec_response.user_login

            user = getUserFromParam(params, optional)

            # TODO: pairing policy
            tokens = getTokens4UserOrSerial(None, serial)

            if not tokens:
                raise Exception('Invalid serial in pairing response')

            if len(tokens) > 1:
                raise Exception('Multiple tokens found. Pairing not possible')

            token = tokens[0]

            if token.type != 'qr':
                raise Exception('Pairing is only implemented for the qrtoken')

            token.ensure_state('pairing_url_sent')
            token.addToTokenInfo('user_token_id', user_token_id)
            b64_user_public_key = b64encode(user_public_key)
            token.addToTokenInfo('user_public_key', b64_user_public_key)

            params['serial'] = serial
            params['user_public_key'] = user_public_key
            params['user_token_id'] = user_token_id
            params['user'] = user
            params['content_type'] = CONTENT_TYPE_PAIRING
            params['data'] = serial

            token.change_state('pairing_response_received')
            Session.commit()
            return sendResult(response, False)

        except Exception:
            Session.rollback()
            return sendResult(response, False, 0, status=False)

        finally:
            Session.close()
Esempio n. 6
0
    def checkYubikeyPass(self, passw):
        """
        Checks the password of a yubikey in Yubico mode (44,48), where
        the first 12 or 16 characters are the tokenid

        :param passw: The password that consist of the static yubikey prefix
                        and the otp
        :type passw: string

        :return: True/False and the User-Object of the token owner
        :rtype: dict
        """

        audit = context['audit']
        opt = None
        res = False

        tokenList = []

        # strip the yubico OTP and the PIN
        modhex_serial = passw[:-32][-16:]
        try:
            hex_serial = modhex_decode(modhex_serial)
            serialnum = "UBAM" + binascii.unhexlify(hex_serial).decode('utf-8')
        except TypeError as exx:
            log.error("Failed to convert serialnumber: %r" % exx)
            return res, opt

        #  build list of possible yubikey tokens
        serials = [serialnum]
        for i in range(1, 3):
            serials.append("%s_%s" % (serialnum, i))

        for serial in serials:
            tokens = getTokens4UserOrSerial(serial=serial,
                                            read_for_update=True)
            tokenList.extend(tokens)

        if len(tokenList) == 0:
            audit['action_detail'] = ('The serial %s could not be found!' %
                                      serialnum)
            return res, opt

        # FIXME if the Token has set a PIN and the User does not want to enter
        # the PIN for authentication, we need to do something different here...
        #  and avoid PIN checking in __checkToken.
        #  We could pass an "option" to __checkToken.
        (res, opt) = self.checkTokenList(tokenList, passw)

        # Now we need to get the user
        if res is not False and 'serial' in audit:
            serial = audit.get('serial', None)
            if serial is not None:
                user = get_token_owner(tokenList[0])
                audit['user'] = user.login
                audit['realm'] = user.realm
                opt = {'user': user.login, 'realm': user.realm}

        return res, opt
Esempio n. 7
0
def janitor_to_remove_enrollment_token(valid_tokens):
    """
    remove all enrollment only tokens
    """
    # ------------------------------------------------------------------ --

    # get all owners for the valid tokens

    all_owners = set()

    for token in valid_tokens:

        # if the authenticated token is a rollout token, we dont count him

        path = token.getFromTokenInfo('scope', {}).get('path', [])
        if len(path) == 1 and path[0] == 'userservice':
            continue

        owner = get_token_owner(token)
        if owner:
            all_owners.add(owner)

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

    # get all rollout only tokens per owner

    to_be_removed_tokens = []

    for owner in all_owners:

        # should be purge the tokens of the user? <- defined by policy

        if not purge_enrollment_token(user=owner):
            continue

        user_tokens = getTokens4UserOrSerial(user=owner)

        # if there is only one token either
        # - the user has still the rollout: do not delete
        # - or the user has a new one: we dont delete either

        if len(user_tokens) < 2:
            continue

        for token in user_tokens:
            path = token.getFromTokenInfo('scope', {}).get('path', [])
            if len(path) == 1 and path[0] == 'userservice':
                to_be_removed_tokens.append(token)

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

    # delete all rollout tokens

    for token in to_be_removed_tokens:
        remove_token(token)


# eof###########################################################################
Esempio n. 8
0
    def checkYubikeyPass(self, passw):
        """
        Checks the password of a yubikey in Yubico mode (44,48), where
        the first 12 or 16 characters are the tokenid

        :param passw: The password that consist of the static yubikey prefix
                        and the otp
        :type passw: string

        :return: True/False and the User-Object of the token owner
        :rtype: dict
        """

        audit = context['audit']
        opt = None
        res = False

        tokenList = []

        # strip the yubico OTP and the PIN
        modhex_serial = passw[:-32][-16:]
        try:
            serialnum = "UBAM" + modhex_decode(modhex_serial)
        except TypeError as exx:
            log.error("Failed to convert serialnumber: %r" % exx)
            return res, opt

        #  build list of possible yubikey tokens
        serials = [serialnum]
        for i in range(1, 3):
            serials.append("%s_%s" % (serialnum, i))

        for serial in serials:
            tokens = getTokens4UserOrSerial(serial=serial,
                                            read_for_update=True)
            tokenList.extend(tokens)

        if len(tokenList) == 0:
            audit['action_detail'] = (
                'The serial %s could not be found!' % serialnum)
            return res, opt

        # FIXME if the Token has set a PIN and the User does not want to enter
        # the PIN for authentication, we need to do something different here...
        #  and avoid PIN checking in __checkToken.
        #  We could pass an "option" to __checkToken.
        (res, opt) = self.checkTokenList(tokenList, passw)

        # Now we need to get the user
        if res is not False and 'serial' in audit:
            serial = audit.get('serial', None)
            if serial is not None:
                user = get_token_owner(tokenList[0])
                audit['user'] = user.login
                audit['realm'] = user.realm
                opt = {'user': user.login, 'realm': user.realm}

        return res, opt
Esempio n. 9
0
    def pair(self):

        try:

            params = dict(**request.params)
            enc_response = params.get('pairing_response')
            if enc_response is None:
                raise Exception('Parameter missing')

            dec_response = decrypt_pairing_response(enc_response)

            if not dec_response.serial:
                raise ValidateError('Pairing responses with no serial attached '
                                    'are currently not implemented.')

            serial = dec_response.serial
            user_public_key = dec_response.user_public_key
            user_token_id = dec_response.user_token_id
            user = dec_response.user_login

            user = getUserFromParam(params, optional)

            # TODO: pairing policy
            tokens = getTokens4UserOrSerial(None, serial)

            if not tokens:
                raise Exception('Invalid serial in pairing response')

            if len(tokens) > 1:
                raise Exception('Multiple tokens found. Pairing not possible')

            token = tokens[0]

            if token.type != 'qr':
                raise Exception('Pairing is only implemented for the qrtoken')

            token.ensure_state('pairing_url_sent')
            token.addToTokenInfo('user_token_id', user_token_id)
            b64_user_public_key = b64encode(user_public_key)
            token.addToTokenInfo('user_public_key', b64_user_public_key)

            params['serial'] = serial
            params['user_public_key'] = user_public_key
            params['user_token_id'] = user_token_id
            params['user'] = user
            params['content_type'] = CONTENT_TYPE_PAIRING
            params['data'] = serial

            token.change_state('pairing_response_received')
            Session.commit()
            return sendResult(response, False)

        except Exception:
            Session.rollback()
            return sendResult(response, False, 0, status=False)

        finally:
            Session.close()
Esempio n. 10
0
    def check_by_transactionid(self, transid, passw, options=None):
        """
        check the passw against the open transaction

        :param transid: the transaction id
        :param passw: the pass parameter
        :param options: the additional optional parameters

        :return: tuple of boolean and detail dict
        """

        reply = {}

        serials = []
        challenges = Challenges.lookup_challenges(transid=transid)

        for challenge in challenges:
            serials.append(challenge.tokenserial)

        if not serials:
            reply['value'] = False
            reply['failure'] = ('No challenge for transaction %r found' %
                                transid)

            return False, reply

        reply['failcount'] = 0
        reply['value'] = False
        reply['token_type'] = ''

        for serial in serials:

            tokens = getTokens4UserOrSerial(serial=serial)
            if not tokens:
                raise Exception('tokenmismatch for token serial: %s' %
                                (unicode(serial)))

            # there could be only one
            token = tokens[0]
            owner = linotp.lib.token.get_token_owner(token)

            (ok, opt) = self.checkTokenList(tokens,
                                            passw,
                                            user=owner,
                                            options=options)
            if opt:
                reply.update(opt)

            reply['token_type'] = token.getType()
            reply['failcount'] = token.getFailCount()
            reply['value'] = ok

            if ok:
                break

        return ok, reply
Esempio n. 11
0
    def check_by_transactionid(self, transid, passw, options=None):
        """
        check the passw against the open transaction

        :param transid: the transaction id
        :param passw: the pass parameter
        :param options: the additional optional parameters

        :return: tuple of boolean and detail dict
        """

        reply = {}

        serials = []
        challenges = Challenges.lookup_challenges(transid=transid)

        for challenge in challenges:
            serials.append(challenge.tokenserial)

        if not serials:
            reply['value'] = False
            reply['failure'] = ('No challenge for transaction %r found'
                                % transid)

            return False, reply

        reply['failcount'] = 0
        reply['value'] = False
        reply['token_type'] = ''

        for serial in serials:

            tokens = getTokens4UserOrSerial(serial=serial)
            if not tokens:
                raise Exception('tokenmismatch for token serial: %s'
                                % (unicode(serial)))

            # there could be only one
            token = tokens[0]
            owner = linotp.lib.token.get_token_owner(token)

            (ok, opt) = self.checkTokenList(tokens, passw, user=owner,
                                            options=options)
            if opt:
                reply.update(opt)

            reply['token_type'] = token.getType()
            reply['failcount'] = token.getFailCount()
            reply['value'] = ok

            if ok:
                break

        return ok, reply
Esempio n. 12
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
        """

        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)
Esempio n. 13
0
    def _getTargetToken(self, forwardSerial):
        """
        helper - to get the target token
        """
        if self.targetToken:
            return self.targetToken

        from linotp.lib.token import getTokens4UserOrSerial
        tokens = getTokens4UserOrSerial(serial=forwardSerial)

        if not tokens:
            raise Exception('no target token with serial %r found' %
                            forwardSerial)

        self.targetToken = tokens[0]
        return self.targetToken
Esempio n. 14
0
    def _getTargetToken(self, forwardSerial):
        """
        helper - to get the target token
        """
        if self.targetToken:
            return self.targetToken

        from linotp.lib.token import getTokens4UserOrSerial
        tokens = getTokens4UserOrSerial(serial=forwardSerial)

        if not tokens:
            raise Exception('no target token with serial %r found' %
                            forwardSerial)

        self.targetToken = tokens[0]
        return self.targetToken
Esempio n. 15
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
        """

        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)
Esempio n. 16
0
def getTokenForUser(user):
    """
    should be moved to token.py
    """
    tokenArray = []

    log.debug("[getTokenForUser] ...user %s in realm %s." %
              (user.login, user.realm))
    tokens = getTokens4UserOrSerial(user=user, serial=None, _class=False)

    for token in tokens:
        tok = token.get_vars()
        if tok.get('LinOtp.TokenInfo', None):
            token_info = json.loads(tok.get('LinOtp.TokenInfo'))
            tok['LinOtp.TokenInfo'] = token_info
        tokenArray.append(tok)

    log.debug("[getTokenForUser] found tokenarray: %r" % tokenArray)
    return tokenArray
Esempio n. 17
0
def getTokenForUser(user):
    """
    should be moved to token.py
    """
    tokenArray = []

    log.debug("[getTokenForUser] iterating tokens for user...")
    log.debug("[getTokenForUser] ...user %s in realm %s." % (user.login, user.realm))
    tokens = getTokens4UserOrSerial(user=user, serial=None, _class=False)

    for token in tokens:
        tok = token.get_vars()
        if tok.get("LinOtp.TokneInfo", None):
            token_info = json.loads(tok.get("LinOtp.TokneInfo"))
            tok["LinOtp.TokenInfo"] = token_info
        tokenArray.append(tok)

    log.debug("[getTokenForUser] found tokenarray: %r" % tokenArray)
    return tokenArray
Esempio n. 18
0
def getTokenForUser(user, active=None, exclude_rollout=True):
    """
    should be moved to token.py
    """
    tokenArray = []

    log.debug("[getTokenForUser] iterating tokens for user...")
    log.debug(
        "[getTokenForUser] ...user %s in realm %s.", user.login, user.realm
    )

    tokens = getTokens4UserOrSerial(
        user=user, serial=None, _class=True, active=active
    )

    for token in tokens:

        tok = token.token.get_vars()
        if tok.get("LinOtp.TokenInfo", None):
            token_info = json.loads(tok.get("LinOtp.TokenInfo"))

            # skip the rollout tokens from the selfservice token list

            path = token_info.get("scope", {}).get("path", [])
            if (
                set(path) & set(["userservice", "validate"])
                and exclude_rollout
            ):
                continue

            tok["LinOtp.TokenInfo"] = token_info

        tok["Enrollment"] = token.get_enrollment_status()

        tokenArray.append(tok)

    log.debug("[getTokenForUser] found tokenarray: %r", tokenArray)
    return tokenArray
Esempio n. 19
0
    def handle_related_challenge(matching_challenges):
        """
        handle related challenges and close these

        :param matching_challenges: all challenges that have
                                    been correctly answerd
        """
        from linotp.lib.token import getTokens4UserOrSerial

        to_be_closed_challenges = []

        for matching_challenge in matching_challenges:

            # gather all challenges which are now obsolete
            # from the token point of view
            serial = matching_challenge.tokenserial
            token = getTokens4UserOrSerial(serial=serial)[0]
            token_challenges = Challenges.lookup_challenges(serial=serial)
            to_be_closed = token.challenge_janitor([matching_challenge],
                                                   token_challenges)
            to_be_closed_challenges.extend(to_be_closed)

            # gather all challenges which are part of the same transaction
            transid = matching_challenge.transid
            if "." in transid:
                transid = transid.split('.')[0]
            transid_challenges = Challenges.lookup_challenges(transid=transid)
            to_be_closed_challenges.extend(transid_challenges)

        hsm = context['hsm'].get('obj')
        for challenge in set(to_be_closed_challenges):
            challenge.close()
            # and calculate the mac for this token data
            challenge.signChallenge(hsm)
            challenge.save()

        return
Esempio n. 20
0
    def handle_related_challenge(matching_challenges):
        """
        handle related challenges and close these

        :param matching_challenges: all challenges that have
                                    been correctly answered
        """
        from linotp.lib.token import getTokens4UserOrSerial

        to_be_closed_challenges = []

        for matching_challenge in matching_challenges:

            # gather all challenges which are now obsolete
            # from the token point of view
            serial = matching_challenge.tokenserial
            token = getTokens4UserOrSerial(serial=serial)[0]
            token_challenges = Challenges.lookup_challenges(serial=serial)
            to_be_closed = token.challenge_janitor([matching_challenge],
                                                   token_challenges)
            to_be_closed_challenges.extend(to_be_closed)

            # gather all challenges which are part of the same transaction
            transid = matching_challenge.transid
            if "." in transid:
                transid = transid.split('.')[0]
            transid_challenges = Challenges.lookup_challenges(transid=transid)
            to_be_closed_challenges.extend(transid_challenges)

        hsm = context['hsm'].get('obj')
        for challenge in set(to_be_closed_challenges):
            challenge.close()
            # and calculate the mac for this token data
            challenge.signChallenge(hsm)
            challenge.save()

        return
Esempio n. 21
0
    def pair(self):
        """
        validate/pair: for the enrollment of qr and push token
        """

        try:

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

            enc_response = self.request_params.get('pairing_response')

            if enc_response is None:
                raise Exception('Parameter missing')

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

            dec_response = decrypt_pairing_response(enc_response)
            token_type = dec_response.token_type
            pairing_data = dec_response.pairing_data

            if not hasattr(pairing_data, 'serial') or \
               pairing_data.serial is None:

                raise ValidateError('Pairing responses with no serial attached'
                                    ' are currently not implemented.')

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

            # TODO: pairing policy
            tokens = getTokens4UserOrSerial(None, pairing_data.serial)

            if not tokens:
                raise Exception('Invalid serial in pairing response')

            if len(tokens) > 1:
                raise Exception('Multiple tokens found. Pairing not possible')

            token = tokens[0]

            # prepare some audit entries
            t_owner = token.getUser()

            realms = token.getRealms()
            realm = ''
            if realms:
                realm = realms[0]

            c.audit['user'] = t_owner or ''
            c.audit['realm'] = realm

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

            if token.type != token_type:
                raise Exception('Serial in pairing response doesn\'t match '
                                'supplied token_type')

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

            token.pair(pairing_data)
            c.audit['success'] = 1

            Session.commit()
            return sendResult(response, False)

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

        except Exception as exx:
            log.exception("validate/pair failed: %r" % exx)
            c.audit['info'] = unicode(exx)
            Session.rollback()
            return sendResult(response, False, 0, status=False)

        finally:
            Session.close()
Esempio n. 22
0
    def getotp(self):
        '''
        This function is used to retrieve the current otp value for a given
        user or a given serial. If the user has more than one token, the list
        of the tokens is returend.

        method:
            gettoken/getotp

        arguments:
            user    - username / loginname
            realm   - additional realm to match the user to a useridresolver
            serial  - the serial number of the token
            curTime - used ONLY for internal testing: datetime.datetime object

        returns:
            JSON response
        '''

        getotp_active = config.get("GETOTP_ENABLED")
        if not getotp_active:
            return sendError(response, "getotp is not activated.", 0)

        param = self.request_params
        ret = {}
        res = -1
        otpval = ""
        passw = ""
        serials = []

        try:

            serial = getParam(param, "serial", optional)
            user = getUserFromParam(param)
            curTime = getParam(param, "curTime", optional)

            g.audit['user'] = user.login
            if "" != user.login:
                g.audit['realm'] = user.realm or getDefaultRealm()

            if serial:
                log.debug("[getotp] retrieving OTP value for token %s", serial)

            elif user.login:
                log.debug(
                    "[getotp] retrieving OTP value for token for user "
                    "%s@%s", user.login, user.realm)

                toks = getTokens4UserOrSerial(user, serial)
                tokennum = len(toks)

                if tokennum > 1:
                    log.debug("[getotp] The user has more than one token."
                              "Returning the list of serials")
                    res = -3
                    for token in toks:
                        serials.append(token.getSerial())
                elif 1 == tokennum:
                    serial = toks[0].getSerial()
                    log.debug(
                        "[getotp] retrieving OTP for token %s for user"
                        " %s@%s", serial, user.login, user.realm)
                else:
                    log.debug("[getotp] no token found for user %s@%s",
                              user.login, user.realm)
                    res = -4
            else:
                res = -5

            # if a serial was given or a unique serial could be
            # received from the given user.

            if serial:
                max_count = checkPolicyPre('gettoken', 'max_count', param)
                log.debug("[getmultiotp] max_count policy: %s", max_count)
                if max_count <= 0:
                    return sendError(
                        response, "The policy forbids receiving"
                        " OTP values for the token %s in "
                        "this realm" % serial, 1)

                (res, pin, otpval, passw) = getOtp(serial, curTime=curTime)

            g.audit['success'] = True

            if int(res) < 0:
                ret['result'] = False
                if -1 == otpval:
                    ret['description'] = "No Token with this serial number"
                if -2 == otpval:
                    ret['description'] = ("This Token does not support the"
                                          " getOtp function")
                if -3 == otpval:
                    ret['description'] = "The user has more than one token"
                    ret['serials'] = serials
                if -4 == otpval:
                    ret['description'] = "No Token found for this user"
                if -5 == otpval:
                    ret['description'] = ("you need to provide a user or "
                                          "a serial")
            else:
                ret['result'] = True
                ret['otpval'] = otpval
                ret['pin'] = pin
                ret['pass'] = passw

            db.session.commit()
            return sendResult(response, ret, 0)

        except PolicyException as pe:
            log.exception("[getotp] gettoken/getotp policy failed: %r", pe)
            db.session.rollback()
            return sendError(response, str(pe), 1)

        except Exception as exx:
            log.exception("[getotp] gettoken/getotp failed: %r", exx)
            db.session.rollback()
            return sendError(response, "gettoken/getotp failed: %s" % exx, 0)
Esempio n. 23
0
    def _get_user_condition(self, user, valid_realms):

        ucondition = None
        log.debug('[TokenIterator::init] start search for username: >%r<' %
                  (user))

        if not user or user.isEmpty() or not user.login:
            return ucondition

        loginUser = user.login.lower()
        loginUser = loginUser.replace('"', '')
        loginUser = loginUser.replace("'", '')

        searchType = "any"
        ## search for a 'blank' user
        if len(loginUser) == 0 and len(user.login) > 0:
            searchType = "blank"
        elif loginUser == "/:no user:/" or loginUser == "/:none:/":
            searchType = "blank"
        elif loginUser == "/:no user info:/":
            searchType = "wildcard"
        elif "*" in loginUser or "." in loginUser:
            searchType = "wildcard"
        else:
            ## no blank and no wildcard search
            searchType = "exact"

        if searchType == "blank":
            log.debug('[TokenIterator::init] search for empty user: >%r<' %
                      (user.login))
            ucondition = and_(
                or_(Token.LinOtpUserid == u'', Token.LinOtpUserid is None))

        if searchType == "exact":
            log.debug('[TokenIterator::init] search for exact user: %r' %
                      (user))
            serials = []
            users = []

            ## if search for a realmuser 'user@realm' we can take the
            ## realm from the argument
            if len(user.realm) > 0:
                users.append(user)
            else:
                for realm in valid_realms:
                    users.append(User(user.login, realm))

            # resolve the realm with wildcard:
            # identify all users and add these to the userlist
            userlist = []
            for usr in users:
                urealm = usr.realm
                if urealm == '*':
                    # if the realm is set to *, the getUserId
                    # triggers the identification of all resolvers, where the
                    # user might reside: tigger the user resolver lookup
                    (uid, resolver, resolverClass) = getUserId(usr)
                    userlist.extend(usr.getUserPerConf())
                else:
                    userlist.append(usr)

            for usr in userlist:
                try:
                    tokens = getTokens4UserOrSerial(user=usr, _class=False)
                    for tok in tokens:
                        serials.append(tok.LinOtpTokenSerialnumber)
                except UserError as ex:
                    ## we get an exception if the user is not found
                    log.debug('[TokenIterator::init] no exact user: %r' %
                              (user))
                    log.debug('[TokenIterator::init] %r' % ex)

            if len(serials) > 0:
                # if tokens found, search for their serials
                ucondition = and_(Token.LinOtpTokenSerialnumber.in_(serials))
            else:
                # if no token is found, block search for user
                # and return nothing
                ucondition = and_(Token.LinOtpTokenSerialnumber == u'')

        ## handle case, when nothing found in former cases
        if searchType == "wildcard":
            log.debug('[TokenIterator::init] wildcard search: %r' % (user))
            serials = []
            users = getAllTokenUsers()
            logRe = None
            lU = loginUser.replace('*', '.*')
            #lU = lU.replace('..', '.')
            logRe = re.compile(lU)

            for ser in users:
                userInfo = users.get(ser)
                tokenUser = userInfo.get('username').lower()
                try:
                    if logRe.match(u'' + tokenUser) is not None:
                        serials.append(ser)
                except Exception as e:
                    log.error('error no express %r ' % e)

            ## to prevent warning, we check is serials are found
            ## SAWarning: The IN-predicate on
            ## "Token.LinOtpTokenSerialnumber" was invoked with an
            ## empty sequence. This results in a contradiction, which
            ## nonetheless can be expensive to evaluate.  Consider
            ## alternative strategies for improved performance.
            if len(serials) > 0:
                ucondition = and_(Token.LinOtpTokenSerialnumber.in_(serials))
            else:
                ucondition = and_(Token.LinOtpTokenSerialnumber == u'')
        return ucondition
Esempio n. 24
0
    def checkstatus(self):
        """
        method:
            ocra/checkstatus

        description:
            Methode zur assynchronen Ueberpruefungen eines Challenge Response Valiadation requests

        arguments:

            * transactionid:  (required one of  - string - (hex))
                    Dies ist eine Transaktions-ID, die bei der Challenge ausgegeben wurde.

            * serial: (required one of  - string)
                    die Serien Nummer des OCRA Token

            * user: (required one of  - string)
                    die Benutzer eines Tokens

            required is one of (user,serial,transactionid)

        returns:

            A JSON response::

                {
                 "version": "LinOTP 2.4",
                 "jsonrpc": "2.0",
                 "result": {
                     "status": true,
                     "value": [
                             {
                             "serial": SERIENNUMMER1,
                             "transactionid": TRANSACTIONID1,
                             "received_tan": true,
                             "valid_tan": true,
                             "failcount": 0
                             },
                             {
                             "serial": SERIENNUMMER1,
                             "transactionid": TRANSACTIONID2,
                             "received_tan": false,
                             "valid_tan": false,
                             "failcount": 0
                             },
                             {
                             "serial": SERIENNUMMER2,
                             "transactionid": TRANSACTIONID3,
                             "received_tan": true,
                             "valid_tan": false,
                             "failcount": 2
                             },
                         ]
                     },
                 "id": 0
                 }

        exception:

        """
        res = {}
        description = 'ocra/checkstatus: check the token status - for assynchronous verification. Missing parameter: You need to provide one of the parameters "transactionid", "user" or "serial"'

        try:
            param = getLowerParams(request.params)
            log.debug("[checkstatus] check OCRA token status: %r" % param)

            checkPolicyPre('ocra', "status")

            transid = getParam(param, 'transactionid'   , optional)
            user = getUserFromParam(param, optional)
            #user   = getParam(param, 'user'          ,optional)
            serial = getParam(param, 'serial'          , optional)

            if transid is None and user.isEmpty() and serial is None:
                ## raise exception
                log.exception("[ocra/checkstatus] : missing transactionid, user or serial number for token")
                raise ParameterError("Usage: %s" % description, id=77)

            tokens = []
            serials = set()
            status = []

            if serial is not None:
                serials.add(serial)

            ## if we have a transaction, get serial from this challenge
            if transid is not None :
                ocraChallenge = None
                try:
                    ocraChallenge = OcraTokenClass.getTransaction(transid)
                except:
                    pass
                if ocraChallenge is not None:
                    serials.add(ocraChallenge.tokenserial)

            ## if we have a serial number of  token
            if len(serials) > 0:
                for serial in serials:
                    tokens.extend(getTokens4UserOrSerial(serial=serial))

            ## if we have a user
            if user.isEmpty() == False:
                try:
                    tokens.extend(getTokens4UserOrSerial(user=user))
                except:
                    log.warning("no token or user %r found!" % user)

            for token in tokens:
                if token.getType() == 'ocra':
                    challenges = []
                    if transid is None:
                        serial = token.getSerial()
                        challenges = OcraTokenClass.getTransactions4serial(serial)
                    else:
                        challenges.append(OcraTokenClass.getTransaction(transid))

                    for challenge in challenges:
                        stat = token.getStatus(challenge.transid)
                        if stat is not None and len(stat) > 0:
                            status.append(stat)

            res['values'] = status
            c.audit['success'] = res

            Session.commit()
            return sendResult(response, res, 1)

        except PolicyException as pe:
            log.exception("[checkstatus] policy failed: %r" % pe)
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:
            log.exception("[checkstatus] failed: %r" % exx)
            Session.rollback()
            return sendResult(response, unicode(exx), 0)

        finally:
            Session.close()
            log.debug('[ocra/checkstatus] done')
Esempio n. 25
0
    def request(self):
        """
        method:
            ocra/request

        description:
            request a challenge for a user or for a serial number (token).

        arguments:
            * serial: (required - string)
              Serial number of the token, for which a challenge should
              be generated (either serial or user is required)

            * user: (required  - string)
              The user for whose token a challenge should be generated
              If the user has more than one token, an error is returend.
              (either serial or user is required)

            * data: (required - String: URLendoced)
              These are the display data, that can be used to generate the challenge

        remark:
            the app will report a wrong qrcode, if the policy::

                {'authentication' : qrtanurl=https://localhost }

            is not defined !!

        returns:

            A JSON respone::

                        {
                            "version": "LinOTP 2.4",
                            "jsonrpc": "2.0",
                            "result": {
                                "status": true,
                                "value": false,
                            },
                            "detail": {
                                    "transactionid" : TRANSAKTIONSID,
                                    "data" : DATAOBJECT,
                            }
                        }

            * transactionid:
              This is the transaction ID, that is used later for
              verifying the Return code /TAN.

            * data:
              This is an object (URL) which can be used to generate a
              QR-Code to be displayed to the QRTAN App
        """
        res = {}
        description = 'ocra/request: request a challenge for a given user or token (serial). You must either provide a parameter "user" or a parameter "serial".'
        dataobj = ""

        try:
            param = getLowerParams(request.params)
            log.info("[request] saving default configuration: %r" % param)

            checkPolicyPre('ocra', "request")

            serial = getParam(param, 'serial', optional)
            user = getUserFromParam(param, optional)

            if user.isEmpty() and serial is None:
                ## raise exception
                log.exception("[request] user or serial is required")
                raise ParameterError("Usage: %s" % description, id=77)

            message = getParam(param, 'data'  , optional)
            if message is None:
                message = ''

            ## ocra token
            tokens = getTokens4UserOrSerial(user, serial)

            if len(tokens) > 1 :
                error = ('More than one token found: unable to create challenge '
                        'for (u:%r,s:%r)!' % (user, serial))
                log.error(error)
                raise Exception(error)

            if len(tokens) == 0:
                error = ('No token found: unable to create challenge for'
                          ' (u:%r,s:%r)!' % (user, serial))
                log.error(error)
                raise Exception(error)

            ocra = tokens[0]
            (transId, challenge, res, url) = ocra.challenge(message)

            u = urlencode({'u':str(url.encode("utf-8"))})

            uInfo = {'tr': transId, 'ch' : challenge,
                      'me': str(message.encode("utf-8")), 'u': u[2:]}
            detail = {"transactionid"   : transId,
                      'challenge'       : challenge,
                      'message'         : str(message.encode("utf-8")),
                      'url'             : str(url.encode("utf-8")),
                     }

            ## create the app_url from the data'''
            dataobj = 'lseqr://req?%s' % (str(urlencode(uInfo)))

            ## append the signature to the url '''
            signature = {'si' : ocra.signData(dataobj)}
            uInfo['si'] = signature
            dataobj = '%s&%s' % (dataobj, str(urlencode(signature)))

            detail["data"] = dataobj

            c.audit['success'] = res
            #c.audit['info'] += "%s=%s, " % (k, value)

            Session.commit()
            qr = getParam(param, 'qr', optional)
            if qr is not None:
                param['alt'] = detail
                return sendQRImageResult(response, dataobj, param)
            else:
                return sendResult(response, res, 1, opt=detail)

        except PolicyException as pe:
            log.exception("[request] policy failed: %r" % pe)
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:
            log.exception("[request] failed: %r" % exx)
            Session.rollback()
            return sendError(response, unicode(exx))

        finally:
            Session.close()
            log.debug("[request] done")
Esempio n. 26
0
    def check_status(self,
                     transid=None,
                     user=None,
                     serial=None,
                     password=None,
                     use_offline=False):
        """
        check for open transactions - for polling support

        :param transid: the transaction id where we request the status from
        :param user: the token owner user
        :param serial: or the serial we are searching for
        :param password: the pin/password for authorization the request
        :param use_offline: on success the offline info is returned

        :return: tuple of success and detail dict
        """

        expired, challenges = Challenges.get_challenges(None, transid=transid)

        # remove all expired challenges
        if expired:
            Challenges.delete_challenges(None, expired)

        if not challenges:
            return False, None

        # there is only one challenge per transaction id
        # if not multiple challenges, where transaction id is the parent one
        reply = {}

        pin_policies = get_pin_policies(user)
        if 1 in pin_policies:
            pin_match = check_pin(None, password, user=user, options=None)
            if not pin_match:
                return False, None

        involved_tokens = []

        transactions = {}
        for ch in challenges:

            # only look for challenges that are not compromised
            if not Challenges.verify_checksum(ch):
                continue

            # is the requester authorized
            serial = ch.getTokenSerial()
            tokens = getTokens4UserOrSerial(serial=serial)
            if not tokens:
                continue
            involved_tokens.extend(tokens)

            # as one challenge belongs exactly to only one token,
            # we take this one as the token
            token = tokens[0]

            if 1 not in pin_policies:
                pin_match = check_pin(token, password, user=user, options=None)
                if not pin_match:
                    ret = False
                    continue

            ret = True

            trans_dict = {}

            trans_dict['received_count'] = ch.received_count
            trans_dict['received_tan'] = ch.received_tan
            trans_dict['valid_tan'] = ch.valid_tan
            trans_dict['message'] = ch.challenge
            trans_dict['status'] = ch.getStatus()

            token_dict = {'serial': serial, 'type': token.type}

            # 1. check if token supports offline at all
            supports_offline_at_all = token.supports_offline_mode

            # 2. check if policy allows to use offline authentication
            if user is not None and user.login and user.realm:
                realms = [user.realm]
            else:
                realms = token.getRealms()

            offline_is_allowed = supports_offline(realms, token)

            if not ch.is_open() and ch.valid_tan and \
               supports_offline_at_all and \
               offline_is_allowed and \
               use_offline:
                token_dict['offline_info'] = token.getOfflineInfo()

            trans_dict['token'] = token_dict
            transactions[ch.transid] = trans_dict

        if transactions:
            reply['transactions'] = transactions

        return ret, reply
Esempio n. 27
0
    def __init__(self, user, serial, page=None, psize=None, filter=None,
                 sort=None, sortdir=None, filterRealm=None, user_fields=None,
                 params=None):
        '''
        constructor of Tokeniterator, which gathers all conditions to build
        a sqalchemy query - iterator

        :param user:     User object - user provides as well the searchfield
                                       entry
        :type  user:     User class
        :param serial:   serial number of a token
        :type  serial:   string
        :param page:     page number
        :type  page:     int
        :param psize:    how many entries per page
        :type  psize:    int
        :param filter:   additional condition
        :type  filter:   string
        :param sort:     sort field definition
        :type  sort:     string
        :param sortdir:  sort direction: ascending or descending
        :type  sortdir:  string
        :param filterRealm:  restrict the set of token to those in
                             the filterRealm
        :type  filterRealm:  string or list
        :param user_fields:  list of additional fields from the user owner
        :type  user_fields: array
        :param params:  list of additional request parameters
                        - currently not used
        :type  params: dict

        :return: - nothing / None

        '''
        log.debug('[TokenIterator::init] begin. start creating TokenIterator \
        class with parameters: user:%r, serial:%r, page=%r, psize:%r, \
                    filter:%r, sort:%r, sortdir:%r, filterRealm:%r' %
                (user, serial, page, psize, filter, sort, sortdir,
                 filterRealm))

        if params is None:
            params = {}

        self.page = 1
        self.pages = 1
        self.tokens = 0
        self.user_fields = user_fields
        if self.user_fields == None:
            self.user_fields = []

        condition = None
        ucondition = None
        scondition = None
        r_condition = None

        if type(filterRealm) in (str, unicode):
            filterRealm = filterRealm.split(',')

        if type(filterRealm) in [list]:
            s_realms = []
            for f in filterRealm:
                #  support for multiple realm filtering in the ui
                #  as a coma separated string
                for s_realm in f.split(','):
                    s_realms.append(s_realm.strip())
            filterRealm = s_realms

        #  create a list of all realms, which are allowed to be searched
        #  based on the list of the existing ones
        valid_realms = []
        realms = getRealms().keys()
        if '*' in filterRealm:
            valid_realms.append("*")
        else:
            for realm in realms:
                if realm in filterRealm:
                    realm = linotp.lib.crypt.uencode(realm)
                    valid_realms.append(realm)

        if serial is not None:
            #  check if the requested serial is in the realms of
            # the admin (filterRealm)
            log.debug('[TokenIterator::init] start search for serial: >%r<'
                       % (serial))

            allowed = False
            if filterRealm == ['*']:
                allowed = True
            else:
                realms = getTokenRealms(serial)
                for realm in realms:
                    if realm in filterRealm:
                        allowed = True

            if allowed == True:
                if '*' in serial:
                    serial = serial.replace('*', '%')
                    scondition = and_(Token.LinOtpTokenSerialnumber.like(serial))
                else:
                    scondition = and_(Token.LinOtpTokenSerialnumber == serial)

        if user.isEmpty() == False and user is not None:
            log.debug('[TokenIterator::init] start search for username: >%r<'
                      % (user))

            if user.login is not None and (user.login) > 0 :
                loginUser = user.login.lower()
                loginUser = loginUser.replace('"', '')
                loginUser = loginUser.replace("'", '')

                searchType = "any"

                #  search for a 'blank' user
                if len(loginUser) == 0 and len(user.login) > 0:
                    searchType = "blank"
                elif loginUser == "/:no user:/" or loginUser == "/:none:/":
                    searchType = "blank"
                elif loginUser == "/:no user info:/":
                    searchType = "wildcard"
                elif "*" in loginUser or "." in loginUser:
                    searchType = "wildcard"
                else:
                    #  no blank and no wildcard search
                    searchType = "exact"

                if searchType == "blank":
                    log.debug('[TokenIterator::init] search for empty user:'******' >%r<' % (user.login))
                    ucondition = and_(or_(Token.LinOtpUserid == u'',
                                          Token.LinOtpUserid == None))

                if searchType == "exact":
                    log.debug('[TokenIterator::init] search for exact user:'******' %r' % (user))
                    serials = []
                    users = []

                    #  if search for a realmuser 'user@realm' we can take the
                    #  realm from the argument
                    if len(user.realm) > 0:
                        users.append(user)
                    else:
                        for realm in valid_realms:
                            users.append(User(user.login, realm))

                    # resolve the realm with wildcard:
                    # identify all users and add these to the userlist
                    userlist = []
                    for usr in users:
                        urealm = usr.realm
                        if urealm == '*':
                            # if the realm is set to *, the getUserId
                            # triggers the identification of all resolvers,
                            # where the user might reside: tigger the user
                            # resolver lookup
                            (uid, resolver, resolverClass) = getUserId(usr)
                            userlist.extend(usr.getUserPerConf())
                        else:
                            userlist.append(usr)

                    for usr in userlist:
                        try:
                            tokens = getTokens4UserOrSerial(user=usr, _class=False)
                            for tok in tokens:
                                serials.append(tok.LinOtpTokenSerialnumber)
                        except UserError as ex:
                            #  we get an exception if the user is not found
                            log.debug('[TokenIterator::init] no exact user: %r'
                                      % (user))
                            log.debug('[TokenIterator::init] %r' % ex)
                    if len(serials) > 0:
                        # if tokens found, search for their serials
                        ucondition = and_(Token.LinOtpTokenSerialnumber.in_(serials))
                    else:
                        # if no token is found, block search for user
                        # and return nothing
                        ucondition = and_(Token.LinOtpTokenSerialnumber == u'')

                #  handle case, when nothing found in former cases
                if searchType == "wildcard":
                    log.debug('[TokenIterator::init] wildcard search: %r' % (user))
                    serials = []
                    users = getAllTokenUsers()
                    logRe = None
                    lU = loginUser.replace('*', '.*')
                    # lU = lU.replace('..', '.')
                    logRe = re.compile(lU)

                    for ser in users:
                        userInfo = users.get(ser)
                        tokenUser = userInfo.get('username').lower()
                        try:
                            if logRe.match(u'' + tokenUser) is not None:
                                serials.append(ser)
                        except Exception as e:
                            log.error('error no express %r ' % e)

                    #  to prevent warning, we check is serials are found
                    #  SAWarning: The IN-predicate on
                    #  "Token.LinOtpTokenSerialnumber" was invoked with an
                    #  empty sequence. This results in a contradiction, which
                    #  nonetheless can be expensive to evaluate.  Consider
                    #  alternative strategies for improved performance.
                    if len(serials) > 0:
                        ucondition = and_(Token.LinOtpTokenSerialnumber.in_(serials))
                    else:
                        ucondition = and_(Token.LinOtpTokenSerialnumber == u'')

        if filter is None:
            condition = None
        elif filter in ['/:active:/', '/:enabled:/',
                        '/:token is active:/', '/:token is enabled:/' ]:
            condition = and_(Token.LinOtpIsactive == True)
        elif filter in ['/:inactive:/', '/:disabled:/',
                        '/:token is inactive:/', '/:token is disabled:/']:
            condition = and_(Token.LinOtpIsactive == False)
        else:
            #  search in other colums
            filter = linotp.lib.crypt.uencode(filter)
            condition = or_(Token.LinOtpTokenDesc.contains(filter),
                            Token.LinOtpIdResClass.contains(filter),
                            Token.LinOtpTokenSerialnumber.contains(filter),
                            Token.LinOtpUserid.contains(filter),
                            Token.LinOtpTokenType.contains(filter))

        ###################################################################
        #   The condition for only getting certain realms!
        if '*' in valid_realms:
            log.debug("[TokenIterator::init] wildcard for realm '*' found."
                      " Tokens of all realms will be displayed")
        elif len(valid_realms) > 0:
            log.debug("[TokenIterator::init] adding filter condition"
                      " for realm %r" % valid_realms)

            #  get all matching realms
            realm_id_tuples = Session.query(Realm.id).\
                                filter(Realm.name.in_(valid_realms)).all()
            realm_ids = set()
            for realm_tuple in realm_id_tuples:
                realm_ids.add(realm_tuple[0])
            #  get all tokenrealm ids
            token_id_tuples = Session.query(TokenRealm.token_id).\
                        filter(TokenRealm.realm_id.in_(realm_ids)).all()
            token_ids = set()
            for token_tuple in token_id_tuples:
                token_ids.add(token_tuple[0])

            #  define the token id condition
            r_condition = and_(Token.LinOtpTokenId.in_(token_ids))

        elif ("''" in filterRealm or '""' in filterRealm or
              "/:no realm:/" in filterRealm):
            log.debug("[TokenIterator::init] search for all tokens, which are"
                      " in no realm")

            #  get all tokenrealm ids
            token_id_tuples = Session.query(TokenRealm.token_id).all()
            token_ids = set()
            for token_tuple in token_id_tuples:
                token_ids.add(token_tuple[0])

            #  define the token id not condition
            r_condition = and_(not_(Token.LinOtpTokenId.in_(token_ids)))

        #  create the final condition as AND of all conditions
        condTuple = ()
        for conn in (condition, ucondition, scondition, r_condition):
            if type(conn).__name__ != 'NoneType':
                condTuple += (conn,)

        condition = and_(*condTuple)

        order = Token.LinOtpTokenDesc

        if sort == "TokenDesc":
            order = Token.LinOtpTokenDesc
        elif sort == "TokenId":
            order = Token.LinOtpTokenId
        elif sort == "TokenType":
            order = Token.LinOtpTokenType
        elif sort == "TokenSerialnumber":
            order = Token.LinOtpTokenSerialnumber
        elif sort == "TokenType":
            order = Token.LinOtpTokenType
        elif sort == "IdResClass":
            order = Token.LinOtpIdResClass
        elif sort == "IdResolver":
            order = Token.LinOtpIdResolver
        elif sort == "Userid":
            order = Token.LinOtpUserid
        elif sort == "FailCount":
            order = Token.LinOtpFailCount
        elif sort == "Userid":
            order = Token.LinOtpUserid
        elif sort == "Isactive":
            order = Token.LinOtpIsactive

        #  care for the result sort order
        if sortdir is not None and sortdir == "desc":
            order = order.desc()
        else:
            order = order.asc()

        #  care for the result pageing
        if page is None:
            self.toks = Session.query(Token).filter(condition).order_by(order).distinct()
            self.tokens = self.toks.count()

            log.debug("[TokenIterator] DB-Query returned # of objects:"
                      " %i" % self.tokens)
            self.pagesize = self.tokens
            self.it = iter(self.toks)
            return

        try:
            if psize is None:
                pagesize = int(getFromConfig("pagesize", 50))
            else:
                pagesize = int(psize)
        except:
            pagesize = 20

        try:
            thePage = int (page) - 1
        except:
            thePage = 0
        if thePage < 0:
            thePage = 0

        start = thePage * pagesize
        stop = (thePage + 1) * pagesize

        self.toks = Session.query(Token).filter(condition).\
                                         order_by(order).distinct()
        self.tokens = self.toks.count()
        log.debug("[TokenIterator::init] DB-Query returned # of objects:"
                  " %i" % self.tokens)
        self.page = thePage + 1
        fpages = float(self.tokens) / float(pagesize)
        self.pages = int(fpages)
        if fpages - int(fpages) > 0:
            self.pages = self.pages + 1
        self.pagesize = pagesize
        self.toks = self.toks.slice(start, stop)

        self.it = iter(self.toks)

        log.debug('[TokenIterator::init] end. Token iterator created: %r' % \
                  (self.it))

        return
Esempio n. 28
0
    def check_status(self, transid=None, user=None, serial=None,
                     password=None, use_offline=False):
        """
        check for open transactions - for polling support

        :param transid: the transaction id where we request the status from
        :param user: the token owner user
        :param serial: or the serial we are searching for
        :param password: the pin/password for authorization the request
        :param use_offline: on success the offline info is returned

        :return: tuple of success and detail dict
        """

        expired, challenges = Challenges.get_challenges(token=None, transid=transid)

        # remove all expired challenges
        if expired:
            Challenges.delete_challenges(None, expired)

        if not challenges:
            return False, None

        # there is only one challenge per transaction id
        # if not multiple challenges, where transaction id is the parent one
        reply = {}
        involved_tokens = []

        transactions = {}
        for ch in challenges:

            # only look for challenges that are not compromised
            if not Challenges.verify_checksum(ch):
                continue

            # is the requester authorized
            challenge_serial = ch.getTokenSerial()
            if serial and challenge_serial != serial:
                continue

            tokens = getTokens4UserOrSerial(serial=challenge_serial)
            if not tokens:
                continue

            involved_tokens.extend(tokens)

            # as one challenge belongs exactly to only one token,
            # we take this one as the token
            token = tokens[0]
            owner = get_token_owner(token)

            if user and user != owner:
                continue

            involved_tokens.extend(tokens)

            # we only check the user password / token pin if the user
            # paranmeter is given

            if user and owner:
                pin_match = check_pin(token, password, user=owner,
                                       options=None)
            else:
                pin_match = token.checkPin(password)

            if not pin_match:
                continue

            trans_dict = {}

            trans_dict['received_count'] = ch.received_count
            trans_dict['received_tan'] = ch.received_tan
            trans_dict['valid_tan'] = ch.valid_tan
            trans_dict['message'] = ch.getChallenge()
            trans_dict['status'] = ch.getStatus()

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

            # extend the check status with the accept or deny of a transaction

            challenge_session = ch.getSession()

            if challenge_session:

                challenge_session_dict = json.loads(challenge_session)

                if 'accept' in challenge_session_dict:
                    trans_dict['accept'] = challenge_session_dict['accept']

                if 'reject' in challenge_session_dict:
                    trans_dict['reject'] = challenge_session_dict['reject']

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

            token_dict = {'serial': token.getSerial(), 'type': token.type}

            # 1. check if token supports offline at all
            supports_offline_at_all = token.supports_offline_mode

            # 2. check if policy allows to use offline authentication
            if user is not None and user.login and user.realm:
                realms = [user.realm]
            else:
                realms = token.getRealms()

            offline_is_allowed = supports_offline(realms, token)

            if not ch.is_open() and ch.valid_tan and \
               supports_offline_at_all and \
               offline_is_allowed and \
               use_offline:
                token_dict['offline_info'] = token.getOfflineInfo()

            trans_dict['token'] = token_dict
            transactions[ch.transid] = trans_dict

        if transactions:
            reply['transactions'] = transactions

        return len(reply) > 0, reply
Esempio n. 29
0
    def check_status(self):
        """
        check the status of a transaction - for polling support
        """

        try:

            param = self.request_params

            #
            # we require either state or transactionid as parameter

            transid = param.get("state", param.get("transactionid", None))
            if not transid:
                raise ParameterError(
                    _(
                        'Missing required parameter "state" or '
                        '"transactionid"!'
                    )
                )

            #
            # serial is an optional parameter

            serial = param.get("serial", None)

            # user is an optional parameter:
            # if no 'user' in the parameters, the User object will be empty
            user = getUserFromParam(param)

            passw = param.get("pass")
            if passw is None:
                raise ParameterError(_('Missing required parameter "pass"!'))

            use_offline = param.get("use_offline", False)

            va = ValidationHandler()
            ok, opt = va.check_status(
                transid=transid,
                user=user,
                serial=serial,
                password=passw,
                use_offline=use_offline,
            )

            serials = []
            types = []
            owner = None
            challenges = Challenges.lookup_challenges(transid=transid)

            for ch in challenges:
                tokens = getTokens4UserOrSerial(serial=ch.getTokenSerial())
                if not tokens:
                    continue

                for token in tokens:
                    serials.append(token.getSerial())
                    types.append(token.getType())

                    if not owner:
                        owner = get_token_owner(token)

            if owner:
                g.audit["user"] = g.audit["user"] or owner.login
                g.audit["realm"] = g.audit["realm"] or owner.realm

            g.audit["serial"] = " ".join(serials)
            g.audit["token_type"] = " ".join(types)

            g.audit["success"] = ok
            g.audit["info"] = str(opt)

            db.session.commit()
            return sendResult(response, ok, 0, opt=opt)

        except Exception as exx:
            log.error("check_status failed: %r", exx)
            g.audit["info"] = str(exx)
            db.session.rollback()
            return sendResult(response, False, 0)
Esempio n. 30
0
    def checkstatus(self):
        """
        method:
            ocra/checkstatus

        description:
            Methode zur assynchronen Ueberpruefungen eines Challenge
            Response Valiadation requests

        arguments:

            * transactionid:  (required one of  - string - (hex))
                    Dies ist eine Transaktions-ID, die bei der Challenge
                    ausgegeben wurde.

            * serial: (required one of  - string)
                    die Serien Nummer des OCRA Token

            * user: (required one of  - string)
                    die Benutzer eines Tokens

            required is one of (user,serial,transactionid)

        returns:

            A JSON response::

                {
                 "version": "LinOTP 2.4",
                 "jsonrpc": "2.0",
                 "result": {
                     "status": true,
                     "value": [
                             {
                             "serial": SERIENNUMMER1,
                             "transactionid": TRANSACTIONID1,
                             "received_tan": true,
                             "valid_tan": true,
                             "failcount": 0
                             },
                             {
                             "serial": SERIENNUMMER1,
                             "transactionid": TRANSACTIONID2,
                             "received_tan": false,
                             "valid_tan": false,
                             "failcount": 0
                             },
                             {
                             "serial": SERIENNUMMER2,
                             "transactionid": TRANSACTIONID3,
                             "received_tan": true,
                             "valid_tan": false,
                             "failcount": 2
                             },
                         ]
                     },
                 "id": 0
                 }

        exception:

        """
        res = {}
        description = ('ocra/checkstatus: check the token status - '
                       'for assynchronous verification. Missing parameter: '
                       'You need to provide one of the parameters '
                       '"transactionid", "user" or "serial"')

        try:
            param = getLowerParams(request.params)
            log.debug("[checkstatus] check OCRA token status: %r" % param)

            checkPolicyPre('ocra', "status")

            transid = param.get('transactionid')
            user = getUserFromParam(param)
            serial = param.get('serial')

            if transid is None and user.is_empty and serial is None:
                # raise exception
                log.exception("[ocra/checkstatus] : missing transactionid, user or serial number for token")
                raise ParameterError("Usage: %s" % description, id=77)

            tokens = []
            serials = set()
            status = []

            if serial is not None:
                serials.add(serial)

            # if we have a transaction, get serial from this challenge

            if transid is not None:
                ocraChallenge = None
                try:
                    ocraChallenge = OcraTokenClass.getTransaction(transid)
                except:
                    pass
                if ocraChallenge is not None:
                    serials.add(ocraChallenge.tokenserial)

            # if we have a serial number of  token

            if len(serials) > 0:
                for serial in serials:
                    tokens.extend(getTokens4UserOrSerial(serial=serial))

            # if we have a user

            if not user.is_empty:
                try:
                    tokens.extend(getTokens4UserOrSerial(user=user))
                except:
                    log.warning("no token or user %r found!" % user)

            for token in tokens:
                if token.getType() == 'ocra':
                    challenges = []
                    if transid is None:
                        serial = token.getSerial()
                        challenges = OcraTokenClass.getTransactions4serial(
                                                                        serial)
                    else:
                        challenges.append(OcraTokenClass.getTransaction(
                                                                    transid))

                    for challenge in challenges:
                        stat = token.getStatus(challenge.transid)
                        if stat is not None and len(stat) > 0:
                            status.append(stat)

            res['values'] = status
            c.audit['success'] = res

            Session.commit()
            return sendResult(response, res, 1)

        except PolicyException as pe:
            log.exception("[checkstatus] policy failed: %r" % pe)
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:
            log.exception("[checkstatus] failed: %r" % exx)
            Session.rollback()
            return sendResult(response, unicode(exx), 0)

        finally:
            Session.close()
Esempio n. 31
0
    def check_t(self):
        """
        method:
            ocra/check_t

        description:
            verify the response of the ocra token

        arguments:
            * transactionid:  (required - string)
                    Dies ist eine Transaktions-ID, die bei der Challenge
                    ausgegeben wurde.

            * pass:   (required - string)
                    die response, die der OCRA Token auf Grund der Challenge
                    berechnet hat

        returns:

            A JSON response::

                {
                 "version": "LinOTP 2.4",
                 "jsonrpc": "2.0",
                 "result": {
                     "status": true,
                     "value": {
                         "failcount" : 3,
                         "result": false
                        }
                    },
                 "id": 0
                }

        exception:

        """
        res = {}
        description = 'ocra/check_t: validate a token request.'

        try:
            param = getLowerParams(request.params)
            log.info("[check_t] check OCRA token: %r" % param)

            # TODO: checkPolicyPre('ocra', "check_t")

            passw = param.get('pass')
            if passw is None:
                # raise exception'''
                log.exception("[check_t] missing pass ")
                raise ParameterError("Usage: %s Missing parameter "
                                     "'pass'." % description, id=77)

            transid = param.get('transactionid')
            if not transid:
                # raise exception
                log.exception("[check_t] missing transactionid, user or "
                              "serial number of token")
                raise ParameterError("Usage: %s Missing parameter "
                                     "'transactionid'." % description, id=77)

            # if we have a transaction, get serial from this challenge

            value = {}
            ocraChallenge = OcraTokenClass.getTransaction(transid)
            if ocraChallenge is not None:
                serial = ocraChallenge.tokenserial

                tokens = getTokens4UserOrSerial(serial=serial)
                if len(tokens) == 0 or len(tokens) > 1:
                    raise Exception('tokenmismatch for token serial: %s'
                                    % (unicode(serial)))

                theToken = tokens[0]
                tok = theToken.token
                desc = tok.get()
                realms = desc.get('LinOtp.RealmNames')
                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)

                vh = ValidationHandler()
                (ok, _opt) = vh.checkSerialPass(
                                       serial,
                                       passw,
                                       user=user,
                                       options={'transactionid': transid})

                failcount = theToken.getFailCount()
                value['result'] = ok
                value['failcount'] = int(failcount)

            else:

                # no challenge found for this transid

                value['result'] = False
                value['failure'] = ('No challenge for transaction %r found'
                                    % transid)

            c.audit['success'] = res

            Session.commit()
            return sendResult(response, value, 1)

        except Exception as exx:
            log.exception("[check_t] failed: %r", exx)
            Session.rollback()
            return sendResult(response, unicode(exx), 0)

        finally:
            Session.close()
Esempio n. 32
0
    def request(self):
        """
        method:
            ocra/request

        description:
            request a challenge for a user or for a serial number (token).

        arguments:
            * serial: (required - string)
              Serial number of the token, for which a challenge should
              be generated (either serial or user is required)

            * user: (required  - string)
              The user for whose token a challenge should be generated
              If the user has more than one token, an error is returend.
              (either serial or user is required)

            * data: (required - String: URLendoced)
              These are the display data, that can be used to generate the
              challenge

        remark:
            the app will report a wrong qrcode, if the policy::

                {'authentication' : qrtanurl=https://localhost }

            is not defined !!

        returns:

            A JSON respone::

                        {
                            "version": "LinOTP 2.4",
                            "jsonrpc": "2.0",
                            "result": {
                                "status": true,
                                "value": false,
                            },
                            "detail": {
                                    "transactionid" : TRANSAKTIONSID,
                                    "data" : DATAOBJECT,
                            }
                        }

            * transactionid:
              This is the transaction ID, that is used later for
              verifying the Return code /TAN.

            * data:
              This is an object (URL) which can be used to generate a
              QR-Code to be displayed to the QRTAN App
        """
        res = {}
        description = ('ocra/request: request a challenge for a given user or'
                       ' token (serial). You must either provide a parameter '
                       '"user" or a parameter "serial".')
        dataobj = ""

        try:
            param = getLowerParams(request.params)
            log.info("[request] saving default configuration: %r" % param)

            checkPolicyPre('ocra', "request")

            serial = param.get('serial')
            user = getUserFromParam(param)

            if user.is_empty and serial is None:

                log.exception("[request] user or serial is required")
                raise ParameterError("Usage: %s" % description, id=77)

            if not serial:
                if not user.exists():
                    raise UserError("getUserId failed: no user >%s< found!"
                                    % user.login, id=1205)

            message = param.get('data')
            if message is None:
                message = ''

            # ocra token

            tokens = getTokens4UserOrSerial(user, serial)

            if len(tokens) > 1:
                error = ('More than one token found: unable to create '
                         'challenge for (u:%r,s:%r)!' % (user, serial))
                raise Exception(error)

            if len(tokens) == 0:
                error = ('No token found: unable to create challenge for'
                         ' (u:%r,s:%r)!' % (user, serial))
                raise Exception(error)

            ocra = tokens[0]
            (transId, challenge, res, url) = ocra.challenge(message)

            u = urlencode({'u': str(url.encode("utf-8"))})

            uInfo = {'tr': transId,
                     'ch': challenge,
                     'me': str(message.encode("utf-8")),
                     'u': u[2:]}

            detail = {"transactionid": transId,
                      'challenge': challenge,
                      'message': str(message.encode("utf-8")),
                      'url': str(url.encode("utf-8")), }

            # create the app_url from the data

            dataobj = 'lseqr://req?%s' % (str(urlencode(uInfo)))

            # append the signature to the url

            signature = {'si': ocra.signData(dataobj)}
            uInfo['si'] = signature
            dataobj = '%s&%s' % (dataobj, str(urlencode(signature)))

            detail["data"] = dataobj

            c.audit['success'] = res

            Session.commit()
            qr = param.get('qr')
            if qr is not None:
                param['alt'] = detail
                return sendQRImageResult(response, dataobj, param)
            else:
                return sendResult(response, res, 1, opt=detail)

        except PolicyException as pe:
            log.exception("[request] policy failed: %r" % pe)
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:
            log.exception("[request] failed: %r" % exx)
            Session.rollback()
            return sendError(response, unicode(exx))

        finally:
            Session.close()
Esempio n. 33
0
    def check_status(self, transid=None, user=None, serial=None,
                     password=None):
        """
        check for open transactions - for polling support

        :param transid: the transaction id where we request the status from
        :param user: the token owner user
        :param serial: or the serial we are searching for
        :param password: the pin/password for authorization the request

        :return: tuple of success and detail dict
        """

        expired, challenges = Challenges.get_challenges(None, transid=transid)

        # remove all expired challenges
        if expired:
            Challenges.delete_challenges(None, expired)

        if not challenges:
            return False, None

        # there is only one challenge per transaction id
        # if not multiple challenges, where transaction id is the parent one
        reply = {}

        pin_policies = linotp.lib.policy.get_pin_policies(user)
        if 1 in pin_policies:
            pin_match = check_pin(None, password, user=user, options=None)
            if not pin_match:
                return False, None

        involved_tokens = []

        transactions = {}
        for ch in challenges:

            # only look for challenges that are not compromised
            if not Challenges.verify_checksum(ch):
                continue

            # is the requester authorized
            serial = ch.getTokenSerial()
            tokens = getTokens4UserOrSerial(serial=serial)
            if not tokens:
                continue
            involved_tokens.extend(tokens)

            if 1 not in pin_policies:
                pin_match = check_pin(tokens[0], password, user=user,
                                      options=None)
                if not pin_match:
                    ret = False
                    continue

            ret = True

            trans_dict = {}
            trans_dict['transactionid'] = ch.transid
            trans_dict['received_count'] = ch.received_count
            trans_dict['received_tan'] = ch.received_tan
            trans_dict['valid_tan'] = ch.valid_tan
            trans_dict['linotp_tokenserial'] = serial
            trans_dict['linotp_tokentype'] = tokens[0].type
            trans_dict['message'] = ch.challenge

            transactions[serial] = trans_dict

        if transactions:
            reply['transactions'] = transactions

        return ret, reply
Esempio n. 34
0
    def check_status(self, transid=None, user=None, serial=None,
                     password=None, use_offline=False):
        """
        check for open transactions - for polling support

        :param transid: the transaction id where we request the status from
        :param user: the token owner user
        :param serial: or the serial we are searching for
        :param password: the pin/password for authorization the request
        :param use_offline: on success the offline info is returned

        :return: tuple of success and detail dict
        """

        expired, challenges = Challenges.get_challenges(token=None, transid=transid)

        # remove all expired challenges
        if expired:
            Challenges.delete_challenges(None, expired)

        if not challenges:
            return False, None

        # there is only one challenge per transaction id
        # if not multiple challenges, where transaction id is the parent one
        reply = {}
        involved_tokens = []

        transactions = {}
        for ch in challenges:

            # only look for challenges that are not compromised
            if not Challenges.verify_checksum(ch):
                continue

            # is the requester authorized
            challenge_serial = ch.getTokenSerial()
            if serial and challenge_serial != serial:
                continue

            tokens = getTokens4UserOrSerial(serial=challenge_serial)
            if not tokens:
                continue

            involved_tokens.extend(tokens)

            # as one challenge belongs exactly to only one token,
            # we take this one as the token
            token = tokens[0]
            owner = get_token_owner(token)

            if user and user != owner:
                continue

            involved_tokens.extend(tokens)

            # we only check the user password / token pin if the user
            # paranmeter is given

            if user and owner:
                pin_match = check_pin(token, password, user=owner,
                                       options=None)
            else:
                pin_match = token.checkPin(password)

            if not pin_match:
                continue

            trans_dict = {}

            trans_dict['received_count'] = ch.received_count
            trans_dict['received_tan'] = ch.received_tan
            trans_dict['valid_tan'] = ch.valid_tan
            trans_dict['message'] = ch.challenge
            trans_dict['status'] = ch.getStatus()

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

            # extend the check status with the accept or deny of a transaction

            challenge_session = ch.getSession()

            if challenge_session:

                challenge_session_dict = json.loads(challenge_session)

                if 'accept' in challenge_session_dict:
                    trans_dict['accept'] = challenge_session_dict['accept']

                if 'reject' in challenge_session_dict:
                    trans_dict['reject'] = challenge_session_dict['reject']

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

            token_dict = {'serial': token.getSerial(), 'type': token.type}

            # 1. check if token supports offline at all
            supports_offline_at_all = token.supports_offline_mode

            # 2. check if policy allows to use offline authentication
            if user is not None and user.login and user.realm:
                realms = [user.realm]
            else:
                realms = token.getRealms()

            offline_is_allowed = supports_offline(realms, token)

            if not ch.is_open() and ch.valid_tan and \
               supports_offline_at_all and \
               offline_is_allowed and \
               use_offline:
                token_dict['offline_info'] = token.getOfflineInfo()

            trans_dict['token'] = token_dict
            transactions[ch.transid] = trans_dict

        if transactions:
            reply['transactions'] = transactions

        return len(reply) > 0, reply
Esempio n. 35
0
    def check_t(self):

        param = {}
        value = {}
        ok = False
        opt = None

        try:
            param.update(request.params)
            passw = getParam(param, "pass", required)

            transid = param.get('state', None)
            if transid is not  None:
                param['transactionid'] = transid
                del param['state']

            if transid is None:
                transid = param.get('transactionid', None)

            if transid is None:
                raise Exception("missing parameter: state or transactionid!")

            serial = get_tokenserial_of_transaction(transId=transid)
            if serial is None:
                value['value'] = False
                value['failure'] = 'No challenge for transaction %r found'\
                                    % transid


            else:
                param['serial'] = serial

                tokens = getTokens4UserOrSerial(serial=serial)
                if len(tokens) == 0 or len(tokens) > 1:
                    raise Exception('tokenmismatch for token serial: %s'
                                    % (unicode(serial)))

                theToken = tokens[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)

                (ok, opt) = checkSerialPass(serial, passw, user=user,
                                     options=param)

                value['value'] = ok
                failcount = theToken.getFailCount()
                value['failcount'] = int(failcount)

            c.audit['success'] = ok
            #c.audit['info'] += "%s=%s, " % (k, value)
            Session.commit()

            qr = getParam(param, 'qr', optional)
            if qr is not None and opt is not None and opt.has_key('message'):
                try:
                    dataobj = opt.get('message')
                    param['alt'] = "%s" % opt
                    return sendQRImageResult(response, dataobj, param)
                except Exception as exc:
                    log.warning("failed to send QRImage: %r " % exc)
                    return sendQRImageResult(response, opt, param)
            else:
                return sendResult(response, value, 1, opt=opt)

        except Exception as exx:
            log.error("[check_t] validate/check_t failed: %r" % exx)
            log.error("[check_t] %s" % traceback.format_exc())
            c.audit['info'] = unicode(exx)
            Session.rollback()
            return sendError(response, "validate/check_t failed: %s"
                             % unicode(exx), 0)

        finally:
            Session.close()
            log.debug('[check_t] done')
Esempio n. 36
0
    def getotp(self):
        '''
        This function is used to retrieve the current otp value for a given user or a given serial
        If the user has more than one token, the list of the tokens is returend.

        method:
            gettoken/getotp

        arguments:
            user    - username / loginname
            realm   - additional realm to match the user to a useridresolver
            serial  - the serial number of the token
            curTime - used ONLY for internal testing: datetime.datetime object

        returns:
            JSON response
        '''

        getotp_active = config.get("linotpGetotp.active")
        if "True" != getotp_active:
            return sendError(response, "getotp is not activated.", 0)

        param = request.params
        ret = {}
        res = -1
        otpval = ""
        passw = ""
        serials = []

        try:

            serial = getParam(param, "serial", optional)
            user = getUserFromParam(param, optional)
            curTime = getParam(param, "curTime", optional)

            c.audit['user'] = user.login
            if "" != user.login:
                c.audit['realm'] = user.realm or getDefaultRealm()

            if serial:
                log.debug("[getotp] retrieving OTP value for token %s" % serial)
            elif user.login:
                log.debug("[getotp] retrieving OTP value for token for user %s@%s" % (user.login, user.realm))
                toks = getTokens4UserOrSerial(user, serial)
                tokennum = len(toks)
                if tokennum > 1:
                    log.debug("[getotp] The user has more than one token. Returning the list of serials")
                    res = -3
                    for token in toks:
                        serials.append(token.getSerial())
                elif 1 == tokennum:
                    serial = toks[0].getSerial()
                    log.debug("[getotp] retrieving OTP for token %s for user %s@%s" %
                                (serial, user.login, user.realm))
                else:
                    log.debug("[getotp] no token found for user %s@%s" % (user.login, user.realm))
                    res = -4
            else:
                res = -5

            # if a serial was given or a unique serial could be received from the given user.
            if serial:
                max_count = checkPolicyPre('gettoken', 'max_count', param)
                log.debug("[getmultiotp] checkpolicypre returned %s" % max_count)
                if max_count <= 0:
                    return sendError(response, "The policy forbids receiving OTP values for the token %s in this realm" % serial , 1)

                (res, pin, otpval, passw) = getOtp(serial, curTime=curTime)

            c.audit['success'] = True

            if int(res) < 0:
                ret['result'] = False
                if -1 == otpval:
                    ret['description'] = "No Token with this serial number"
                if -2 == otpval:
                    ret['description'] = "This Token does not support the getOtp function"
                if -3 == otpval:
                    ret['description'] = "The user has more than one token"
                    ret['serials'] = serials
                if -4 == otpval:
                    ret['description'] = "No Token found for this user"
                if -5 == otpval:
                    ret['description'] = "you need to provide a user or a serial"
            else:
                ret['result'] = True
                ret['otpval'] = otpval
                ret['pin'] = pin
                ret['pass'] = passw

            Session.commit()
            return sendResult(response, ret , 0)

        except PolicyException as pe:
            log.exception("[getotp] gettoken/getotp policy failed: %r" % pe)
            Session.rollback()
            return sendError(response, unicode(pe), 1)

        except Exception as e:
            log.exception("[getotp] gettoken/getotp failed: %r" % e)
            Session.rollback()
            return sendError(response, "gettoken/getotp failed: %s" % unicode(e), 0)

        finally:
            Session.close()
            log.debug('[getotp] done')
Esempio n. 37
0
    def check_status(self, transid=None, user=None, serial=None,
                     password=None, use_offline=False):
        """
        check for open transactions - for polling support

        :param transid: the transaction id where we request the status from
        :param user: the token owner user
        :param serial: or the serial we are searching for
        :param password: the pin/password for authorization the request
        :param use_offline: on success the offline info is returned

        :return: tuple of success and detail dict
        """

        expired, challenges = Challenges.get_challenges(None, transid=transid)

        # remove all expired challenges
        if expired:
            Challenges.delete_challenges(None, expired)

        if not challenges:
            return False, None

        # there is only one challenge per transaction id
        # if not multiple challenges, where transaction id is the parent one
        reply = {}

        pin_policies = linotp.lib.policy.get_pin_policies(user)
        if 1 in pin_policies:
            pin_match = check_pin(None, password, user=user, options=None)
            if not pin_match:
                return False, None

        involved_tokens = []

        transactions = {}
        for ch in challenges:

            # only look for challenges that are not compromised
            if not Challenges.verify_checksum(ch):
                continue

            # is the requester authorized
            serial = ch.getTokenSerial()
            tokens = getTokens4UserOrSerial(serial=serial)
            if not tokens:
                continue
            involved_tokens.extend(tokens)

            # as one challenge belongs exactly to only one token,
            # we take this one as the token
            token = tokens[0]

            if 1 not in pin_policies:
                pin_match = check_pin(token, password, user=user,
                                      options=None)
                if not pin_match:
                    ret = False
                    continue

            ret = True

            trans_dict = {}

            trans_dict['received_count'] = ch.received_count
            trans_dict['received_tan'] = ch.received_tan
            trans_dict['valid_tan'] = ch.valid_tan
            trans_dict['message'] = ch.challenge
            trans_dict['status'] = ch.getStatus()

            token_dict = {'serial': serial, 'type': token.type}

            # 1. check if token supports offline at all
            supports_offline_at_all = token.supports_offline_mode

            # 2. check if policy allows to use offline authentication
            if user is not None and user.login and user.realm:
                realms = [user.realm]
            else:
                realms = token.getRealms()

            offline_is_allowed = supports_offline(realms, token)

            if not ch.is_open() and ch.valid_tan and \
               supports_offline_at_all and \
               offline_is_allowed and \
               use_offline:
                token_dict['offline_info'] = token.getOfflineInfo()

            trans_dict['token'] = token_dict
            transactions[ch.transid] = trans_dict

        if transactions:
            reply['transactions'] = transactions

        return ret, reply
Esempio n. 38
0
    def check_by_transactionid(self, transid, passw, options=None):
        """
        check the passw against the open transaction

        :param transid: the transaction id
        :param passw: the pass parameter
        :param options: the additional optional parameters

        :return: tuple of boolean and detail dict
        """
        reply = {}

        serials = []
        challenges = Challenges.lookup_challenges(transid=transid)

        for challenge in challenges:
            serials.append(challenge.tokenserial)

        if not serials:
            reply["value"] = False
            reply["failure"] = ("No challenge for transaction %r found" %
                                transid)

            return False, reply

        ok = False
        reply["failcount"] = 0
        reply["value"] = False
        reply["token_type"] = ""

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

        for serial in serials:

            tokens = getTokens4UserOrSerial(serial=serial,
                                            token_type=token_type,
                                            read_for_update=True)

            if not tokens and token_type:
                continue

            if not tokens and not token_type:
                raise Exception("tokenmismatch for token serial: %r" % serial)

            # there could be only one
            token = tokens[0]
            owner = get_token_owner(token)

            (ok, opt) = self.checkTokenList(tokens,
                                            passw,
                                            user=owner,
                                            options=options)
            if opt:
                reply.update(opt)

            reply["value"] = ok
            reply["token_type"] = token.getType()
            reply["failcount"] = token.getFailCount()
            reply["serial"] = token.getSerial()

            if ok:
                break

        return ok, reply
Esempio n. 39
0
    def _get_user_condition(self, user, valid_realms):

        ucondition = None

        if not user or user.is_empty or not user.login:
            return ucondition

        loginUser = user.login.lower()
        loginUser = loginUser.replace('"', '')
        loginUser = loginUser.replace("'", '')

        searchType = "any"
        ## search for a 'blank' user
        if len(loginUser) == 0 and len(user.login) > 0:
            searchType = "blank"
        elif loginUser == "/:no user:/" or loginUser == "/:none:/":
            searchType = "blank"
        elif loginUser == "/:no user info:/":
            searchType = "wildcard"
        elif "*" in loginUser:
            searchType = "wildcard"
        else:
            ## no blank and no wildcard search
            searchType = "exact"

        if searchType == "blank":
            ucondition = and_(or_(Token.LinOtpUserid == u'',
                                  Token.LinOtpUserid is None))

        if searchType == "exact":
            serials = []
            users = []

            # if search for a realmuser 'user@realm' we can take the
            # realm from the argument
            if len(user.realm) > 0:
                users.append(user)
            else:
                # otherwise we add all users which are possible combinations
                # from loginname and entry of the valid realms.
                # In case of a '*' wildcard in the list, we take all available
                # realms
                if '*' in valid_realms:
                    valid_realm_list = getRealms().keys()
                else:
                    valid_realm_list = valid_realms

                for realm in valid_realm_list:
                    users.append(User(user.login, realm))

            # resolve the realm with wildcard:
            # identify all users and add these to the userlist
            userlist = []
            for usr in users:
                urealm = usr.realm
                if urealm == '*':
                    # if the realm is set to *, the getUserId
                    # triggers the identification of all resolvers, where the
                    # user might reside: trigger the user resolver lookup
                    for realm in getRealms().keys():
                        if realm in valid_realms or '*' in valid_realms:
                            usr.realm = realm
                            try:
                                (_uid, _resolver, _resolverClass) = getUserId(usr)
                            except UserError as exx:
                                log.info('User %r not found in realm %r',
                                         usr, realm)
                                continue
                            userlist.extend(usr.getUserPerConf())
                else:
                    userlist.append(usr)

            for usr in userlist:
                try:
                    tokens = getTokens4UserOrSerial(user=usr, _class=False)
                    for tok in tokens:
                        serials.append(tok.LinOtpTokenSerialnumber)
                except UserError as ex:
                    ## we get an exception if the user is not found
                    log.debug('[TokenIterator::init] no exact user: %r'
                              % (user))
                    log.debug('[TokenIterator::init] %r' % ex)

            if len(serials) > 0:
                # if tokens found, search for their serials
                ucondition = and_(Token.LinOtpTokenSerialnumber.in_(serials))
            else:
                # if no token is found, block search for user
                # and return nothing
                ucondition = and_(Token.LinOtpTokenSerialnumber == u'')

        ## handle case, when nothing found in former cases
        if searchType == "wildcard":

            serials = _user_expression_match(loginUser, token_owner_iterator())

            # to prevent warning, we check is serials are found
            # SAWarning: The IN-predicate on
            # "Token.LinOtpTokenSerialnumber" was invoked with an
            # empty sequence. This results in a contradiction, which
            # nonetheless can be expensive to evaluate.  Consider
            # alternative strategies for improved performance.

            if len(serials) > 0:
                ucondition = and_(Token.LinOtpTokenSerialnumber.in_(serials))
            else:
                ucondition = and_(Token.LinOtpTokenSerialnumber == u'')
        return ucondition
Esempio n. 40
0
def janitor_to_remove_enrollment_token(valid_tokens):
    """
    remove all enrollment only tokens
    """
    # ------------------------------------------------------------------ --

    # get all owners for the valid tokens

    all_owners = set()

    for token in valid_tokens:

        # if the authenticated token is a rollout token, we dont count him

        path = token.getFromTokenInfo('scope', {}).get('path', [])
        if len(path) == 1 and path[0] == 'userservice':
            continue

        # TODO: get owner sadly throws a genric exception in case of
        # no intersection beteen token realms and user realms :(
        try:
            owner = get_token_owner(token)
        except Exception:
            continue

        if owner:
            all_owners.add(owner)

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

    # get all rollout only tokens per owner

    to_be_removed_tokens = []

    for owner in all_owners:

        # should be purge the tokens of the user? <- defined by policy

        if not purge_enrollment_token(user=owner):
            continue

        user_tokens = getTokens4UserOrSerial(user=owner)

        # if there is only one token either
        # - the user has still the rollout: do not delete
        # - or the user has a new one: we dont delete either

        if len(user_tokens) < 2:
            continue

        for token in user_tokens:
            path = token.getFromTokenInfo('scope', {}).get('path', [])
            if len(path) == 1 and path[0] == 'userservice':
                to_be_removed_tokens.append(token)

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

    # delete all rollout tokens

    serials = []
    for token in to_be_removed_tokens:
        serials.append(token.getSerial())
        remove_token(token)

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

    # add info about the purging

    audit = context['audit']

    if serials:
        audit['info'] += 'purged rollout tokens:' + ', '.join(serials)
Esempio n. 41
0
    def check_t(self):
        """
        method:
            ocra/check_t

        description:
            verify the response of the ocra token

        arguments:
            * transactionid:  (required - string)
                    Dies ist eine Transaktions-ID, die bei der Challenge ausgegeben wurde.

            * pass:   (required - string)
                    die response, die der OCRA Token auf Grund der Challenge berechnet hat

        returns:

            A JSON response::

                {
                 "version": "LinOTP 2.4",
                 "jsonrpc": "2.0",
                 "result": {
                     "status": true,
                     "value": {
                         "failcount" : 3,
                         "result": false
                        }
                    },
                 "id": 0
                }

        exception:

        """
        res = {}
        description = 'ocra/check_t: validate a token request.'

        try:
            param = getLowerParams(request.params)
            log.info("[check_t] check OCRA token: %r" % param)

            #checkPolicyPre('ocra', "check_t")

            passw = getParam(param, 'pass'  , optional)
            if passw is None:
                ## raise exception'''
                log.exception("[check_t] missing pass ")
                raise ParameterError("Usage: %s Missing parameter 'pass'." % description, id=77)

            transid = getParam(param, 'transactionid', optional)
            if transid is None:
                ## raise exception'''
                log.exception("[check_t] missing transactionid, user or serial number of token")
                raise ParameterError("Usage: %s Missing parameter 'transactionid'." % description, id=77)

            ## if we have a transaction, get serial from this challenge
            value = {}
            ocraChallenge = OcraTokenClass.getTransaction(transid)
            if ocraChallenge is not None:
                serial = ocraChallenge.tokenserial

                tokens = getTokens4UserOrSerial(serial=serial)
                if len(tokens) == 0 or len(tokens) > 1:
                    raise Exception('tokenmismatch for token serial: %s'
                                    % (unicode(serial)))

                theToken = tokens[0]
                tok = theToken.token
                desc = tok.get()
                realms = desc.get('LinOtp.RealmNames')
                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)

                vh = ValidationHandler()
                (ok, opt) = vh.checkSerialPass(serial, passw, user=user,
                                            options={'transactionid': transid})

                failcount = theToken.getFailCount()
                value['result'] = ok
                value['failcount'] = int(failcount)

            else:
                ## no challenge found for this transid
                value['result'] = False
                value['failure'] = 'No challenge for transaction %r found'\
                                    % transid

            c.audit['success'] = res
            #c.audit['info'] += "%s=%s, " % (k, value)

            Session.commit()
            return sendResult(response, value, 1)

        except Exception as e :
            log.exception("[check_t] failed: %r" % e)
            Session.rollback()
            return sendResult(response, unicode(e), 0)

        finally:
            Session.close()
            log.debug("[check_t] done")
Esempio n. 42
0
    def checkUserPass(self, user, passw, options=None):
        """
        :param user: the to be identified user
        :param passw: the identification pass
        :param options: optional parameters, which are provided
                    to the token checkOTP / checkPass

        :return: tuple of True/False and optional information
        """

        # the upper layer will catch / at least should ;-)

        opt = None
        serial = None
        resolverClass = None
        uid = None
        user_exists = False

        if user:
            # the upper layer will catch / at least should
            try:
                (uid, _resolver,
                 resolverClass) = getUserId(user, check_existance=True)
                user_exists = True
            except Exception as _exx:
                pass_on = context.get("Config").get(
                    "linotp.PassOnUserNotFound", False)
                if pass_on and pass_on.lower() == "true":
                    g.audit[
                        "action_detail"] = "authenticated by PassOnUserNotFound"
                    return (True, opt)
                else:
                    g.audit["action_detail"] = "User not found"
                    return (False, opt)

        # if we have an user, check if we forward the request to another server
        if user_exists and not get_auth_forward_on_no_token(user):
            servers = get_auth_forward(user)
            if servers:
                log.info("forwarding auth request for user {} to {}".format(
                    user, servers))
                res, opt = ForwardServerPolicy.do_request(
                    servers, env, user, passw, options)
                log.info("result of auth request for user {}: ({}, {})".format(
                    user, res, opt))
                g.audit["action_detail"] = "Forwarded, result {}".format(res)
                return res, opt
            else:
                log.info(
                    "NOT forwarding auth request for user {} (no servers)".
                    format(user))
                g.audit["action_detail"] = "Not forwarded (no servers)"
        else:
            log.info(
                "NOT forwarding auth request for user {} "
                "(get_auth_forward_on_no_token returned False)".format(user))

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

        th = TokenHandler()

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

        # auto asignement with otp only if user has no active token

        auto_assign_otp_return = th.auto_assign_otp_only(otp=passw,
                                                         user=user,
                                                         options=options)

        if auto_assign_otp_return:
            return (True, None)

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

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

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

        # if there is a serial provided in the parameters, it overwrites the
        # token selection by user

        query_user = user
        if options and "serial" in options and options["serial"]:
            serial = options["serial"]
            query_user = None

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

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

        if len(tokenList) == 0:
            g.audit["action_detail"] = "User has no tokens assigned"

            # here we check if we should to autoassign and try to do it
            auto_assign_return = th.auto_assignToken(passw, user)
            if auto_assign_return:
                # We can not check the token, as the OTP value is already used!
                # but we will auth the user....
                return (True, opt)

            auto_enroll_return, opt = th.auto_enrollToken(passw,
                                                          user,
                                                          options=options)
            if auto_enroll_return:
                # we always have to return a false, as
                # we have a challenge tiggered
                return (False, opt)

            pass_on = context.get("Config").get("linotp.PassOnUserNoToken",
                                                False)
            if pass_on and pass_on.lower() == "true":
                g.audit["action_detail"] = "authenticated by PassOnUserNoToken"
                return (True, opt)

            # Check if there is an authentication policy passthru

            if get_auth_passthru(user):
                log.debug(
                    "user %r has no token. Checking for passthru in realm %r",
                    user.login,
                    user.realm,
                )
                y = getResolverObject(resolverClass)
                g.audit["action_detail"] = "Authenticated against Resolver"
                if y.checkPass(uid, passw):
                    return (True, opt)

            # Check alternatively if there is an authentication
            # policy passOnNoToken
            elif get_auth_passOnNoToken(user):
                log.info("user %r has not token. PassOnNoToken"
                         " set - authenticated!")
                g.audit[
                    "action_detail"] = "Authenticated by passOnNoToken policy"
                return (True, opt)

            # if we have an user, check if we forward the request to another
            # server
            elif get_auth_forward_on_no_token(user):
                servers = get_auth_forward(user)
                if servers:
                    log.info(
                        "forwarding auth request for user {} to {}".format(
                            user, servers))
                    res, opt = ForwardServerPolicy.do_request(
                        servers, env, user, passw, options)
                    log.info(
                        "result of auth request for user {}: ({}, {})".format(
                            user, res, opt))
                    g.audit["action_detail"] = "Forwarded, result {}".format(
                        res)
                    return res, opt
                else:
                    log.info(
                        "NOT forwarding auth request for user {} (no servers)".
                        format(user))
                    g.audit["action_detail"] = "Not forwarded (no servers)"

            return False, opt

        if passw is None:
            raise ParameterError("Missing parameter:pass", id=905)

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

        return (res, opt)
Esempio n. 43
0
    def getotp(self):
        '''
        This function is used to retrieve the current otp value for a given user or a given serial
        If the user has more than one token, the list of the tokens is returend.

        method:
            gettoken/getotp

        arguments:
            user    - username / loginname
            realm   - additional realm to match the user to a useridresolver
            serial  - the serial number of the token
            curTime - used ONY for internal testing: datetime.datetime object

        returns:
            JSON response
        '''

        getotp_active = config.get("linotpGetotp.active")
        if "True" != getotp_active:
            return sendError(response, "getotp is not activated.", 0)

        param = request.params
        ret = {}
        res = -1
        otpval = ""
        passw = ""
        serials = []

        try:

            serial = getParam(param, "serial", optional)
            user = getUserFromParam(param, optional)
            curTime = getParam(param, "curTime", optional)

            c.audit['user'] = user.login
            if "" != user.login:
                c.audit['realm'] = user.realm or getDefaultRealm()

            if serial:
                log.debug("[getotp] retrieving OTP value for token %s" %
                          serial)
            elif user.login:
                log.debug(
                    "[getotp] retrieving OTP value for token for user %s@%s" %
                    (user.login, user.realm))
                toks = getTokens4UserOrSerial(user, serial)
                tokennum = len(toks)
                if tokennum > 1:
                    log.debug(
                        "[getotp] The user has more than one token. Returning the list of serials"
                    )
                    res = -3
                    for token in toks:
                        serials.append(token.getSerial())
                elif 1 == tokennum:
                    serial = toks[0].getSerial()
                    log.debug(
                        "[getotp] retrieving OTP for token %s for user %s@%s" %
                        (serial, user.login, user.realm))
                else:
                    log.debug("[getotp] no token found for user %s@%s" %
                              (user.login, user.realm))
                    res = -4
            else:
                res = -5

            # if a serial was given or a unique serial could be received from the given user.
            if serial:
                max_count = checkPolicyPre('gettoken', 'max_count', param)
                log.debug("[getmultiotp] checkpolicypre returned %s" %
                          max_count)
                if max_count <= 0:
                    return sendError(
                        response,
                        "The policy forbids receiving OTP values for the token %s in this realm"
                        % serial, 1)

                (res, pin, otpval, passw) = getOtp(serial, curTime=curTime)

            c.audit['success'] = True

            if int(res) < 0:
                ret['result'] = False
                if -1 == otpval:
                    ret['description'] = "No Token with this serial number"
                if -2 == otpval:
                    ret['description'] = "This Token does not support the getOtp function"
                if -3 == otpval:
                    ret['description'] = "The user has more than one token"
                    ret['serials'] = serials
                if -4 == otpval:
                    ret['description'] = "No Token found for this user"
                if -5 == otpval:
                    ret['description'] = "you need to provide a user or a serial"
            else:
                ret['result'] = True
                ret['otpval'] = otpval
                ret['pin'] = pin
                ret['pass'] = passw

            Session.commit()
            return sendResult(response, ret, 0)

        except PolicyException as pe:
            log.error("[getotp] gettoken/getotp policy failed: %r" % pe)
            log.error("[getotp] %s" % traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe), 1)

        except Exception as e:
            log.error("[getotp] gettoken/getotp failed: %r" % e)
            log.error("[getotp] %s" % traceback.format_exc())
            Session.rollback()
            return sendError(response,
                             "gettoken/getotp failed: %s" % unicode(e), 0)

        finally:
            Session.close()
            log.debug('[getotp] done')
Esempio n. 44
0
    def check_s(self):
        """
        This function is used to validate the serial and the otp value/password.

        method:
            validate/check_s

        arguments:
            * serial:  the serial number of the token
            * pass:    the password that consists of a possible fixes password component
                        and the OTP value

        returns:
            JSON response
        """
        param = {}
        param.update(request.params)

        options = {}
        options.update(param)
        for k in ["user", "serial", "pass", "init"]:
            if k in options:
                del options[k]

        if "init" in param:
            if isSelfTest() == True:
                options["initTime"] = param.get("init")

        try:
            passw = getParam(param, "pass", optional)
            serial = getParam(param, "serial", optional)
            if serial is None:
                user = getParam(param, "user", optional)
                if user is not None:
                    user = getUserFromParam(param, optional)
                    toks = getTokens4UserOrSerial(user=user)
                    if len(toks) == 0:
                        raise Exception("No token found!")
                    elif len(toks) > 1:
                        raise Exception("More than one token found!")
                    else:
                        tok = toks[0].token
                        desc = tok.get()
                        realms = desc.get("LinOtp.RealmNames")
                        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)

                        serial = tok.getSerial()

            c.audit["serial"] = serial

            if isSelfTest() == True:
                initTime = getParam(param, "init", optional)
                if initTime is not None:
                    if options is None:
                        options = {}
                    options["initTime"] = initTime

            (ok, opt) = checkSerialPass(serial, passw, options=options)

            c.audit["success"] = ok
            Session.commit()

            qr = getParam(param, "qr", optional)
            if qr is not None and opt is not None and opt.has_key("message"):
                try:
                    dataobj = opt.get("message")
                    param["alt"] = "%s" % opt
                    return sendQRImageResult(response, dataobj, param)
                except Exception as exc:
                    log.warning("failed to send QRImage: %r " % exc)
                    return sendQRImageResult(response, opt, param)
            else:
                return sendResult(response, ok, 0, opt=opt)

        except Exception as exx:
            log.error("[check_s] validate/check_s failed: %r" % exx)
            log.error("[check_s] %s" % traceback.format_exc())
            c.audit["info"] = unicode(exx)
            Session.rollback()
            return sendError(response, "validate/check_s failed: %s" % unicode(exx), 0)

        finally:
            Session.close()
            log.debug("[check_s] done")
Esempio n. 45
0
    def _get_user_condition(self, user, valid_realms):

        ucondition = None

        if not user or user.is_empty or not user.login:
            return ucondition

        loginUser = user.login.lower()
        loginUser = loginUser.replace('"', '')
        loginUser = loginUser.replace("'", '')

        searchType = "any"
        ## search for a 'blank' user
        if len(loginUser) == 0 and len(user.login) > 0:
            searchType = "blank"
        elif loginUser == "/:no user:/" or loginUser == "/:none:/":
            searchType = "blank"
        elif loginUser == "/:no user info:/":
            searchType = "wildcard"
        elif "*" in loginUser:
            searchType = "wildcard"
        else:
            ## no blank and no wildcard search
            searchType = "exact"

        if searchType == "blank":
            ucondition = and_(or_(Token.LinOtpUserid == u'',
                                  Token.LinOtpUserid is None))

        if searchType == "exact":
            serials = []
            users = []

            # if search for a realmuser 'user@realm' we can take the
            # realm from the argument
            if len(user.realm) > 0:
                users.append(user)
            else:
                # otherwise we add all users which are possible combinations
                # from loginname and entry of the valid realms.
                # In case of a '*' wildcard in the list, we take all available
                # realms
                if '*' in valid_realms:
                    valid_realm_list = getRealms().keys()
                else:
                    valid_realm_list = valid_realms

                for realm in valid_realm_list:
                    users.append(User(user.login, realm))

            # resolve the realm with wildcard:
            # identify all users and add these to the userlist
            userlist = []
            for usr in users:
                urealm = usr.realm
                if urealm == '*':
                    # if the realm is set to *, the getUserId
                    # triggers the identification of all resolvers, where the
                    # user might reside: trigger the user resolver lookup
                    for realm in getRealms().keys():
                        if realm in valid_realms or '*' in valid_realms:
                            usr.realm = realm
                            try:
                                (_uid, _resolver, _resolverClass) = getUserId(usr)
                            except UserError as exx:
                                log.info('User %r not found in realm %r',
                                         usr, realm)
                                continue
                            userlist.extend(usr.getUserPerConf())
                else:
                    userlist.append(usr)

            for usr in userlist:
                try:
                    tokens = getTokens4UserOrSerial(user=usr, _class=False)
                    for tok in tokens:
                        serials.append(tok.LinOtpTokenSerialnumber)
                except UserError as ex:
                    ## we get an exception if the user is not found
                    log.debug('[TokenIterator::init] no exact user: %r'
                              % (user))
                    log.debug('[TokenIterator::init] %r' % ex)

            if len(serials) > 0:
                # if tokens found, search for their serials
                ucondition = and_(Token.LinOtpTokenSerialnumber.in_(serials))
            else:
                # if no token is found, block search for user
                # and return nothing
                ucondition = and_(Token.LinOtpTokenSerialnumber == u'')

        ## handle case, when nothing found in former cases
        if searchType == "wildcard":

            serials = _user_expression_match(loginUser, token_owner_iterator())

            # to prevent warning, we check is serials are found
            # SAWarning: The IN-predicate on
            # "Token.LinOtpTokenSerialnumber" was invoked with an
            # empty sequence. This results in a contradiction, which
            # nonetheless can be expensive to evaluate.  Consider
            # alternative strategies for improved performance.

            if len(serials) > 0:
                ucondition = and_(Token.LinOtpTokenSerialnumber.in_(serials))
            else:
                ucondition = and_(Token.LinOtpTokenSerialnumber == u'')
        return ucondition
Esempio n. 46
0
    def check_s(self):
        '''
        This function is used to validate the serial and the otp value/password.

        method:
            validate/check_s

        arguments:
            * serial:  the serial number of the token
            * pass:    the password that consists of a possible fixes password component
                        and the OTP value

        returns:
            JSON response
        '''
        param = {}
        param.update(request.params)

        options = {}
        options.update(param)
        for k in ['user', 'serial', "pass", "init"]:
            if k in options:
                del options[k]

        if 'init' in param:
            if isSelfTest() is True:
                options['initTime'] = param.get('init')

        try:
            passw = getParam(param, "pass", optional)
            serial = getParam(param, 'serial', optional)
            if serial is None:
                user = getParam(param, 'user', optional)
                if user is not None:
                    user = getUserFromParam(param, optional)
                    toks = getTokens4UserOrSerial(user=user)
                    if len(toks) == 0:
                        raise Exception("No token found!")
                    elif len(toks) > 1:
                        raise Exception("More than one token found!")
                    else:
                        tok = toks[0].token
                        desc = tok.get()
                        realms = desc.get('LinOtp.RealmNames')
                        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)

                        serial = tok.getSerial()

            c.audit['serial'] = serial

            if isSelfTest() is True:
                initTime = getParam(param, "init", optional)
                if initTime is not None:
                    if options is None:
                        options = {}
                    options['initTime'] = initTime

            options['scope'] = {"check_s": True}
            vh = ValidationHandler()
            (ok, opt) = vh.checkSerialPass(serial, passw, options=options)
            c.audit['success'] = ok
            Session.commit()

            qr = param.get('qr', None)
            if qr and opt and 'message' in opt:
                try:
                    dataobj = opt.get('message')
                    param['alt'] = "%s" % opt
                    if 'transactionid' in opt:
                        param['transactionid'] = opt['transactionid']
                    return sendQRImageResult(response, dataobj, param)
                except Exception as exc:
                    log.warning("failed to send QRImage: %r " % exc)
                    return sendQRImageResult(response, opt, param)
            else:
                return sendResult(response, ok, 0, opt=opt)

        except Exception as exx:
            log.exception("[check_s] validate/check_s failed: %r" % exx)
            c.audit['info'] = unicode(exx)
            Session.rollback()
            return sendResult(response, False, id=0, status=False)

        finally:
            Session.close()
            log.debug('[check_s] done')
Esempio n. 47
0
    def check_s(self):
        '''
        This function is used to validate the serial and the otp value/password.

        method:
            validate/check_s

        arguments:
            * serial:  the serial number of the token
            * pass:    the password that consists of a possible fixes password component
                        and the OTP value

        returns:
            JSON response
        '''
        param = self.request_params

        options = {}
        options.update(param)
        for k in ['user', 'serial', "pass", "init"]:
            if k in options:
                del options[k]

        if 'init' in param:
            if isSelfTest() is True:
                options['initTime'] = param.get('init')

        try:
            passw = param.get("pass")
            serial = param.get('serial')
            if serial is None:
                user = param.get('user')
                if user is not None:
                    user = getUserFromParam(param)
                    toks = getTokens4UserOrSerial(user=user)
                    if len(toks) == 0:
                        raise Exception("No token found!")
                    elif len(toks) > 1:
                        raise Exception("More than one token found!")
                    else:
                        tok = toks[0].token
                        desc = tok.get()
                        realms = desc.get('LinOtp.RealmNames')
                        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)

                        serial = tok.getSerial()

            c.audit['serial'] = serial

            if isSelfTest() is True:
                initTime = param.get("init")
                if initTime is not None:
                    if options is None:
                        options = {}
                    options['initTime'] = initTime

            options['scope'] = {"check_s": True}
            vh = ValidationHandler()
            (ok, opt) = vh.checkSerialPass(serial, passw, options=options)
            c.audit['success'] = ok
            Session.commit()

            qr = param.get('qr', None)
            if qr and opt and 'message' in opt:
                try:
                    dataobj = opt.get('message')
                    param['alt'] = "%s" % opt
                    if 'transactionid' in opt:
                        param['transactionid'] = opt['transactionid']
                    return sendQRImageResult(response, dataobj, param)
                except Exception as exc:
                    log.warning("failed to send QRImage: %r " % exc)
                    return sendQRImageResult(response, opt, param)
            else:
                return sendResult(response, ok, 0, opt=opt)

        except Exception as exx:
            log.exception("[check_s] validate/check_s failed: %r" % exx)
            c.audit['info'] = unicode(exx)
            Session.rollback()
            return sendResult(response, False, id=0, status=False)

        finally:
            Session.close()
Esempio n. 48
0
    def pair(self):
        """
        validate/pair: for the enrollment of qr and push token
        """

        try:

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

            enc_response = self.request_params.get('pairing_response')

            if enc_response is None:
                raise Exception('Parameter missing')

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

            dec_response = decrypt_pairing_response(enc_response)
            token_type = dec_response.token_type
            pairing_data = dec_response.pairing_data

            if not hasattr(pairing_data, 'serial') or \
               pairing_data.serial is None:

                raise ValidateError('Pairing responses with no serial attached'
                                    ' are currently not implemented.')

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

            # TODO: pairing policy
            tokens = getTokens4UserOrSerial(None, pairing_data.serial)

            if not tokens:
                raise Exception('Invalid serial in pairing response')

            if len(tokens) > 1:
                raise Exception('Multiple tokens found. Pairing not possible')

            token = tokens[0]

            # prepare some audit entries
            t_owner = token.getUser()

            realms = token.getRealms()
            realm = ''
            if realms:
                realm = realms[0]

            c.audit['user'] = t_owner or ''
            c.audit['realm'] = realm

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

            if token.type != token_type:
                raise Exception('Serial in pairing response doesn\'t match '
                                'supplied token_type')

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

            token.pair(pairing_data)
            c.audit['success'] = 1
            c.audit['serial'] = token.getSerial()

            Session.commit()
            return sendResult(response, False)

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

        except Exception as exx:
            log.exception("validate/pair failed: %r" % exx)
            c.audit['info'] = unicode(exx)
            Session.rollback()
            return sendResult(response, False, 0, status=False)

        finally:
            Session.close()
Esempio n. 49
0
    def checkUserPass(self, user, passw, options=None):
        """
        :param user: the to be identified user
        :param passw: the identification pass
        :param options: optional parameters, which are provided
                    to the token checkOTP / checkPass

        :return: tuple of True/False and optional information
        """

        # the upper layer will catch / at least should ;-)

        opt = None
        serial = None
        resolverClass = None
        uid = None
        audit = context['audit']
        user_exists = False

        if user is not None and not user.is_empty:
            # the upper layer will catch / at least should
            try:
                (uid, _resolver, resolverClass) = getUserId(
                                                    user, check_existance=True)
                user_exists = True
            except Exception as _exx:
                pass_on = context.get('Config').get(
                    'linotp.PassOnUserNotFound', False)
                if pass_on and 'true' == pass_on.lower():
                    audit['action_detail'] = (
                        'authenticated by PassOnUserNotFound')
                    return (True, opt)
                else:
                    audit['action_detail'] = 'User not found'
                    return (False, opt)

        # if we have an user, check if we forward the request to another server
        if user_exists and get_auth_forward_on_no_token(user) is False:
            servers = get_auth_forward(user)
            if servers:
                res, opt = ForwardServerPolicy.do_request(servers, env,
                                                          user, passw, options)
                return res, opt

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

        th = TokenHandler()

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

        # auto asignement with otp only if user has no active token

        auto_assign_otp_return = th.auto_assign_otp_only(
                                                    otp=passw,
                                                    user=user,
                                                    options=options)

        if auto_assign_otp_return is True:
            return (True, None)

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

        token_type = None
        if options:
            token_type = options.get('token_type', None)

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

        # if there is a serial provided in the parameters, it overwrites the
        # token selection by user

        query_user = user
        if options and 'serial' in  options and options['serial']:
            serial = options['serial']
            query_user = None

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

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

        if len(tokenList) == 0:
            audit['action_detail'] = 'User has no tokens assigned'

            # here we check if we should to autoassign and try to do it
            auto_assign_return = th.auto_assignToken(passw, user)
            if auto_assign_return is True:
                # We can not check the token, as the OTP value is already used!
                # but we will auth the user....
                return (True, opt)

            auto_enroll_return, opt = th.auto_enrollToken(passw, user,
                                                          options=options)
            if auto_enroll_return is True:
                # we always have to return a false, as
                # we have a challenge tiggered
                return (False, opt)

            pass_on = context.get('Config').get('linotp.PassOnUserNoToken',
                                                False)
            if pass_on and 'true' == pass_on.lower():
                audit['action_detail'] = 'authenticated by PassOnUserNoToken'
                return (True, opt)

            # Check if there is an authentication policy passthru

            if get_auth_passthru(user):
                log.debug('user %r has no token. Checking for '
                          'passthru in realm %r' % (user.login, user.realm))
                y = getResolverObject(resolverClass)
                audit['action_detail'] = 'Authenticated against Resolver'
                if y.checkPass(uid, passw):
                    return (True, opt)

            # Check alternatively if there is an authentication
            # policy passOnNoToken
            elif get_auth_passOnNoToken(user):
                log.info('user %r has not token. PassOnNoToken'
                         ' set - authenticated!')
                audit['action_detail'] = (
                    'Authenticated by passOnNoToken policy')
                return (True, opt)

            # if we have an user, check if we forward the request to another server
            elif get_auth_forward_on_no_token(user) is True:
                servers = get_auth_forward(user)
                if servers:
                    res, opt = ForwardServerPolicy.do_request(
                                            servers, env, user, passw, options)
                    return res, opt

            return False, opt

        if passw is None:
            raise ParameterError(u"Missing parameter:pass", id=905)

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

        return (res, opt)
Esempio n. 50
0
    def __init__(self, user, serial, page=None, psize=None, filter=None,
                 sort=None, sortdir=None, filterRealm=None, user_fields=None,
                 params=None):
        '''
        constructor of Tokeniterator, which gathers all conditions to build
        a sqalchemy query - iterator

        :param user:     User object - user provides as well the searchfield
                                       entry
        :type  user:     User class
        :param serial:   serial number of a token
        :type  serial:   string
        :param page:     page number
        :type  page:     int
        :param psize:    how many entries per page
        :type  psize:    int
        :param filter:   additional condition
        :type  filter:   string
        :param sort:     sort field definition
        :type  sort:     string
        :param sortdir:  sort direction: ascending or descending
        :type  sortdir:  string
        :param filterRealm:  restrict the set of token to those in
                             the filterRealm
        :type  filterRealm:  string or list
        :param user_fields:  list of additional fields from the user owner
        :type  user_fields: array
        :param params:  list of additional request parameters
                        - currently not used
        :type  params: dict

        :return: - nothing / None

        '''
        log.debug('[TokenIterator::init] begin. start creating TokenIterator \
        class with parameters: user:%r, serial:%r, page=%r, psize:%r, \
                    filter:%r, sort:%r, sortdir:%r, filterRealm:%r' %
                (user, serial, page, psize, filter, sort, sortdir,
                 filterRealm))

        if params is None:
            params = {}

        self.page = 1
        self.pages = 1
        self.tokens = 0
        self.user_fields = user_fields
        if self.user_fields == None:
            self.user_fields = []

        condition = None
        ucondition = None
        scondition = None
        r_condition = None

        if type(filterRealm) in (str, unicode):
            filterRealm = filterRealm.split(',')

        if type(filterRealm) in [list]:
            s_realms = []
            for f in filterRealm:
                #  support for multiple realm filtering in the ui
                #  as a coma separated string
                for s_realm in f.split(','):
                    s_realms.append(s_realm.strip())
            filterRealm = s_realms

        #  create a list of all realms, which are allowed to be searched
        #  based on the list of the existing ones
        valid_realms = []
        realms = getRealms().keys()
        if '*' in filterRealm:
            valid_realms.append("*")
        else:
            for realm in realms:
                if realm in filterRealm:
                    realm = linotp.lib.crypt.uencode(realm)
                    valid_realms.append(realm)

        if serial is not None:
            #  check if the requested serial is in the realms of
            # the admin (filterRealm)
            log.debug('[TokenIterator::init] start search for serial: >%r<'
                       % (serial))

            allowed = False
            if filterRealm == ['*']:
                allowed = True
            else:
                realms = getTokenRealms(serial)
                for realm in realms:
                    if realm in filterRealm:
                        allowed = True

            if allowed == True:
                if '*' in serial:
                    serial = serial.replace('*', '%')
                    scondition = and_(Token.LinOtpTokenSerialnumber.like(serial))
                else:
                    scondition = and_(Token.LinOtpTokenSerialnumber == serial)

        if user.isEmpty() == False and user is not None:
            log.debug('[TokenIterator::init] start search for username: >%r<'
                      % (user))

            if user.login is not None and (user.login) > 0 :
                loginUser = user.login.lower()
                loginUser = loginUser.replace('"', '')
                loginUser = loginUser.replace("'", '')

                searchType = "any"

                #  search for a 'blank' user
                if len(loginUser) == 0 and len(user.login) > 0:
                    searchType = "blank"
                elif loginUser == "/:no user:/" or loginUser == "/:none:/":
                    searchType = "blank"
                elif loginUser == "/:no user info:/":
                    searchType = "wildcard"
                elif "*" in loginUser or "." in loginUser:
                    searchType = "wildcard"
                else:
                    #  no blank and no wildcard search
                    searchType = "exact"

                if searchType == "blank":
                    log.debug('[TokenIterator::init] search for empty user:'******' >%r<' % (user.login))
                    ucondition = and_(or_(Token.LinOtpUserid == u'',
                                          Token.LinOtpUserid == None))

                if searchType == "exact":
                    log.debug('[TokenIterator::init] search for exact user:'******' %r' % (user))
                    serials = []
                    users = []

                    #  if search for a realmuser 'user@realm' we can take the
                    #  realm from the argument
                    if len(user.realm) > 0:
                        users.append(user)
                    else:
                        for realm in valid_realms:
                            users.append(User(user.login, realm))

                    # resolve the realm with wildcard:
                    # identify all users and add these to the userlist
                    userlist = []
                    for usr in users:
                        urealm = usr.realm
                        if urealm == '*':
                            # if the realm is set to *, the getUserId
                            # triggers the identification of all resolvers,
                            # where the user might reside: tigger the user
                            # resolver lookup
                            (uid, resolver, resolverClass) = getUserId(usr)
                            userlist.extend(usr.getUserPerConf())
                        else:
                            userlist.append(usr)

                    for usr in userlist:
                        try:
                            tokens = getTokens4UserOrSerial(user=usr, _class=False)
                            for tok in tokens:
                                serials.append(tok.LinOtpTokenSerialnumber)
                        except UserError as ex:
                            #  we get an exception if the user is not found
                            log.debug('[TokenIterator::init] no exact user: %r'
                                      % (user))
                            log.debug('[TokenIterator::init] %r' % ex)

                    if len(serials) > 0:
                        #  if tokens found, search for their serials
                        ucondition = and_(Token.LinOtpTokenSerialnumber.in_(serials))
                    else:
                        #  if no token is found, block search for user
                        #  and return nothing
                        ucondition = and_(or_(Token.LinOtpUserid == u'',
                                              Token.LinOtpUserid == None))

                #  handle case, when nothing found in former cases
                if searchType == "wildcard":
                    log.debug('[TokenIterator::init] wildcard search: %r' % (user))
                    serials = []
                    users = getAllTokenUsers()
                    logRe = None
                    lU = loginUser.replace('*', '.*')
                    # lU = lU.replace('..', '.')
                    logRe = re.compile(lU)

                    for ser in users:
                        userInfo = users.get(ser)
                        tokenUser = userInfo.get('username').lower()
                        try:
                            if logRe.match(u'' + tokenUser) is not None:
                                serials.append(ser)
                        except Exception as e:
                            log.error('error no express %r ' % e)

                    #  to prevent warning, we check is serials are found
                    #  SAWarning: The IN-predicate on
                    #  "Token.LinOtpTokenSerialnumber" was invoked with an
                    #  empty sequence. This results in a contradiction, which
                    #  nonetheless can be expensive to evaluate.  Consider
                    #  alternative strategies for improved performance.
                    if len(serials) > 0:
                        ucondition = and_(Token.LinOtpTokenSerialnumber.in_(serials))
                    else:
                        ucondition = and_(or_(Token.LinOtpUserid == u'',
                                              Token.LinOtpUserid == None))

        if filter is None:
            condition = None
        elif filter in ['/:active:/', '/:enabled:/',
                        '/:token is active:/', '/:token is enabled:/' ]:
            condition = and_(Token.LinOtpIsactive == True)
        elif filter in ['/:inactive:/', '/:disabled:/',
                        '/:token is inactive:/', '/:token is disabled:/']:
            condition = and_(Token.LinOtpIsactive == False)
        else:
            #  search in other colums
            filter = linotp.lib.crypt.uencode(filter)
            condition = or_(Token.LinOtpTokenDesc.contains(filter),
                            Token.LinOtpIdResClass.contains(filter),
                            Token.LinOtpTokenSerialnumber.contains(filter),
                            Token.LinOtpUserid.contains(filter),
                            Token.LinOtpTokenType.contains(filter))

        ###################################################################
        #   The condition for only getting certain realms!
        if '*' in valid_realms:
            log.debug("[TokenIterator::init] wildcard for realm '*' found."
                      " Tokens of all realms will be displayed")
        elif len(valid_realms) > 0:
            log.debug("[TokenIterator::init] adding filter condition"
                      " for realm %r" % valid_realms)

            #  get all matching realms
            realm_id_tuples = Session.query(Realm.id).\
                                filter(Realm.name.in_(valid_realms)).all()
            realm_ids = set()
            for realm_tuple in realm_id_tuples:
                realm_ids.add(realm_tuple[0])
            #  get all tokenrealm ids
            token_id_tuples = Session.query(TokenRealm.token_id).\
                        filter(TokenRealm.realm_id.in_(realm_ids)).all()
            token_ids = set()
            for token_tuple in token_id_tuples:
                token_ids.add(token_tuple[0])

            #  define the token id condition
            r_condition = and_(Token.LinOtpTokenId.in_(token_ids))

        elif ("''" in filterRealm or '""' in filterRealm or
              "/:no realm:/" in filterRealm):
            log.debug("[TokenIterator::init] search for all tokens, which are"
                      " in no realm")

            #  get all tokenrealm ids
            token_id_tuples = Session.query(TokenRealm.token_id).all()
            token_ids = set()
            for token_tuple in token_id_tuples:
                token_ids.add(token_tuple[0])

            #  define the token id not condition
            r_condition = and_(not_(Token.LinOtpTokenId.in_(token_ids)))

        #  create the final condition as AND of all conditions
        condTuple = ()
        for conn in (condition, ucondition, scondition, r_condition):
            if type(conn).__name__ != 'NoneType':
                condTuple += (conn,)

        condition = and_(*condTuple)

        order = Token.LinOtpTokenDesc

        if sort == "TokenDesc":
            order = Token.LinOtpTokenDesc
        elif sort == "TokenId":
            order = Token.LinOtpTokenId
        elif sort == "TokenType":
            order = Token.LinOtpTokenType
        elif sort == "TokenSerialnumber":
            order = Token.LinOtpTokenSerialnumber
        elif sort == "TokenType":
            order = Token.LinOtpTokenType
        elif sort == "IdResClass":
            order = Token.LinOtpIdResClass
        elif sort == "IdResolver":
            order = Token.LinOtpIdResolver
        elif sort == "Userid":
            order = Token.LinOtpUserid
        elif sort == "FailCount":
            order = Token.LinOtpFailCount
        elif sort == "Userid":
            order = Token.LinOtpUserid
        elif sort == "Isactive":
            order = Token.LinOtpIsactive

        #  care for the result sort order
        if sortdir is not None and sortdir == "desc":
            order = order.desc()
        else:
            order = order.asc()

        #  care for the result pageing
        if page is None:
            self.toks = Session.query(Token).filter(condition).order_by(order).distinct()
            self.tokens = self.toks.count()

            log.debug("[TokenIterator] DB-Query returned # of objects:"
                      " %i" % self.tokens)
            self.pagesize = self.tokens
            self.it = iter(self.toks)
            return

        try:
            if psize is None:
                pagesize = int(getFromConfig("pagesize", 50))
            else:
                pagesize = int(psize)
        except:
            pagesize = 20

        try:
            thePage = int (page) - 1
        except:
            thePage = 0
        if thePage < 0:
            thePage = 0

        start = thePage * pagesize
        stop = (thePage + 1) * pagesize

        self.toks = Session.query(Token).filter(condition).\
                                         order_by(order).distinct()
        self.tokens = self.toks.count()
        log.debug("[TokenIterator::init] DB-Query returned # of objects:"
                  " %i" % self.tokens)
        self.page = thePage + 1
        fpages = float(self.tokens) / float(pagesize)
        self.pages = int(fpages)
        if fpages - int(fpages) > 0:
            self.pages = self.pages + 1
        self.pagesize = pagesize
        self.toks = self.toks.slice(start, stop)

        self.it = iter(self.toks)

        log.debug('[TokenIterator::init] end. Token iterator created: %r' % \
                  (self.it))

        return
Esempio n. 51
0
    def check_s(self):
        """
        This function is used to validate the serial and the otp value/password.
        If the otppin policy is set, the endpoint /validate/check_s does not work.

        method:
            validate/check_s

        arguments:
            * serial:  the serial number of the token
            * pass:    the password that consists of a possible fixes password component
                        and the OTP value

        returns:
            JSON response
        """
        param = self.request_params

        options = {}
        options.update(param)
        for k in ["user", "serial", "pass", "init"]:
            if k in options:
                del options[k]

        try:
            passw = param.get("pass")
            serial = param.get("serial")
            if serial is None:
                user = param.get("user")
                if user is not None:
                    user = getUserFromParam(param)
                    toks = getTokens4UserOrSerial(user=user)
                    if len(toks) == 0:
                        raise Exception("No token found!")
                    elif len(toks) > 1:
                        raise Exception("More than one token found!")
                    else:
                        tok = toks[0].token
                        desc = tok.get()
                        realms = desc.get("LinOtp.RealmNames")
                        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
                        )

                        serial = tok.getSerial()

            g.audit["serial"] = serial

            options["scope"] = {"check_s": True}
            vh = ValidationHandler()
            (ok, opt) = vh.checkSerialPass(serial, passw, options=options)
            g.audit["success"] = ok
            db.session.commit()

            qr = param.get("qr", None)
            if qr and opt and "message" in opt:
                try:
                    dataobj = opt.get("message")
                    param["alt"] = "%s" % opt
                    if "transactionid" in opt:
                        param["transactionid"] = opt["transactionid"]
                    return sendQRImageResult(response, dataobj, param)
                except Exception as exc:
                    log.warning("failed to send QRImage: %r ", exc)
                    return sendQRImageResult(response, opt, param)
            else:
                return sendResult(response, ok, 0, opt=opt)

        except Exception as exx:
            log.error("[check_s] validate/check_s failed: %r", exx)
            g.audit["info"] = str(exx)
            db.session.rollback()
            return sendResult(response, False, id=0, status=False)
Esempio n. 52
0
    def _get_user_condition(self, user, valid_realms):

        ucondition = None
        log.debug('[TokenIterator::init] start search for username: >%r<'
                  % (user))

        if not user or user.isEmpty() or not user.login:
            return ucondition

        loginUser = user.login.lower()
        loginUser = loginUser.replace('"', '')
        loginUser = loginUser.replace("'", '')

        searchType = "any"
        ## search for a 'blank' user
        if len(loginUser) == 0 and len(user.login) > 0:
            searchType = "blank"
        elif loginUser == "/:no user:/" or loginUser == "/:none:/":
            searchType = "blank"
        elif loginUser == "/:no user info:/":
            searchType = "wildcard"
        elif "*" in loginUser or "." in loginUser:
            searchType = "wildcard"
        else:
            ## no blank and no wildcard search
            searchType = "exact"

        if searchType == "blank":
            log.debug('[TokenIterator::init] search for empty user: >%r<' % (user.login))
            ucondition = and_(or_(Token.LinOtpUserid == u'',
                                  Token.LinOtpUserid is None))

        if searchType == "exact":
            log.debug('[TokenIterator::init] search for exact user: %r' % (user))
            serials = []
            users = []

            ## if search for a realmuser 'user@realm' we can take the
            ## realm from the argument
            if len(user.realm) > 0:
                users.append(user)
            else:
                for realm in valid_realms:
                    users.append(User(user.login, realm))

            # resolve the realm with wildcard:
            # identify all users and add these to the userlist
            userlist = []
            for usr in users:
                urealm = usr.realm
                if urealm == '*':
                    # if the realm is set to *, the getUserId
                    # triggers the identification of all resolvers, where the
                    # user might reside: tigger the user resolver lookup
                    (uid, resolver, resolverClass) = getUserId(usr)
                    userlist.extend(usr.getUserPerConf())
                else:
                    userlist.append(usr)

            for usr in userlist:
                try:
                    tokens = getTokens4UserOrSerial(user=usr, _class=False)
                    for tok in tokens:
                        serials.append(tok.LinOtpTokenSerialnumber)
                except UserError as ex:
                    ## we get an exception if the user is not found
                    log.debug('[TokenIterator::init] no exact user: %r'
                              % (user))
                    log.debug('[TokenIterator::init] %r' % ex)

            if len(serials) > 0:
                # if tokens found, search for their serials
                ucondition = and_(Token.LinOtpTokenSerialnumber.in_(serials))
            else:
                # if no token is found, block search for user
                # and return nothing
                ucondition = and_(Token.LinOtpTokenSerialnumber == u'')

        ## handle case, when nothing found in former cases
        if searchType == "wildcard":
            log.debug('[TokenIterator::init] wildcard search: %r' % (user))
            serials = []
            users = getAllTokenUsers()
            logRe = None
            lU = loginUser.replace('*', '.*')
            #lU = lU.replace('..', '.')
            logRe = re.compile(lU)

            for ser in users:
                userInfo = users.get(ser)
                tokenUser = userInfo.get('username').lower()
                try:
                    if logRe.match(u'' + tokenUser) is not None:
                        serials.append(ser)
                except Exception as e:
                    log.error('error no express %r ' % e)

            ## to prevent warning, we check is serials are found
            ## SAWarning: The IN-predicate on
            ## "Token.LinOtpTokenSerialnumber" was invoked with an
            ## empty sequence. This results in a contradiction, which
            ## nonetheless can be expensive to evaluate.  Consider
            ## alternative strategies for improved performance.
            if len(serials) > 0:
                ucondition = and_(Token.LinOtpTokenSerialnumber.in_(serials))
            else:
                ucondition = and_(Token.LinOtpTokenSerialnumber == u'')
        return ucondition
Esempio n. 53
0
    def checkUserPass(self, user, passw, options=None):
        """
        :param user: the to be identified user
        :param passw: the identification pass
        :param options: optional parameters, which are provided
                    to the token checkOTP / checkPass

        :return: tuple of True/False and optional information
        """

        # the upper layer will catch / at least should ;-)

        opt = None
        serial = None
        resolverClass = None
        uid = None
        user_exists = False

        if user is not None and not user.is_empty:
            # the upper layer will catch / at least should
            try:
                (uid, _resolver, resolverClass) = getUserId(
                                                    user, check_existance=True)
                user_exists = True
            except Exception as _exx:
                pass_on = context.get('Config').get(
                    'linotp.PassOnUserNotFound', False)
                if pass_on and 'true' == pass_on.lower():
                    g.audit['action_detail'] = (
                        'authenticated by PassOnUserNotFound')
                    return (True, opt)
                else:
                    g.audit['action_detail'] = 'User not found'
                    return (False, opt)

        # if we have an user, check if we forward the request to another server
        if user_exists and get_auth_forward_on_no_token(user) is False:
            servers = get_auth_forward(user)
            if servers:
                res, opt = ForwardServerPolicy.do_request(servers, env,
                                                          user, passw, options)
                return res, opt

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

        th = TokenHandler()

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

        # auto asignement with otp only if user has no active token

        auto_assign_otp_return = th.auto_assign_otp_only(
                                                    otp=passw,
                                                    user=user,
                                                    options=options)

        if auto_assign_otp_return is True:
            return (True, None)

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

        token_type = None
        if options:
            token_type = options.get('token_type', None)

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

        # if there is a serial provided in the parameters, it overwrites the
        # token selection by user

        query_user = user
        if options and 'serial' in  options and options['serial']:
            serial = options['serial']
            query_user = None

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

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

        if len(tokenList) == 0:
            g.audit['action_detail'] = 'User has no tokens assigned'

            # here we check if we should to autoassign and try to do it
            auto_assign_return = th.auto_assignToken(passw, user)
            if auto_assign_return is True:
                # We can not check the token, as the OTP value is already used!
                # but we will auth the user....
                return (True, opt)

            auto_enroll_return, opt = th.auto_enrollToken(passw, user,
                                                          options=options)
            if auto_enroll_return is True:
                # we always have to return a false, as
                # we have a challenge tiggered
                return (False, opt)

            pass_on = context.get('Config').get('linotp.PassOnUserNoToken',
                                                False)
            if pass_on and 'true' == pass_on.lower():
                g.audit['action_detail'] = 'authenticated by PassOnUserNoToken'
                return (True, opt)

            # Check if there is an authentication policy passthru

            if get_auth_passthru(user):
                log.debug('user %r has no token. Checking for '
                          'passthru in realm %r' % (user.login, user.realm))
                y = getResolverObject(resolverClass)
                g.audit['action_detail'] = 'Authenticated against Resolver'
                if y.checkPass(uid, passw):
                    return (True, opt)

            # Check alternatively if there is an authentication
            # policy passOnNoToken
            elif get_auth_passOnNoToken(user):
                log.info('user %r has not token. PassOnNoToken'
                         ' set - authenticated!')
                g.audit['action_detail'] = (
                    'Authenticated by passOnNoToken policy')
                return (True, opt)

            # if we have an user, check if we forward the request to another server
            elif get_auth_forward_on_no_token(user) is True:
                servers = get_auth_forward(user)
                if servers:
                    res, opt = ForwardServerPolicy.do_request(
                                            servers, env, user, passw, options)
                    return res, opt

            return False, opt

        if passw is None:
            raise ParameterError("Missing parameter:pass", id=905)

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

        return (res, opt)
Esempio n. 54
0
    def pair(self):
        """
        validate/pair: for the enrollment of qr and push token
        """

        try:

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

            enc_response = self.request_params.get("pairing_response")

            if enc_response is None:
                raise Exception("Parameter missing")

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

            dec_response = decrypt_pairing_response(enc_response)
            token_type = dec_response.token_type
            pairing_data = dec_response.pairing_data

            if (
                not hasattr(pairing_data, "serial")
                or pairing_data.serial is None
            ):

                raise ValidateError(
                    "Pairing responses with no serial attached"
                    " are currently not implemented."
                )

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

            # TODO: pairing policy
            tokens = getTokens4UserOrSerial(None, pairing_data.serial)

            if not tokens:
                raise Exception("Invalid serial in pairing response")

            if len(tokens) > 1:
                raise Exception("Multiple tokens found. Pairing not possible")

            token = tokens[0]

            # prepare some audit entries
            t_owner = token.getUser()

            realms = token.getRealms()
            realm = ""
            if realms:
                realm = realms[0]

            g.audit["user"] = t_owner or ""
            g.audit["realm"] = realm

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

            if token.type != token_type:
                raise Exception(
                    "Serial in pairing response doesn't match "
                    "supplied token_type"
                )

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

            token.pair(pairing_data)
            g.audit["success"] = 1
            g.audit["serial"] = token.getSerial()

            db.session.commit()
            return sendResult(response, False)

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

        except Exception as exx:
            log.error("validate/pair failed: %r", exx)
            g.audit["info"] = str(exx)
            db.session.rollback()
            return sendResult(response, False, 0, status=False)