예제 #1
0
    def check_serial_wrapper(*args, **kwds):
        tokenobject_list_from = get_tokens(serial=args[0])
        tokenobject_list_to = get_tokens(serial=args[1])
        if len(tokenobject_list_from) != 1:
            log.error("not a unique token to copy from found")
            raise (TokenAdminError("No unique token to copy from found",
                                   id=1016))
        if len(tokenobject_list_to) != 1:
            log.error("not a unique token to copy to found")
            raise (TokenAdminError("No unique token to copy to found",
                                   id=1017))

        f_result = func(*args, **kwds)
        return f_result
예제 #2
0
    def get_init_detail(self, params=None, user=None):
        """
        At the end of the initialization we ask the user to press the button
        """
        response_detail = {}
        if self.init_step == 1:
            # This is the first step of the init request
            app_id = get_from_config("u2f.appId", "").strip("/")
            from privacyidea.lib.error import TokenAdminError
            if not app_id:
                raise TokenAdminError(
                    _("You need to define the appId in the "
                      "token config!"))
            nonce = url_encode(geturandom(32))
            response_detail = TokenClass.get_init_detail(self, params, user)
            register_request = {
                "version": U2F_Version,
                "challenge": nonce,
                "appId": app_id
            }
            response_detail["u2fRegisterRequest"] = register_request
            self.add_tokeninfo("appId", app_id)

        elif self.init_step == 2:
            # This is the second step of the init request
            response_detail["u2fRegisterResponse"] = {
                "subject": self.token.description
            }

        return response_detail
예제 #3
0
    def update(self, param):
        """
        This method is called during the initialization process.

        :param param: parameters from the token init
        :type param: dict
        :return: None
        """
        j_questions = getParam(param, "questions", required)
        try:
            # If we have a string, we load the json format
            questions = json.loads(j_questions)
        except TypeError:
            # Obviously we have a dict...
            questions = j_questions
        num_answers = get_from_config("question.num_answers",
                                      DEFAULT_NUM_ANSWERS)
        if len(questions) < int(num_answers):
            raise TokenAdminError(
                _("You need to provide at least %s "
                  "answers.") % num_answers)
        # Save all questions and answers and encrypt them
        for question, answer in questions.iteritems():
            self.add_tokeninfo(question, answer, value_type="password")
        TokenClass.update(self, param)
예제 #4
0
def lost_api(serial=None):
    """
    Mark the specified token as lost and create a new temporary token.
    This new token gets the new serial number "lost<old-serial>" and
    a certain validity period and the PIN of the lost token.

    This method can be called by either the admin or the user on his own tokens.

    You can call the function like this:
        POST /token/lost/serial

    :jsonparam basestring serial: the serial number of the lost token.
    :return: returns value=dictionary in case of success
    :rtype: bool
    """
    # check if a user is given, that the user matches the token owner.
    g.audit_object.log({"serial": serial})
    userobj = get_user_from_param(request.all_data)
    if userobj:
        toks = get_tokens(serial=serial, user=userobj)
        if not toks:
            raise TokenAdminError(
                "The user {0!s} does not own the token {1!s}".format(
                    userobj, serial))

    options = {"g": g, "clientip": g.client_ip}
    res = lost_token(serial, options=options)

    g.audit_object.log({"success": True})
    return send_result(res)
예제 #5
0
    def get_init_detail(self, params=None, user=None):
        """
        At the end of the initialization we ask the user to press the button
        """
        response_detail = {}
        # get_init_details runs after "update" method. So in the first step clientwait has already been set
        if self.token.rollout_state == ROLLOUTSTATE.CLIENTWAIT:
            # This is the first step of the init request
            app_id = get_from_config("u2f.appId", "").strip("/")
            from privacyidea.lib.error import TokenAdminError
            if not app_id:
                raise TokenAdminError(
                    _("You need to define the appId in the "
                      "token config!"))
            nonce = url_encode(geturandom(32))
            response_detail = TokenClass.get_init_detail(self, params, user)
            register_request = {
                "version": U2F_Version,
                "challenge": nonce,
                "appId": app_id
            }
            response_detail["u2fRegisterRequest"] = register_request
            self.add_tokeninfo("appId", app_id)

        elif self.token.rollout_state == "":
            # This is the second step of the init request, the clientwait rollout state has been reset
            response_detail["u2fRegisterResponse"] = {
                "subject": self.token.description
            }

        return response_detail
예제 #6
0
def setrandompin_api(serial=None):
    """
    Set the OTP PIN for a specific token to a random value.

    The token is identified by the unique serial number.

    :jsonparam basestring serial: the serial number of the single
        token to reset
    :return: In "value" returns the number of PINs set.
        The detail-section contains the key "pin" with the set PIN.
    :rtype: json object
    """
    if not serial:
        serial = getParam(request.all_data, "serial", required)
    g.audit_object.log({"serial": serial})
    user = request.User
    encrypt_pin = getParam(request.all_data, "encryptpin")
    pin = getParam(request.all_data, "pin")
    if not pin:
        raise TokenAdminError("We have an empty PIN. Please check your policy 'otp_pin_set_random'.")

    g.audit_object.add_to_log({'action_detail': "otppin, "})
    res = set_pin(serial, pin, user=user, encrypt_pin=encrypt_pin)
    g.audit_object.log({"success": True})
    return send_result(res, details={"pin": pin})
예제 #7
0
 def token_locked_wrapper(*args, **kwds):
     # The token object
     token = args[0]
     if token.is_locked():
         raise TokenAdminError(_("This action is not possible, since the "
                                 "token is locked"), id=1007)
     f_result = func(*args, **kwds)
     return f_result
예제 #8
0
def check_subscription(request, action):
    """
    Check if another token is allowed to be enrolled or assigned.
    It check if the total assigned tokens exceed the subscription count.
    Raises a TokenAdminError, if exceeded.
    """
    # get the number of assigned tokens
    token_count = get_tokens(assigned=True, count=True)
    subscription = get_subscription()
    subscription_count = subscription.get("subscription")

    # The subscription_count==0 means unlimited users
    if subscription_count >= 0:
        check_signature(subscription)

    if subscription_count != 0 and token_count >= subscription_count:
            raise TokenAdminError("Subscription limit exceeded. You are only "
                                  "entitled to assign %s tokens to users."
                                  " Please contact NetKnights for a subscription!" %
                                  subscription_count, id=34131)
예제 #9
0
def loadtokens_api(filename=None):
    """
    The call imports the given file containing token definitions.
    The file can be an OATH CSV file, an aladdin XML file or a Yubikey CSV file
    exported from the yubikey initialization tool.

    The function is called as a POST request with the file upload.

    :jsonparam filename: The name of the token file, that is imported
    :jsonparam type: The file type. Can be "aladdin-xml",
        "oathcsv" or "yubikeycsv".
    :jsonparam tokenrealms: comma separated list of tokens.
    :jsonparam psk: Pre Shared Key, when importing PSKC
    :return: The number of the imported tokens
    :rtype: int
    """
    if not filename:
        filename = getParam(request.all_data, "filename", required)
    known_types = [
        'aladdin-xml', 'oathcsv', "OATH CSV", 'yubikeycsv', 'Yubikey CSV',
        'pskc'
    ]
    file_type = getParam(request.all_data, "type", required)
    hashlib = getParam(request.all_data, "aladdin_hashlib")
    aes_psk = getParam(request.all_data, "psk")
    aes_password = getParam(request.all_data, "password")
    if aes_psk and len(aes_psk) != 32:
        raise TokenAdminError("The Pre Shared Key must be 128 Bit hex "
                              "encoded. It must be 32 characters long!")
    trealms = getParam(request.all_data, "tokenrealms") or ""
    tokenrealms = []
    if trealms:
        tokenrealms = trealms.split(",")

    TOKENS = {}
    token_file = request.files['file']
    file_contents = ""
    # In case of form post requests, it is a "instance" of FieldStorage
    # i.e. the Filename is selected in the browser and the data is
    # transferred
    # in an iframe. see: http://jquery.malsup.com/form/#sample4
    #
    if type(token_file) == FieldStorage:  # pragma: no cover
        log.debug("Field storage file: %s", token_file)
        file_contents = token_file.value
    elif type(token_file) == FileStorage:
        log.debug("Werkzeug File storage file: %s", token_file)
        file_contents = token_file.read()
    else:  # pragma: no cover
        file_contents = token_file

    if file_contents == "":
        log.error(
            "Error loading/importing token file. file {0!s} empty!".format(
                filename))
        raise ParameterError("Error loading token file. File empty!")

    if file_type not in known_types:
        log.error(
            "Unknown file type: >>{0!s}<<. We only know the types: {1!s}".
            format(file_type, ', '.join(known_types)))
        raise TokenAdminError("Unknown file type: >>%s<<. We only know the "
                              "types: %s" %
                              (file_type, ', '.join(known_types)))

    # Decrypt file, if necessary
    if file_contents.startswith("-----BEGIN PGP MESSAGE-----"):
        GPG = GPGImport(current_app.config)
        file_contents = GPG.decrypt(file_contents)

    # Parse the tokens from file and get dictionary
    if file_type == "aladdin-xml":
        TOKENS = parseSafeNetXML(file_contents)
    elif file_type in ["oathcsv", "OATH CSV"]:
        TOKENS = parseOATHcsv(file_contents)
    elif file_type in ["yubikeycsv", "Yubikey CSV"]:
        TOKENS = parseYubicoCSV(file_contents)
    elif file_type in ["pskc"]:
        TOKENS = parsePSKCdata(file_contents,
                               preshared_key_hex=aes_psk,
                               password=aes_password)

    # Now import the Tokens from the dictionary
    ret = ""
    for serial in TOKENS:
        log.debug("importing token {0!s}".format(TOKENS[serial]))

        log.info("initialize token. serial: {0!s}, realm: {1!s}".format(
            serial, tokenrealms))

        init_param = {
            'serial': serial,
            'type': TOKENS[serial]['type'],
            'description': TOKENS[serial].get("description", "imported"),
            'otpkey': TOKENS[serial]['otpkey'],
            'otplen': TOKENS[serial].get('otplen'),
            'timeStep': TOKENS[serial].get('timeStep'),
            'hashlib': TOKENS[serial].get('hashlib')
        }

        if hashlib and hashlib != "auto":
            init_param['hashlib'] = hashlib

        #if tokenrealm:
        #    self.Policy.checkPolicyPre('admin', 'loadtokens',
        #                   {'tokenrealm': tokenrealm })

        init_token(init_param, tokenrealms=tokenrealms)

    g.audit_object.log({
        'info':
        "{0!s}, {1!s} (imported: {2:d})".format(file_type, token_file,
                                                len(TOKENS)),
        'serial':
        ', '.join(TOKENS.keys())
    })
    # logTokenNum()

    return send_result(len(TOKENS))
예제 #10
0
def loadtokens_api(filename=None):
    """
    The call imports the given file containing token definitions.
    The file can be an OATH CSV file, an aladdin XML file or a Yubikey CSV file
    exported from the yubikey initialization tool.

    The function is called as a POST request with the file upload.

    :jsonparam basestring filename: The name of the token file, that is imported
    :jsonparam basestring type: The file type. Can be "aladdin-xml",
        "oathcsv" or "yubikeycsv".
    :jsonparam basestring tokenrealms: comma separated list of tokens.
    :return: The number of the imported tokens
    :rtype: int
    """
    if not filename:
        filename = getParam(request.all_data, "filename", required)
    known_types = [
        'aladdin-xml', 'oathcsv', "OATH CSV", 'yubikeycsv', 'Yubikey CSV',
        'pskc'
    ]
    file_type = getParam(request.all_data, "type", required)
    hashlib = getParam(request.all_data, "aladdin_hashlib")
    trealms = getParam(request.all_data, "tokenrealms") or ""
    tokenrealms = []
    if trealms:
        tokenrealms = trealms.split(",")

    TOKENS = {}
    token_file = request.files['file']
    file_contents = ""
    # In case of form post requests, it is a "instance" of FieldStorage
    # i.e. the Filename is selected in the browser and the data is
    # transferred
    # in an iframe. see: http://jquery.malsup.com/form/#sample4
    #
    if type(token_file) == FieldStorage:  # pragma: no cover
        log.debug("Field storage file: %s", token_file)
        file_contents = token_file.value
    elif type(token_file) == FileStorage:
        log.debug("Werkzeug File storage file: %s", token_file)
        file_contents = token_file.read()
    else:  # pragma: no cover
        file_contents = token_file

    if file_contents == "":
        log.error("Error loading/importing token file. file %s empty!" %
                  filename)
        raise ParameterError("Error loading token file. File empty!")

    if file_type not in known_types:
        log.error("Unknown file type: >>%s<<. We only know the types: %s" %
                  (file_type, ', '.join(known_types)))
        raise TokenAdminError("Unknown file type: >>%s<<. We only know the "
                              "types: %s" %
                              (file_type, ', '.join(known_types)))

    # Parse the tokens from file and get dictionary
    if file_type == "aladdin-xml":
        TOKENS = parseSafeNetXML(file_contents)
    elif file_type in ["oathcsv", "OATH CSV"]:
        TOKENS = parseOATHcsv(file_contents)
    elif file_type in ["yubikeycsv", "Yubikey CSV"]:
        TOKENS = parseYubicoCSV(file_contents)
    elif file_type in ["pskc"]:
        # At the moment we only process unencrypted data
        # TODO: We need to also parse encryption!
        TOKENS = parsePSKCdata(file_contents)

    # Now import the Tokens from the dictionary
    ret = ""
    for serial in TOKENS:
        log.debug("importing token %s" % TOKENS[serial])

        log.info("initialize token. serial: %s, realm: %s" %
                 (serial, tokenrealms))

        init_param = {
            'serial': serial,
            'type': TOKENS[serial]['type'],
            'description': TOKENS[serial].get("description", "imported"),
            'otpkey': TOKENS[serial]['otpkey'],
            'otplen': TOKENS[serial].get('otplen'),
            'timeStep': TOKENS[serial].get('timeStep'),
            'hashlib': TOKENS[serial].get('hashlib')
        }

        if hashlib and hashlib != "auto":
            init_param['hashlib'] = hashlib

        #if tokenrealm:
        #    self.Policy.checkPolicyPre('admin', 'loadtokens',
        #                   {'tokenrealm': tokenrealm })

        init_token(init_param, tokenrealms=tokenrealms)

    g.audit_object.log({
        'info':
        "%s, %s (imported: %i)" % (file_type, token_file, len(TOKENS)),
        'serial':
        ', '.join(TOKENS.keys())
    })
    # logTokenNum()

    return send_result(len(TOKENS))