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
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
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)
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)
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)
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)