def _PersistBit9Events(event, file_catalog, computer, signing_chain): """Creates a Bit9Event from the given Event protobuf. Args: event: The api.Event instance to be synced to Upvote. file_catalog: The api.FileCatalog instance associated with this event. computer: The api.Computer instance associated with this event. signing_chain: List of api.Certificate instances associated with this event. Returns: An ndb.Future that resolves when all events are created. """ logging.info('Creating new Bit9Event') host_id = str(computer.id) blockable_key = ndb.Key(binary_models.Bit9Binary, file_catalog.sha256) host_users = list(bit9_utils.ExtractHostUsers(computer.users)) occurred_dt = event.timestamp _CheckAndResolveAnomalousBlock(blockable_key, host_id) new_event = event_models.Bit9Event( blockable_key=blockable_key, cert_key=_GetCertKey(signing_chain), event_type=constants.EVENT_TYPE.BLOCK_BINARY, last_blocked_dt=occurred_dt, first_blocked_dt=occurred_dt, host_id=host_id, file_name=event.file_name, file_path=event.path_name, publisher=file_catalog.publisher, version=file_catalog.product_version, description=event.description, executing_user=bit9_utils.ExtractHostUser(event.user_name), bit9_id=event.id) tables.EXECUTION.InsertRow( sha256=new_event.blockable_key.id(), device_id=host_id, timestamp=occurred_dt, platform=new_event.GetPlatformName(), client=new_event.GetClientName(), file_path=new_event.file_path, file_name=new_event.file_name, executing_user=new_event.executing_user, associated_users=host_users, decision=new_event.event_type) keys_to_insert = model_utils.GetEventKeysToInsert( new_event, host_users, host_users) futures = [_PersistBit9Event(new_event, key) for key in keys_to_insert] return datastore_utils.GetMultiFuture(futures)
def _PersistBit9Host(computer, occurred_dt): """Creates a Bit9Host from the Event protobuf if one does not already exist. NOTE: This function could be transactional but, at least for now, host puts in multiple requests don't really need to be processed in a fixed order. last_event_dt is the only frequently modified property and there's currently no need for it to be perfectly accurate. Args: computer: api.Computer object associated with the event. occurred_dt: datetime object corresponding to the time of the event. Returns: ndb.Future that resolves when the host is updated. """ host_id = str(computer.id) policy = computer.policy_id policy_key = (ndb.Key(bit9.Bit9Policy, str(policy)) if policy is not None else None) hostname = bit9_utils.ExpandHostname( bit9_utils.StripDownLevelDomain(computer.name)) policy_entity = policy_key.get() mode = (policy_entity.enforcement_level if policy_entity is not None else constants.HOST_MODE.UNKNOWN) # Grab the corresponding Bit9Host. bit9_host = yield bit9.Bit9Host.get_by_id_async(host_id) existing_users = set(bit9_host.users if bit9_host is not None else []) extracted_users = list(bit9_utils.ExtractHostUsers(computer.users)) # Ignore any 'Desktop Window Manager' users, otherwise a user can temporarily # become disassociated with their machine. If they vote for something to be # locally whitelisted during such a period, they won't get a rule for it. incoming_users = set() for extracted_user in extracted_users: if r'Window Manager\DWM-' in extracted_user: logging.warning('Ignoring user "%s"', extracted_user) else: incoming_users.add(extracted_user) # If there are incoming users, either because it was only all 'Desktop Window # Manager' entries, or because Bit9 didn't report any users for whatever # reason, then just stick with the existing users, otherwise we'll # disassociate the machine from the user. if not incoming_users: incoming_users = existing_users # Perform initialization for users new to this host. new_users = incoming_users - existing_users for new_user in new_users: # Create User if we haven't seen this user before. email = user_map.UsernameToEmail(new_user) user = user_models.User.GetOrInsert(email_addr=email) # Copy the user's local rules over from a pre-existing host. yield _CopyLocalRules(user.key, host_id) # List of all row action that need to be persisted. row_actions = [] # Doesn't exist? Guess we better fix that. if bit9_host is None: logging.info('Creating new Bit9Host') bit9_host = bit9.Bit9Host(id=host_id, hostname=hostname, last_event_dt=occurred_dt, policy_key=policy_key, users=sorted(list(incoming_users))) row_actions.append(constants.HOST_ACTION.FIRST_SEEN) else: changed = False if not bit9_host.last_event_dt or bit9_host.last_event_dt < occurred_dt: bit9_host.last_event_dt = occurred_dt changed = True if bit9_host.hostname != hostname: logging.info('Hostname for %s changed from %s to %s', host_id, bit9_host.hostname, hostname) bit9_host.hostname = hostname changed = True if bit9_host.policy_key != policy_key: bit9_host.policy_key = policy_key changed = True row_actions.append(constants.HOST_ACTION.MODE_CHANGE) if existing_users != incoming_users: existing_users_list = sorted(list(existing_users)) incoming_users_list = sorted(list(incoming_users)) logging.info('Users for %s changed from %s to %s', host_id, existing_users_list, incoming_users_list) bit9_host.users = incoming_users_list changed = True row_actions.append(constants.HOST_ACTION.USERS_CHANGE) if not changed: raise ndb.Return() logging.info('Attempting to put Bit9Host...') yield bit9_host.put_async() for action in row_actions: tables.HOST.InsertRow(device_id=host_id, timestamp=(bit9_host.recorded_dt if action == constants.HOST_ACTION.FIRST_SEEN else bit9_host.last_event_dt), action=action, hostname=hostname, platform=constants.PLATFORM.WINDOWS, users=sorted(list(incoming_users)), mode=mode)
def testMixedCase(self): user_str = r'HOST\user,{0}\USer'.format(settings.AD_DOMAIN) expected = [r'HOST\user', r'user'] actual = utils.ExtractHostUsers(user_str) self.assertEqual(expected, actual)
def testSkip(self): user_str = r'HOST\user,{0}\user,HOST\skipuser$,{0}\skipuser$'.format( settings.AD_DOMAIN) expected = [r'HOST\user', r'user'] actual = utils.ExtractHostUsers(user_str) self.assertEqual(expected, actual)
def testNone(self): self.assertEqual([], utils.ExtractHostUsers(None))
def testEmpty(self): self.assertEqual([], utils.ExtractHostUsers(''))