예제 #1
0
def learn_from_result(result, node):
    from doorman.models import Node

    if not result['data']:
        return

    capture_columns = set(
        map(itemgetter(0),
            current_app.config['DOORMAN_CAPTURE_NODE_INFO']
        )
    )

    if not capture_columns:
        return

    node_info = node.get('node_info', {})
    orig_node_info = node_info.copy()

    for _, action, columns, _, in extract_results(result):
        # only update columns common to both sets
        for column in capture_columns & set(columns):
            if action == 'removed':
                node_info.pop(column, None)
            elif action == 'added':
                node_info[column] = columns.get(column)

    # only update node_info if there's actually a change

    if orig_node_info == node_info:
        return

    node = Node.get_by_id(node['id'])
    node.update(node_info=node_info)
    return
예제 #2
0
def learn_from_result(result, node):
    if not result['data']:
        return

    capture_columns = set(
        map(itemgetter(0), current_app.config['DOORMAN_CAPTURE_NODE_INFO']))

    if not capture_columns:
        return

    node_info = node.get('node_info', {})
    orig_node_info = node_info.copy()

    for _, action, columns, _, in extract_results(result):
        # only update columns common to both sets
        for column in capture_columns & set(columns):

            cvalue = node_info.get(column)  # current value
            value = columns.get(column)

            if action == 'removed' and (cvalue is None or cvalue != value):
                pass
            elif action == 'removed' and cvalue == value:
                node_info.pop(column)
            elif action == 'added' and (cvalue is None or cvalue != value):
                node_info[column] = value

    # only update node_info if there's actually a change

    if orig_node_info == node_info:
        return

    node = Node.get_by_id(node['id'])
    node.update(node_info=node_info)
    return
예제 #3
0
def enroll():
    '''
    Enroll an endpoint with osquery.

    :returns: a `node_key` unique id. Additionally `node_invalid` will
        be true if the node failed to enroll.
    '''
    request_json = request.get_json()
    if not request_json:
        current_app.logger.error(
            "%s - Request did not contain valid JSON data. This could "
            "be an attempt to gather information about this endpoint "
            "or an automated scanner.", request.remote_addr)
        # Return nothing
        return ""

    enroll_secret = request_json.get(
        current_app.config.get('DOORMAN_ENROLL_OVERRIDE', 'enroll_secret'))
    if not enroll_secret:
        current_app.logger.error(
            "%s - No enroll_secret provided by remote host",
            request.remote_addr)
        return jsonify(node_invalid=True)

    # If we pre-populate node table with a per-node enroll_secret,
    # let's query it now.

    if current_app.config.get('DOORMAN_ENROLL_SECRET_TAG_DELIMITER'):
        delimiter = current_app.config.get(
            'DOORMAN_ENROLL_SECRET_TAG_DELIMITER')
        enroll_secret, _, enroll_tags = enroll_secret.partition(delimiter)
        enroll_tags = set(
            [tag.strip() for tag in enroll_tags.split(delimiter)[:10]])
    else:
        enroll_secret, enroll_tags = enroll_secret, set()

    node = Node.query.filter(Node.enroll_secret == enroll_secret).first()

    if not node and enroll_secret not in current_app.config[
            'DOORMAN_ENROLL_SECRET']:
        current_app.logger.error("%s - Invalid enroll_secret %s",
                                 request.remote_addr, enroll_secret)
        return jsonify(node_invalid=True)

    host_identifier = request_json.get('host_identifier')

    if node and node.enrolled_on:
        current_app.logger.warn(
            "%s - %s already enrolled on %s, returning existing node_key",
            request.remote_addr, node, node.enrolled_on)

        if node.host_identifier != host_identifier:
            current_app.logger.info(
                "%s - %s changed their host_identifier to %s",
                request.remote_addr, node, host_identifier)
            node.host_identifier = host_identifier

        node.update(last_checkin=dt.datetime.utcnow(),
                    last_ip=request.remote_addr)

        return jsonify(node_key=node.node_key, node_invalid=False)

    existing_node = None
    if host_identifier:
        existing_node = Node.query.filter(
            Node.host_identifier == host_identifier).first()

    if existing_node and not existing_node.enroll_secret:
        current_app.logger.warning(
            "%s - Duplicate host_identifier %s, already enrolled %s",
            request.remote_addr, host_identifier, existing_node.enrolled_on)

        if current_app.config['DOORMAN_EXPECTS_UNIQUE_HOST_ID'] is True:
            current_app.logger.info(
                "%s - Unique host identification is true, %s already enrolled "
                "returning existing node key %s", request.remote_addr,
                host_identifier, existing_node.node_key)
            existing_node.update(last_checkin=dt.datetime.utcnow(),
                                 last_ip=request.remote_addr)
            return jsonify(node_key=existing_node.node_key, node_invalid=False)

    now = dt.datetime.utcnow()

    if node:
        node.update(host_identifier=host_identifier,
                    last_checkin=now,
                    enrolled_on=now,
                    last_ip=request.remote_addr)
    else:
        node = Node(host_identifier=host_identifier,
                    last_checkin=now,
                    enrolled_on=now,
                    last_ip=request.remote_addr)

        enroll_tags.update(
            current_app.config.get('DOORMAN_ENROLL_DEFAULT_TAGS', []))

        for value in sorted((t.strip() for t in enroll_tags if t)):
            tag = Tag.query.filter_by(value=value).first()
            if tag and tag not in node.tags:
                node.tags.append(tag)
            elif not tag:
                node.tags.append(Tag(value=value))

        node.save()

    current_app.logger.info("%s - Enrolled new node %s", request.remote_addr,
                            node)

    notify_of_node_enrollment.delay(node.to_dict())

    return jsonify(node_key=node.node_key, node_invalid=False)
예제 #4
0
def enroll():
    '''
    Enroll an endpoint with osquery.

    :returns: a `node_key` unique id. Additionally `node_invalid` will
        be true if the node failed to enroll.
    '''
    request_json = request.get_json()
    if not request_json:
        current_app.logger.error(
            "Request did not contain valid JSON data. This could be an "
            "attempt to gather information about this endpoint or an "
            "automated scanner.")
        # Return nothing
        return ""

    enroll_secret = request_json.get(
        current_app.config.get('DOORMAN_ENROLL_OVERRIDE', 'enroll_secret'))

    if not enroll_secret:
        current_app.logger.error("No enroll_secret provided by remote host %s",
                                 request.remote_addr)
        return jsonify(node_invalid=True)

    # If we pre-populate node table with a per-node enroll_secret,
    # let's query it now.

    node = Node.query.filter(Node.enroll_secret == enroll_secret).first()

    if not node and enroll_secret not in current_app.config[
            'DOORMAN_ENROLL_SECRET']:
        current_app.logger.error("Invalid enroll_secret %s", enroll_secret)
        return jsonify(node_invalid=True)

    host_identifier = request_json.get('host_identifier')

    if node and node.enrolled_on:
        current_app.logger.warn(
            "%s already enrolled on %s, returning "
            "existing node_key", node, node.enrolled_on)

        if node.host_identifier != host_identifier:
            current_app.logger.info("%s changed their host_identifier to %s",
                                    node, host_identifier)
            node.update(host_identifier=host_identifier)

        return jsonify(node_key=node.node_key, node_invalid=False)

    existing_node = None
    if host_identifier:
        existing_node = Node.query.filter(
            Node.host_identifier == host_identifier).first()

    if existing_node and not existing_node.enroll_secret:
        current_app.logger.warning(
            "Duplicate host_identifier %s, already enrolled %s",
            host_identifier, existing_node.enrolled_on)

        if current_app.config['DOORMAN_EXPECTS_UNIQUE_HOST_ID'] is True:
            current_app.logger.info(
                "Unique host identification is true, %s already enrolled "
                "returning existing node key %s", host_identifier,
                existing_node.node_key)
            return jsonify(node_key=existing_node.node_key, node_invalid=False)

    now = dt.datetime.utcnow()

    if node:
        node.update(host_identifier=host_identifier,
                    last_checkin=now,
                    enrolled_on=now)
    else:
        node = Node(host_identifier=host_identifier,
                    last_checkin=now,
                    enrolled_on=now)

        for value in current_app.config.get('DOORMAN_ENROLL_DEFAULT_TAGS', []):
            tag = Tag.query.filter_by(value=value).first()
            if tag and tag not in node.tags:
                node.tags.append(tag)
            elif not tag:
                node.tags.append(Tag(value=value))

        node.save()

    current_app.logger.info("Enrolled new node %s", node)

    return jsonify(node_key=node.node_key, node_invalid=False)
예제 #5
0
def enroll():
    '''
    Enroll an endpoint with osquery.

    :returns: a `node_key` unique id. Additionally `node_invalid` will
        be true if the node failed to enroll.
    '''
    request_json = request.get_json()
    if not request_json:
        current_app.logger.error(
            "%s - Request did not contain valid JSON data. This could "
            "be an attempt to gather information about this endpoint "
            "or an automated scanner.",
            request.remote_addr
        )
        # Return nothing
        return ""

    enroll_secret = request_json.get(
        current_app.config.get('DOORMAN_ENROLL_OVERRIDE', 'enroll_secret'))

    if not enroll_secret:
        current_app.logger.error(
            "%s - No enroll_secret provided by remote host",
            request.remote_addr
        )
        return jsonify(node_invalid=True)

    # If we pre-populate node table with a per-node enroll_secret,
    # let's query it now.

    if current_app.config.get('DOORMAN_ENROLL_SECRET_TAG_DELIMITER'):
        delimiter = current_app.config.get('DOORMAN_ENROLL_SECRET_TAG_DELIMITER')
        enroll_secret, _, enroll_tags = enroll_secret.partition(delimiter)
        enroll_tags = set([tag.strip() for tag in enroll_tags.split(delimiter)[:10]])
    else:
        enroll_secret, enroll_tags = enroll_secret, set()

    node = Node.query.filter(Node.enroll_secret == enroll_secret).first()

    if not node and enroll_secret not in current_app.config['DOORMAN_ENROLL_SECRET']:
        current_app.logger.error("%s - Invalid enroll_secret %s",
            request.remote_addr, enroll_secret
        )
        return jsonify(node_invalid=True)

    host_identifier = request_json.get('host_identifier')

    if node and node.enrolled_on:
        current_app.logger.warn(
            "%s - %s already enrolled on %s, returning existing node_key",
            request.remote_addr, node, node.enrolled_on
        )

        if node.host_identifier != host_identifier:
            current_app.logger.info(
                "%s - %s changed their host_identifier to %s",
                request.remote_addr, node, host_identifier
            )
            node.host_identifier = host_identifier

        node.update(
            last_checkin=dt.datetime.utcnow(),
            last_ip=request.remote_addr
        )

        return jsonify(node_key=node.node_key, node_invalid=False)

    existing_node = None
    if host_identifier:
        existing_node = Node.query.filter(
            Node.host_identifier == host_identifier
        ).first()

    if existing_node and not existing_node.enroll_secret:
        current_app.logger.warning(
            "%s - Duplicate host_identifier %s, already enrolled %s",
            request.remote_addr, host_identifier, existing_node.enrolled_on
        )

        if current_app.config['DOORMAN_EXPECTS_UNIQUE_HOST_ID'] is True:
            current_app.logger.info(
                "%s - Unique host identification is true, %s already enrolled "
                "returning existing node key %s",
                request.remote_addr, host_identifier, existing_node.node_key
            )
            existing_node.update(
                last_checkin=dt.datetime.utcnow(),
                last_ip=request.remote_addr
            )
            return jsonify(node_key=existing_node.node_key, node_invalid=False)

    now = dt.datetime.utcnow()

    if node:
        node.update(host_identifier=host_identifier,
                    last_checkin=now,
                    enrolled_on=now,
                    last_ip=request.remote_addr)
    else:
        node = Node(host_identifier=host_identifier,
                    last_checkin=now,
                    enrolled_on=now,
                    last_ip=request.remote_addr)

        enroll_tags.update(current_app.config.get('DOORMAN_ENROLL_DEFAULT_TAGS', []))

        for value in sorted((t.strip() for t in enroll_tags if t)):
            tag = Tag.query.filter_by(value=value).first()
            if tag and tag not in node.tags:
                node.tags.append(tag)
            elif not tag:
                node.tags.append(Tag(value=value))

        node.save()

    current_app.logger.info("%s - Enrolled new node %s",
        request.remote_addr, node
    )

    notify_of_node_enrollment.delay(node.to_dict())

    return jsonify(node_key=node.node_key, node_invalid=False)
예제 #6
0
파일: api.py 프로젝트: smook1980/doorman
def enroll():
    '''
    Enroll an endpoint with osquery.

    :returns: a `node_key` unique id. Additionally `node_invalid` will
        be true if the node failed to enroll.
    '''
    request_json = request.get_json()
    if not request_json:
        current_app.logger.error(
            "Request did not contain valid JSON data. This could be an "
            "attempt to gather information about this endpoint or an "
            "automated scanner."
        )
        # Return nothing
        return ""

    enroll_secret = request_json.get(
        current_app.config.get('DOORMAN_ENROLL_OVERRIDE', 'enroll_secret'))

    if not enroll_secret:
        current_app.logger.error("No enroll_secret provided by remote host %s",
                                 request.remote_addr)
        return jsonify(node_invalid=True)

    # If we pre-populate node table with a per-node enroll_secret,
    # let's query it now.

    node = Node.query.filter(Node.enroll_secret == enroll_secret).first()

    if not node and enroll_secret not in current_app.config['DOORMAN_ENROLL_SECRET']:
        current_app.logger.error("Invalid enroll_secret %s", enroll_secret)
        return jsonify(node_invalid=True)

    host_identifier = request_json.get('host_identifier')

    if node and node.enrolled_on:
        current_app.logger.warn("%s already enrolled on %s, returning "
                                "existing node_key", node, node.enrolled_on)

        if node.host_identifier != host_identifier:
            current_app.logger.info("%s changed their host_identifier to %s",
                                    node, host_identifier)
            node.update(host_identifier=host_identifier)

        return jsonify(node_key=node.node_key, node_invalid=False)

    existing_node = None
    if host_identifier:
        existing_node = Node.query.filter(
            Node.host_identifier == host_identifier
        ).first()

    if existing_node and not existing_node.enroll_secret:
        current_app.logger.warning(
            "Duplicate host_identifier %s, already enrolled %s",
            host_identifier, existing_node.enrolled_on)

        if current_app.config['DOORMAN_EXPECTS_UNIQUE_HOST_ID'] is True:
            current_app.logger.info(
                "Unique host identification is true, %s already enrolled "
                "returning existing node key %s",
                host_identifier, existing_node.node_key)
            return jsonify(node_key=existing_node.node_key, node_invalid=False)

    now = dt.datetime.utcnow()

    if node:
        node.update(host_identifier=host_identifier,
                    last_checkin=now,
                    enrolled_on=now)
    else:
        node = Node.create(host_identifier=host_identifier,
                           last_checkin=now,
                           enrolled_on=now)

    current_app.logger.info("Enrolled new node %s", node)

    return jsonify(node_key=node.node_key, node_invalid=False)