Exemple #1
0
def _ChangeModeForHosts(mode, user_keys, honor_lock=True):
    """Performs a client mode change for the specified users' hosts.

  Args:
    mode: The new client_mode to set.
    user_keys: The users whose host modes are to be changed.
    honor_lock: bool, whether the client_mode_lock property will be honored.
  """
    predicates = [
        santa.SantaHost.primary_user == user_map.EmailToUsername(key.id())
        for key in user_keys
    ]
    query = santa.SantaHost.query(ndb.OR(*predicates))
    hosts = query.fetch()
    updated_hosts = []

    for host in hosts:

        # If lock is honored, skip locked users.
        if honor_lock and host.client_mode_lock:
            continue

        # Ignore non-changes also.
        if host.client_mode == mode:
            continue

        # Proceed with the mode change.
        host.client_mode = mode
        host.client_mode_lock = False
        updated_hosts.append(host)

    ndb.put_multi(updated_hosts)
    logging.debug('Client mode changed to %s for %d host(s)', mode,
                  len(updated_hosts))
Exemple #2
0
  def testGetKeysToInsert_HostOwner(self):
    self.PatchSetting('EVENT_CREATION', constants.EVENT_CREATION.HOST_OWNER)
    keys = self.event_1.GetKeysToInsert([], ['foo'])

    self.assertEqual(1, len(keys))
    key_usernames = [user_map.EmailToUsername(key.flat()[1]) for key in keys]
    self.assertSameElements(['foo'], key_usernames)
Exemple #3
0
  def _CreateNewLocalRules(self, uuid, user_key):
    """Creates copies of all local rules for the new host."""
    # Pick any host owned by the user to copy rules from. Exclude hosts that
    # haven't completed a full sync because they won't have a complete rule set.
    # NOTE: Because we expect all hosts owned by a user to have the same local
    # rules, we should get the same rules set with any one of the user's hosts.
    username = user_map.EmailToUsername(user_key.id())
    host_query = santa_db.SantaHost.query(
        santa_db.SantaHost.primary_user == username,
        santa_db.SantaHost.last_postflight_dt != None)  # pylint: disable=g-equals-none
    a_host = host_query.get()
    if a_host is None:
      return utils.GetNoOpFuture()

    # Get all local rules from that host.
    rules_query = santa_db.SantaRule.query(
        santa_db.SantaRule.host_id == a_host.key.id(),
        santa_db.SantaRule.in_effect == True)  # pylint: disable=g-explicit-bool-comparison

    # Copy the local rules to the new host.
    new_rules = []
    for batch in query_utils.Paginate(rules_query):
      for rule in batch:
        new_rule = utils.CopyEntity(
            rule, new_parent=rule.key.parent(), host_id=uuid, user_key=user_key)
        new_rules.append(new_rule)

    futures = ndb.put_multi_async(new_rules)
    return utils.GetMultiFuture(futures)
Exemple #4
0
    def testModeChange(self):

        host = test_utils.CreateSantaHost(
            primary_user=user_map.EmailToUsername(self.user.key.id()),
            client_mode=MONITOR)
        roles._ChangeModeForHosts(LOCKDOWN, [self.user.key])

        host = host.key.get()
        self.assertEqual(LOCKDOWN, host.client_mode)
Exemple #5
0
  def testClientModeLockOnNotHonored(self):

    host = test_utils.CreateSantaHost(
        primary_user=user_map.EmailToUsername(self.user.key.id()),
        client_mode=MONITOR, client_mode_lock=True)
    roles._ChangeModeForHosts(LOCKDOWN, [self.user.key], honor_lock=False)

    host = host.key.get()
    self.assertFalse(host.client_mode_lock)
    self.assertEqual(LOCKDOWN, host.client_mode)
Exemple #6
0
  def testGetKeysToInsert_Admin(self):
    usernames = ['foo', 'bar']
    with mock.patch.object(
        base.Event, 'run_by_local_admin', return_value=True):
      event = utils.CopyEntity(self.event_1)
      keys = event.GetKeysToInsert(usernames, [])

    self.assertEqual(2, len(keys))
    key_usernames = [user_map.EmailToUsername(key.flat()[1]) for key in keys]
    self.assertSameElements(usernames, key_usernames)
Exemple #7
0
def _CopyLocalRules(user_key, dest_host_id):
    """Copy over a user's local rules to a newly-associated host.

  NOTE: Because of the implementation of local whitelisting on Bit9, many of
  these new copied local rules will likely be initially unfulfilled, that is,
  held in Upvote and not saved to Bit9.

  Args:
    user_key: str, The user for whom the rules will be copied.
    dest_host_id: str, The ID of the host for which the new rules will be
        created.
  """
    logging.info('Copying rules for %s to host %s', user_key.id(),
                 dest_host_id)

    username = user_map.EmailToUsername(user_key.id())
    host_query = bit9.Bit9Host.query(bit9.Bit9Host.users == username)
    src_host = yield host_query.get_async()
    if src_host is None:
        raise ndb.Return()
    assert src_host.key.id() != dest_host_id, (
        'User already associated with target host')

    # Get all local rules from that host.
    rules_query = bit9.Bit9Rule.query(
        bit9.Bit9Rule.host_id == src_host.key.id(),
        bit9.Bit9Rule.in_effect == True)  # pylint: disable=g-explicit-bool-comparison

    # Get a rough idea of how many rules we're in for. Since this is a
    # non-critical query, we limit the max number to a fairly low bound.
    rule_count = yield rules_query.count_async(limit=250)
    logging.info('Retrieved %s%s rules to copy',
                 '>' if rule_count == 250 else '', rule_count)

    # Copy the local rules to the new host.
    new_rules = []
    for batch in query_utils.Paginate(rules_query):
        for rule in batch:
            new_rule = model_utils.CopyEntity(rule,
                                              new_parent=rule.key.parent(),
                                              host_id=dest_host_id,
                                              user_key=user_key)
            new_rules.append(new_rule)
    logging.info('Copying %s rules to new host', len(new_rules))
    yield ndb.put_multi_async(new_rules)

    # Create the change sets necessary to submit the new rules to Bit9.
    changes = []
    for new_rule in new_rules:
        change = bit9.RuleChangeSet(rule_keys=[new_rule.key],
                                    change_type=new_rule.policy,
                                    parent=new_rule.key.parent())
        changes.append(change)
    logging.info('Creating %s RuleChangeSet', len(changes))
    yield ndb.put_multi_async(changes)
Exemple #8
0
def CreateTestEntities(email_addr):
  """Create some test Datastore data if specified, but only if running locally.

  Note that this code doesn't (and shouldn't) delete any existing entities.
  The risk of such code being accidentally triggered in prod is too great, so
  if local entities need to be deleted, use the local Datastore viewer (e.g.
  http://127.0.0.1:8000/datastore).

  Args:
    email_addr: Email address of the local users for whom test data should
        be created.

  Raises:
    NotRunningLocally: if called anywhere other than a local deployment.
  """
  if not env_utils.RunningLocally():
    raise NotRunningLocally

  # Create a user entity with all available roles.
  user = user_models.User.GetOrInsert(email_addr=email_addr)
  user_models.User.SetRoles(email_addr, constants.USER_ROLE.SET_ALL)

  username = user_map.EmailToUsername(email_addr)

  # Create associated SantaHosts for the user.
  santa_hosts = CreateSantaHosts(2, primary_user=username)

  # For each SantaHost, create some SantaEvents.
  for santa_host in santa_hosts:
    for santa_blockable in CreateSantaBlockables(5):

      parent_key = model_utils.ConcatenateKeys(
          user.key, santa_host.key, santa_blockable.key)
      CreateSantaEvent(
          santa_blockable,
          executing_user=username,
          event_type=constants.EVENT_TYPE.BLOCK_BINARY,
          host_id=santa_host.key.id(),
          parent=parent_key)

  # Create associated Bit9Hosts for the user.
  bit9_hosts = CreateBit9Hosts(2, users=[username])

  # For each Bit9Host, create some Bit9Events.
  for bit9_host in bit9_hosts:
    for bit9_binary in CreateBit9Binaries(5):

      parent_key = model_utils.ConcatenateKeys(
          user.key, bit9_host.key, bit9_binary.key)
      CreateBit9Event(
          bit9_binary,
          executing_user=username,
          event_type=constants.EVENT_TYPE.BLOCK_BINARY,
          host_id=bit9_host.key.id(),
          parent=parent_key)
Exemple #9
0
def _CopyLocalRules(user_key, dest_host_id):
    """Copy over a user's local rules to a newly-associated host.

  NOTE: Because of the implementation of local whitelisting on Bit9, many of
  these new copied local rules will likely be initially unfulfilled, that is,
  held in Upvote and not saved to Bit9.

  Args:
    user_key: str, The user for whom the rules will be copied.
    dest_host_id: str, The ID of the host for which the new rules will be
        created.
  """
    logging.info('Copying rules for user %s to host %s', user_key.id(),
                 dest_host_id)

    # Query for a host belonging to the user.
    username = user_map.EmailToUsername(user_key.id())
    query = bit9.Bit9Host.query(bit9.Bit9Host.users == username)
    src_host = yield query.get_async()
    if src_host is None:
        logging.warning('User %s has no hosts to copy from', username)
        raise ndb.Return()
    src_host_id = src_host.key.id()

    # Query for all the Bit9Rules in effect for the given user on the chosen host.
    query = bit9.Bit9Rule.query(bit9.Bit9Rule.host_id == src_host_id,
                                bit9.Bit9Rule.user_key == user_key,
                                bit9.Bit9Rule.in_effect == True)  # pylint: disable=g-explicit-bool-comparison
    src_rules = yield query.fetch_async()
    logging.info('Found a total of %d rule(s) for user %s', len(src_rules),
                 user_key.id())

    # Copy the local rules to the new host.
    logging.info('Copying %d rule(s) to host %s', len(src_rules), dest_host_id)
    new_rules = []
    for src_rule in src_rules:
        new_rule = datastore_utils.CopyEntity(src_rule,
                                              new_parent=src_rule.key.parent(),
                                              host_id=dest_host_id,
                                              user_key=user_key)
        new_rules.append(new_rule)
    yield ndb.put_multi_async(new_rules)

    # Create the change sets necessary to submit the new rules to Bit9.
    changes = []
    for new_rule in new_rules:
        change = bit9.RuleChangeSet(rule_keys=[new_rule.key],
                                    change_type=new_rule.policy,
                                    parent=new_rule.key.parent())
        changes.append(change)
    logging.info('Creating %d RuleChangeSet(s)', len(changes))
    yield ndb.put_multi_async(changes)
Exemple #10
0
  def _GetHostsToWhitelist(self, user_key):
    """Returns hosts for which whitelist rules should be created for a user.

    The current policy is to whitelist on Bit9Hosts where the User is listed in
    the users field.

    Args:
      user_key: Key, The user for whom hosts to whitelist should be fetched.

    Returns:
      set<str>, IDs of Hosts for which whitelist rules should be created.
    """
    username = user_map.EmailToUsername(user_key.id())
    query = bit9.Bit9Host.query(bit9.Bit9Host.users == username)
    return {host_key.id() for host_key in query.fetch(keys_only=True)}
Exemple #11
0
  def _GetHostsToWhitelist(self, user_key):
    """Returns hosts for which whitelist rules should be created for a user.

    The current policy is to only whitelist on Hosts where the User is listed as
    the primary_user.

    Args:
      user_key: Key, The user for whom hosts to whitelist should be fetched.

    Returns:
      set<str>, IDs of Hosts for which whitelist rules should be created.
    """
    username = user_map.EmailToUsername(user_key.id())
    query = santa.SantaHost.query(santa.SantaHost.primary_user == username)
    return {host_key.id() for host_key in query.fetch(keys_only=True)}
Exemple #12
0
  def testChangeModeForGroup_MultiBatch(self, mock_ctor):

    users = [
        test_utils.CreateUser() for _ in xrange(roles.BATCH_SIZE + 1)]
    hosts = [
        test_utils.CreateSantaHost(
            primary_user=user_map.EmailToUsername(user.key.id()),
            client_mode=MONITOR)
        for user in users]
    mock_ctor.return_value.AllMembers.return_value = [
        user.key.id() for user in users]

    response = self.testapp.get('')

    self.assertEqual(httplib.OK, response.status_int)

    self.assertTaskCount(constants.TASK_QUEUE.DEFAULT, 2)
    self.DrainTaskQueue(constants.TASK_QUEUE.DEFAULT)

    new_hosts = ndb.get_multi(host.key for host in hosts)
    self.assertTrue(all(host.client_mode == LOCKDOWN for host in new_hosts))
Exemple #13
0
    def testUserGetListOwnEventsWithBlockableAndContext(self):
        """Normal user getting list of their events with context, by blockable."""
        test_utils.CreateVote(self.santa_blockable1,
                              user_email=self.user_1.email)
        test_utils.CreateVote(self.santa_blockable1,
                              user_email=self.user_2.email)

        params = {
            'blockableKey': self.santa_blockable1.key.urlsafe(),
            'withContext': 'true'
        }

        with self.LoggedInUser(user=self.user_1):
            response = self.testapp.get(self.ROUTE, params)

        output = response.json

        self.assertIn('application/json', response.headers['Content-type'])
        self.assertIsInstance(output, dict)
        self.assertEqual(len(output['content']), 2)

        event_with_context = output['content'][0]
        self.assertEqual(len(event_with_context.keys()), 5)
        self.assertEqual(event_with_context['host']['id'],
                         event_with_context['event']['hostId'])
        blockable_key = ndb.Key(
            urlsafe=event_with_context['event']['blockableKey'])
        self.assertEqual(event_with_context['blockable']['id'],
                         blockable_key.id())
        self.assertEqual(event_with_context['blockable']['fileName'],
                         event_with_context['event']['fileName'])
        self.assertEqual(event_with_context['cert']['id'],
                         event_with_context['blockable']['certId'])
        self.assertEqual(
            user_map.EmailToUsername(event_with_context['vote']['userEmail']),
            event_with_context['event']['executingUser'])
Exemple #14
0
def _CopyLocalRules(user_key, dest_host_id):
    """Creates copies of all local rules for the new host."""

    logging.info('Copying rules for user %s to host %s', user_key.id(),
                 dest_host_id)

    # Pick any host owned by the user to copy rules from. Exclude hosts that
    # haven't completed a full sync because they won't have a complete rule set.
    username = user_map.EmailToUsername(user_key.id())
    query = santa_db.SantaHost.query(
        santa_db.SantaHost.primary_user == username,
        santa_db.SantaHost.last_postflight_dt != None)  # pylint: disable=g-equals-none
    src_host = query.get()
    if src_host is None:
        logging.warning('User %s has no hosts to copy from', username)
        return datastore_utils.GetNoOpFuture()

    # Query for all SantaRules for the given user on the chosen host.
    query = santa_db.SantaRule.query(
        santa_db.SantaRule.host_id == src_host.key.id(),
        santa_db.SantaRule.user_key == user_key)

    # Copy the local rules to the new host.
    new_rules = []
    for src_rules in datastore_utils.Paginate(query):
        for src_rule in src_rules:
            new_rule = datastore_utils.CopyEntity(
                src_rule,
                new_parent=src_rule.key.parent(),
                host_id=dest_host_id,
                user_key=user_key)
            new_rules.append(new_rule)

    logging.info('Copying %d rule(s) to host %s', len(new_rules), dest_host_id)
    futures = ndb.put_multi_async(new_rules)
    return datastore_utils.GetMultiFuture(futures)
 def testEmailToUsername(self):
     self.assertEqual('user', user_map.EmailToUsername('*****@*****.**'))
     self.assertEqual('user', user_map.EmailToUsername('user'))
Exemple #16
0
 def nickname(self):
     return user_map.EmailToUsername(self.key.string_id())