def test_close_manually_changed_incident_open_machine_incident(self): event_metadata = EventMetadata(event_type="test", machine_serial_number="YOLOFOMO") event_metadata.machine = MockMetaMachine([self.mbu1], [self.tag1], "WINDOWS", "LAPTOP", serial_number="YOLOFOMO") event = BaseEvent(event_metadata, {"joe": "jackson"}) self.assertTrue(self.probe.test_event(event)) machine_incident1, _ = update_or_create_open_machine_incident( self.probe_source, self.probe.get_matching_event_incident_severity(event), event.metadata.machine_serial_number, event.metadata.uuid ) # manually changed incident status incident = machine_incident1.incident incident.status = STATUS_IN_PROGRESS incident.save() machine_incident2, event_payloads = update_or_create_open_machine_incident( self.probe_source, 0, # severity == 0 => close event.metadata.machine_serial_number, event.metadata.uuid ) self.assertEqual(machine_incident1, machine_incident2) self.assertEqual(machine_incident2.incident, machine_incident1.incident) self.assertEqual(machine_incident2.status, STATUS_CLOSED) self.assertEqual(incident.status, STATUS_IN_PROGRESS) # not touched because manually changed self.assertEqual(len(event_payloads), 1) event_payload = event_payloads[0] self.assertEqual(event_payload["action"], "closed") self.assertEqual(event_payload["pk"], machine_incident2.pk) self.assertEqual(event_payload["status"], STATUS_CLOSED) # machine incident closed self.assertEqual(event_payload["incident"]["pk"], incident.pk) self.assertEqual(event_payload["incident"]["status"], STATUS_IN_PROGRESS) # incident still in progress
def test_enrich_event_machine_incident_match(self): event_metadata = EventMetadata(event_type="test", machine_serial_number="YOLOFOMO") event_metadata.machine = MockMetaMachine([self.mbu1], [self.tag1], "WINDOWS", "LAPTOP", serial_number="YOLOFOMO") event = BaseEvent(event_metadata, {"joe": "jackson"}) self.assertTrue(self.probe.test_event(event)) enriched_events = list(enrich_event(event)) self.assertEqual(len(enriched_events), 3) eevent1, eevent2, eevent3 = enriched_events # first event is the incident event self.assertIsInstance(eevent1, IncidentEvent) incident = Incident.objects.all()[0] self.assertEqual(eevent1.payload["action"], "created") self.assertEqual(eevent1.payload["pk"], incident.pk) self.assertEqual(eevent1.metadata.machine_serial_number, "YOLOFOMO") # second event is the machine incident event self.assertIsInstance(eevent2, MachineIncidentEvent) self.assertEqual(eevent2.payload["action"], "created") self.assertEqual(eevent2.payload["incident"]["pk"], incident.pk) self.assertEqual(eevent2.metadata.machine_serial_number, "YOLOFOMO") machine_incident = incident.machineincident_set.all()[0] self.assertEqual(eevent2.payload["pk"], machine_incident.pk) # third event is the original event self.assertEqual(eevent3, event) # machine incident in the original event metadata incidents self.assertEqual(len(eevent3.metadata.incidents), 1) eevent3_incident = eevent3.metadata.incidents[0] self.assertEqual(eevent3_incident["pk"], machine_incident.incident.pk) self.assertEqual(eevent3_incident["machine_incident"]["pk"], machine_incident.pk)
def test_close_manually_changed_open_machine_incident(self): event_metadata = EventMetadata(event_type="test", machine_serial_number="YOLOFOMO") event_metadata.machine = MockMetaMachine([self.mbu1], [self.tag1], "WINDOWS", "LAPTOP", serial_number="YOLOFOMO") event = BaseEvent(event_metadata, {"joe": "jackson"}) self.assertTrue(self.probe.test_event(event)) machine_incident1, _ = update_or_create_open_machine_incident( self.probe_source, self.probe.get_matching_event_incident_severity(event), event.metadata.machine_serial_number, event.metadata.uuid ) # manually changed incident status machine_incident1.status = STATUS_IN_PROGRESS machine_incident1.save() machine_incident2, event_payloads = update_or_create_open_machine_incident( self.probe_source, 0, # severity == 0 => close event.metadata.machine_serial_number, event.metadata.uuid ) # no changes, because the machine incident was manually changed self.assertEqual(machine_incident2, None) self.assertEqual(len(event_payloads), 0)
def test_update_open_machine_incident(self): event_metadata = EventMetadata(event_type="test", machine_serial_number="YOLOFOMO") event_metadata.machine = MockMetaMachine([self.mbu1], [self.tag1], "WINDOWS", "LAPTOP", serial_number="YOLOFOMO") event = BaseEvent(event_metadata, {"joe": "jackson"}) self.assertTrue(self.probe.test_event(event)) machine_incident1, _ = update_or_create_open_machine_incident( self.probe_source, self.probe.get_matching_event_incident_severity(event), event.metadata.machine_serial_number, event.metadata.uuid ) machine_incident2, event_payloads = update_or_create_open_machine_incident( self.probe_source, self.probe.get_matching_event_incident_severity(event) + 100, event.metadata.machine_serial_number, event.metadata.uuid ) self.assertEqual(machine_incident1, machine_incident2) self.assertEqual(machine_incident2.incident, machine_incident1.incident) self.assertEqual(machine_incident2.incident.severity, SEVERITY_CRITICAL + 100) self.assertEqual(len(event_payloads), 1) event_payload = event_payloads[0] self.assertEqual(event_payload["action"], "updated") self.assertEqual(event_payload["diff"], {"removed": {"severity": SEVERITY_CRITICAL}, "added": {"severity": SEVERITY_CRITICAL + 100}}) self.assertEqual(event_payload["severity"], SEVERITY_CRITICAL + 100) self.assertEqual(event_payload.get("incident"), None) # meta machine self.assertEqual(MetaMachine("YOLOFOMO").max_incident_severity(), SEVERITY_CRITICAL + 100)
def post_group_membership_updates(request, added_groups, removed_groups, user=None): event_request = EventRequest.build_from_request(request) created_at = datetime.utcnow() event_uuid = uuid.uuid4() event_index = 0 base_payload = {} if user: base_payload["user"] = { "pk": user.pk, "username": user.username, "is_service_account": user.is_service_account } if added_groups: for added_group in added_groups: event_metadata = EventMetadata(request=event_request, uuid=event_uuid, index=event_index, created_at=created_at) payload = base_payload.copy() payload["group"] = {"pk": added_group.pk, "name": added_group.name} event = AddUserToGroupEvent(event_metadata, payload) event.post() event_index += 1 if removed_groups: for removed_group in removed_groups: event_metadata = EventMetadata(request=event_request, uuid=event_uuid, index=event_index, created_at=created_at) payload = base_payload.copy() payload["group"] = {"pk": removed_group.pk, "name": removed_group.name} event = RemoveUserFromGroupEvent(event_metadata, payload) event.post() event_index += 1
def test_probe_test_event(self): for mbuis, tis, p, t, result in (([1238971298], [self.tag1.id], "WINDOWS", "LAPTOP", False), ([self.mbu1.id], [self.tag1.id], "WINDOWS", "LAPTOP", True), ([self.mbu1.id], [self.tag1.id], "WINDOWS", "VM", True), ): event_metadata = EventMetadata(machine_serial_number="YO", event_type="base") # TODO hack event_metadata.machine = MockMetaMachine(mbuis, tis, p, t) event = BaseEvent(event_metadata, {"godzilla": "kommt"}) self.assertEqual(self.probe.test_event(event), result) self.assertEqual(self.error_probe.test_event(event), False)
def post_munki_events(msn, user_agent, ip, data): for report in data: events = report.pop('events') metadata = EventMetadata(MunkiEvent.event_type, machine_serial_number=msn, request=EventRequest(user_agent, ip), tags=MunkiEvent.tags) for index, (created_at, payload) in enumerate(events): metadata.index = index metadata.created_at = parser.parse(created_at) payload.update(report) event = MunkiEvent(metadata, payload) event.post()
def test_same_open_incident(self): event1_metadata = EventMetadata(event_type="test") event1 = BaseEvent(event1_metadata, {"joe": "jackson"}) self.assertTrue(self.probe.test_event(event1)) incident, _ = update_or_create_open_incident(self.probe_source, SEVERITY_CRITICAL, event1.metadata.uuid) event2_metadata = EventMetadata(event_type="test") event2 = BaseEvent(event2_metadata, {"joe": "jackson"}) self.assertTrue(self.probe.test_event(event2)) incident2, event_payloads = update_or_create_open_incident( self.probe_source, SEVERITY_CRITICAL, event2.metadata.uuid) self.assertEqual(incident, incident2) self.assertEqual(len(event_payloads), 0)
def post_santa_ruleset_update_events(request, ruleset_data, rules_data): event_request = EventRequest.build_from_request(request) ruleset_update_event_metadata = EventMetadata(request=event_request) ruleset_update_event = SantaRuleSetUpdateEvent( ruleset_update_event_metadata, ruleset_data) ruleset_update_event.post() for idx, rule_data in enumerate(rules_data): rule_update_event_metadata = EventMetadata( request=event_request, uuid=ruleset_update_event_metadata.uuid, index=idx + 1) rule_update_event = SantaRuleUpdateEvent(rule_update_event_metadata, rule_data) rule_update_event.post()
def post_osquery_pack_update_events(request, pack_data, pack_queries_data): event_request = EventRequest.build_from_request(request) pack_update_event_metadata = EventMetadata(request=event_request) pack_update_event = OsqueryPackUpdateEvent(pack_update_event_metadata, pack_data) pack_update_event.post() for idx, pack_query_data in enumerate(pack_queries_data): pack_query_update_event_metadata = EventMetadata( request=event_request, uuid=pack_update_event_metadata.uuid, index=idx + 1) pack_query_update_event = OsqueryPackQueryUpdateEvent( pack_query_update_event_metadata, pack_query_data) pack_query_update_event.post()
def test_close_open_machine_incident(self): event_metadata = EventMetadata(event_type="test", machine_serial_number="YOLOFOMO") event_metadata.machine = MockMetaMachine([self.mbu1], [self.tag1], "WINDOWS", "LAPTOP", serial_number="YOLOFOMO") event = BaseEvent(event_metadata, {"joe": "jackson"}) self.assertTrue(self.probe.test_event(event)) machine_incident1, _ = update_or_create_open_machine_incident( self.probe_source, self.probe.get_matching_event_incident_severity(event), event.metadata.machine_serial_number, event.metadata.uuid ) self.assertEqual(machine_incident1.status, STATUS_OPEN) self.assertEqual(machine_incident1.incident.status, STATUS_OPEN) machine_incident2, event_payloads = update_or_create_open_machine_incident( self.probe_source, 0, # severity == 0 => close event.metadata.machine_serial_number, event.metadata.uuid ) self.assertEqual(machine_incident1, machine_incident2) self.assertEqual(machine_incident2.incident, machine_incident1.incident) self.assertEqual(machine_incident2.status, STATUS_CLOSED) incident = machine_incident2.incident self.assertEqual(incident.severity, SEVERITY_CRITICAL) self.assertEqual(incident.status, STATUS_CLOSED) self.assertEqual(len(event_payloads), 2) event_payload1, event_payload2 = event_payloads # machine incident event payload self.assertEqual(event_payload1["action"], "closed") self.assertEqual(event_payload1["incident"]["pk"], incident.pk) self.assertEqual(event_payload1["incident"]["status"], STATUS_OPEN) # Incident still open self.assertEqual(event_payload1["pk"], machine_incident2.pk) self.assertEqual(event_payload1["status"], machine_incident2.status) self.assertEqual(event_payload1["event_id"], str(event.metadata.uuid)) self.assertEqual(event_payload1["diff"], {"removed": {"status": STATUS_OPEN}, "added": {"status": STATUS_CLOSED}}) # incident event payload self.assertEqual(event_payload2["action"], "closed") self.assertEqual(event_payload2["pk"], incident.pk) self.assertEqual(event_payload2["status"], STATUS_CLOSED) # Incident closed now self.assertEqual(event_payload2.get("incident"), None) self.assertEqual(event_payload2["diff"], {"removed": {"status": STATUS_OPEN}, "added": {"status": STATUS_CLOSED}}) # meta machine self.assertEqual(MetaMachine("YOLOFOMO").max_incident_severity(), None)
def test_create_open_incident(self): event_metadata = EventMetadata(event_type="test") event = BaseEvent(event_metadata, {"joe": "jackson"}) self.assertTrue(self.probe.test_event(event)) self.assertEqual(self.probe.get_matching_event_incident_severity(event), SEVERITY_CRITICAL) incident, event_payloads = update_or_create_open_incident(self.probe_source, SEVERITY_CRITICAL, event.metadata.uuid) # incident self.assertEqual(incident.probe_source, self.probe_source) self.assertEqual(incident.name, "base probe") self.assertEqual(incident.status, STATUS_OPEN) self.assertEqual(incident.severity, SEVERITY_CRITICAL) self.assertEqual(incident.event_id, event.metadata.uuid) self.assertEqual(MachineIncident.objects.count(), 0) self.assertEqual([incident], list(Incident.objects.all())) # event payload self.assertEqual(len(event_payloads), 1) event_payload = event_payloads[0] self.assertEqual(event_payload["action"], "created") self.assertEqual(event_payload["pk"], incident.pk) self.assertEqual(event_payload["probe_pk"], self.probe_source.pk) self.assertEqual(event_payload["name"], "base probe") self.assertEqual(event_payload["status"], STATUS_OPEN) self.assertEqual(event_payload["severity"], SEVERITY_CRITICAL) self.assertEqual(event_payload["event_id"], str(event.metadata.uuid)) self.assertEqual(event_payload.get("incident"), None) # not a machine incident payload
def post_results(msn, user_agent, ip, results): event_uuid = uuid.uuid4() if user_agent or ip: request = EventRequest(user_agent, ip) else: request = None cc_status_agg = ComplianceCheckStatusAggregator(msn) for index, result in enumerate(_iter_cleaned_up_records(results)): try: event_time = _get_record_created_at(result) except Exception: logger.exception("Could not extract osquery result time") event_time = None metadata = EventMetadata(uuid=event_uuid, index=index, machine_serial_number=msn, request=request, created_at=event_time) event = OsqueryResultEvent(metadata, result) event.post() snapshot = event.payload.get("snapshot") if snapshot is None: # no snapshot, cannot be a compliance check continue try: _, query_pk, query_version = event.parse_result_name() except ValueError as e: logger.warning(str(e)) continue cc_status_agg.add_result(query_pk, query_version, event_time, snapshot) cc_status_agg.commit_and_post_events()
def test_update_open_incident(self): event_metadata = EventMetadata(event_type="test") event = BaseEvent(event_metadata, {"joe": "jackson"}) self.assertTrue(self.probe.test_event(event)) incident, _ = update_or_create_open_incident(self.probe_source, SEVERITY_CRITICAL, event.metadata.uuid) incident2, event_payloads = update_or_create_open_incident( self.probe_source, SEVERITY_CRITICAL + 100, event.metadata.uuid) self.assertEqual(incident, incident2) self.assertEqual(incident2.severity, SEVERITY_CRITICAL + 100) self.assertEqual(Incident.objects.all().count(), 1) self.assertEqual(len(event_payloads), 1) event_payload = event_payloads[0] self.assertEqual(event_payload["action"], "updated") self.assertEqual( event_payload["diff"], { "removed": { "severity": SEVERITY_CRITICAL }, "added": { "severity": SEVERITY_CRITICAL + 100 } }) self.assertEqual(event_payload["severity"], SEVERITY_CRITICAL + 100)
def build_from_object_serial_number_and_statuses(cls, jmespath_check, serial_number, status, previous_status): payload = jmespath_check.compliance_check.serialize_for_event() payload["inventory_jmespath_check"] = jmespath_check.serialize_for_event() payload["status"] = status.name if previous_status is not None: payload["previous_status"] = previous_status.name return cls(EventMetadata(machine_serial_number=serial_number), payload)
def apply_incident_updates(original_event): events = [] incident_updates = original_event.metadata.incident_updates if not incident_updates: return events serial_number = original_event.metadata.machine_serial_number event_uuid = uuid.uuid4() event_index = 0 with transaction.atomic(): for incident_update in incident_updates: for event_cls, event_payload in apply_incident_update( incident_update, serial_number): event_metadata = EventMetadata( uuid=event_uuid, index=event_index, machine_serial_number=serial_number, # copy the original event payload linked objects into the incident events metadata objects=original_event.get_linked_objects_keys()) event = event_cls(event_metadata, event_payload) events.append(event) event_index += 1 # copy the incident event payload linked objects into the original event metadata original_event.metadata.add_objects( event.get_linked_objects_keys()) return events
def build_osquery_result_event(query_name): OsqueryResult = event_types["osquery_result"] payload = payload_template.copy() payload["name"] = query_name return OsqueryResult(EventMetadata(machine_serial_number="YO", event_type=OsqueryResult.event_type), payload)
def update_machine(self, client, device_type, jamf_id): logger.info("Update machine %s %s %s", client.get_source_d(), device_type, jamf_id) try: machine_d = client.get_machine_d(device_type, jamf_id) except: logger.exception("Could not get machine_d. %s %s %s", client.get_source_d(), device_type, jamf_id) else: try: msc, ms = MachineSnapshotCommit.objects.commit_machine_snapshot_tree( machine_d) except: logger.exception("Could not commit machine snapshot") else: if msc: for idx, (event_type, created_at, payload) in enumerate( inventory_events_from_machine_snapshot_commit( msc)): event_cls = event_cls_from_type(event_type) metadata = EventMetadata( event_cls.event_type, machine_serial_number=ms.serial_number, index=idx, created_at=created_at, tags=event_cls.tags) event = event_cls(metadata, payload) yield event
def user_login_failed_callback(sender, credentials, **kwargs): request = kwargs.get("request") # introduced in django 1.11 if request: request = EventRequest.build_from_request(request) metadata = EventMetadata(request=request) event = FailedLoginEvent(metadata, {"user": {k: str(v) for k, v in credentials.items() if k in ("username",)}}) event.post()
def build_software_server_event(self, raw_event_d): payload = {} for p_attr, re_attr in (("log_level", "log_level"), ("info_1", "info_1"), ("component", "component"), ("message", "cleaned_message")): v = raw_event_d.get(re_attr, None) if v: payload[p_attr] = v else: logger.warning("Missing software server event attr %s.", re_attr) if not payload: logger.error("Could not build software server event %s", raw_event_d) return None else: # jamf instance self.add_payload_jamf_instance(payload, raw_event_d) # event metadata = EventMetadata( JAMFSoftwareServerEvent.event_type, created_at=self.get_created_at(raw_event_d), tags=JAMFSoftwareServerEvent.tags) return JAMFSoftwareServerEvent(metadata, payload)
def post_munki_request_event(msn, user_agent, ip, **kwargs): metadata = EventMetadata( machine_serial_number=msn, request=EventRequest(user_agent, ip), incident_updates=kwargs.pop("incident_updates", []) ) event = MunkiRequestEvent(metadata, kwargs) event.post()
def post_sync_started_event(instance, serialized_event_request): request = None if serialized_event_request: request = EventRequest.deserialize(serialized_event_request) metadata = EventMetadata(request=request) event = WSOneInstanceSyncStarted( metadata, {"instance": instance.serialize_for_event()}) event.post()
def test_probe_test_event(self): for event_type, tags, result in (("santa_event", ["yo"], False), ("osquery_result", ["super", "michel"], True), ("inventory_group_update", ["osquery", "yo"], True)): event = BaseEvent(EventMetadata(machine_serial_number="YO", event_type=event_type, tags=tags), {"godzilla": "kommt"}) self.assertEqual(self.probe.test_event(event), result)
def post_event(event_cls, request, user, payload=None): if payload is None: payload = {} metadata = EventMetadata(request=EventRequest.build_from_request(request)) if user and user != request.user: payload["user"] = {"pk": user.pk, "username": user.username} event = event_cls(metadata, payload) event.post()
def iter_inventory_events(msn, events): event_uuid = uuid.uuid4() for index, (event_type, created_at, data) in enumerate(events): event_cls = event_cls_from_type(event_type) metadata = EventMetadata(machine_serial_number=msn, uuid=event_uuid, index=index, created_at=created_at) yield event_cls(metadata, data)
def user_login_failed_callback(sender, credentials, **kwargs): request = kwargs.get("request") # introduced in django 1.11 if request: request = EventRequest.build_from_request(request) metadata = EventMetadata(FailedLoginEvent.event_type, request=request, tags=FailedLoginEvent.tags) event = FailedLoginEvent(metadata, credentials) event.post()
def post_event(event_cls, request, user): payload = make_event_payload(user) if not payload: return metadata = EventMetadata(event_cls.event_type, request=make_event_metadata_request(request), tags=event_cls.tags) event = event_cls(metadata, payload) event.post()
def _build_event(event_type, machine_serial_number=None, payload=None, tags=None): cls = type("".join(w.title() for w in event_type.split("_")), (BaseEvent,), {"event_type": event_type, "tags": tags or []}) event_metadata = EventMetadata(machine_serial_number=machine_serial_number) if payload is None: payload = {} return cls(event_metadata, payload)
def test_create_open_machine_incident(self): event_metadata = EventMetadata(event_type="test", machine_serial_number="YOLOFOMO") event_metadata.machine = MockMetaMachine([self.mbu1], [self.tag1], "WINDOWS", "LAPTOP", serial_number="YOLOFOMO") event = BaseEvent(event_metadata, {"joe": "jackson"}) self.assertTrue(self.probe.test_event(event)) machine_incident, event_payloads = update_or_create_open_machine_incident( self.probe_source, self.probe.get_matching_event_incident_severity(event), event.metadata.machine_serial_number, event.metadata.uuid) # machine incident self.assertEqual([machine_incident], list(MachineIncident.objects.all())) self.assertEqual(machine_incident.status, STATUS_OPEN) self.assertEqual(machine_incident.event_id, event.metadata.uuid) # incident incident = machine_incident.incident self.assertEqual([incident], list(Incident.objects.all())) self.assertEqual(incident.probe_source, self.probe_source) self.assertEqual(incident.name, "base probe") self.assertEqual(incident.status, STATUS_OPEN) self.assertEqual(incident.severity, SEVERITY_CRITICAL) self.assertEqual(incident.event_id, event.metadata.uuid) # event payloads self.assertEqual(len(event_payloads), 2) event_payload1, event_payload2 = event_payloads # incident event payload self.assertEqual(event_payload1["action"], "created") self.assertEqual(event_payload1["pk"], incident.pk) self.assertEqual(event_payload1.get("machine_incident"), None) # machine incident event payload self.assertEqual(event_payload2["action"], "created") self.assertEqual( event_payload2["machine_incident"], { "pk": machine_incident.pk, "status": machine_incident.status, "event_id": str(event.metadata.uuid) }) # meta machine self.assertEqual( MetaMachine("YOLOFOMO").max_incident_severity(), SEVERITY_CRITICAL)
def post_inventory_events(msn, events): for index, (event_type, created_at, data) in enumerate(events): event_cls = event_cls_from_type(event_type) metadata = EventMetadata(event_cls.event_type, machine_serial_number=msn, index=index, created_at=created_at, tags=event_cls.tags) event = event_cls(metadata, data) event.post()