示例#1
0
def _SanitizeAddrs(addrs):
    if isinstance(addrs, list):
        return [user_utils.UsernameToEmail(addr.strip()) for addr in addrs]
    elif isinstance(addrs, str):
        return [user_utils.UsernameToEmail(addrs.strip())]
    else:
        return []
 def setUp(self):
   app = webapp2.WSGIApplication(
       [webapp2.Route(r'', handler=FakeHandler)])
   super(XsrfTest, self).setUp(app, patch_generate_token=False)
   self.user_email = user_utils.UsernameToEmail('test')
   self.Login(self.user_email)
   self.user_id = users.get_current_user().user_id()
示例#3
0
  def get(self, blockable_id):  # pylint: disable=g-bad-name
    blockable = binary_models.Blockable.get_by_id(blockable_id)
    if not blockable:
      self.abort(httplib.NOT_FOUND, explanation='Blockable not found')

    username = self.request.get('asUser')
    if username:
      self.RequirePermission(constants.PERMISSIONS.VIEW_OTHER_EVENTS)
      user = user_models.User.GetById(
          user_utils.UsernameToEmail(username))
    else:
      user = self.user

    # If the blockable is a bundle, search by the 'bundle_key' property instead
    # of 'blockable_key'.
    blockable_filter = (
        event_models.SantaEvent.bundle_key == blockable.key
        if isinstance(blockable, package_models.SantaBundle) else
        event_models.Event.blockable_key == blockable.key)

    event_query = (event_models.Event
                   .query(ancestor=user.key)
                   .filter(blockable_filter)
                   .order(-event_models.Event.last_blocked_dt))

    event = event_query.get()

    response_data = event
    if event:
      with_context = (self.request.get('withContext').lower() == 'true')
      response_data = _GetEventContext([event])[0] if with_context else event

    self.respond_json(response_data)
示例#4
0
def GetEventKeysToInsert(event, logged_in_users, host_owners):
    """Returns the list of keys with which this Event should be inserted."""
    if settings.EVENT_CREATION == constants.EVENT_CREATION.EXECUTING_USER:
        if event.run_by_local_admin:
            usernames = logged_in_users
        else:
            usernames = [event.executing_user] if event.executing_user else []
    else:  # HOST_OWNERS
        usernames = host_owners

    emails = [user_utils.UsernameToEmail(username) for username in usernames]

    keys = []
    for email in emails:
        key_pairs = [(user_models.User, email.lower()),
                     (host_models.Host, event.host_id)]
        key_pairs += event.blockable_key.pairs()
        key_pairs += [(event_models.Event, '1')]
        keys.append(ndb.Key(pairs=key_pairs))
    return keys
示例#5
0
    def testGetEventKeysToInsert(self):
        keys = model_utils.GetEventKeysToInsert(self.event, ['foo', 'bar'], [])

        self.assertLen(keys, 1)
        expected_email = user_utils.UsernameToEmail(self.event.executing_user)
        self.assertEqual(expected_email, keys[0].pairs()[0][1])
示例#6
0
    def post(self, uuid):
        futures = []

        # Create an User for the reported user on any preflight,
        # if one doesn't already exist.
        primary_user = self.parsed_json.get(_PREFLIGHT.PRIMARY_USER)
        email_addr = user_utils.UsernameToEmail(primary_user)
        user = user_models.User.GetOrInsert(email_addr=email_addr)

        # Ensures the returned username is consistent with the User entity.
        primary_user = user.nickname

        first_seen = not self.host
        users_change = not first_seen and primary_user != self.host.primary_user

        # Create a SantaHost on the first preflight.
        if first_seen:
            logging.info('Host %s is syncing for the first time', uuid)
            self.host = host_models.SantaHost(key=self.host_key)
            self.host.client_mode = settings.DEFAULT_CLIENT_MODE[
                constants.CLIENT.SANTA]
            futures.append(_CopyLocalRules(user.key, uuid))

        # Update the SantaHost on every sync.
        self.host.serial_num = self.parsed_json.get(_PREFLIGHT.SERIAL_NUM)
        self.host.hostname = self.parsed_json.get(_PREFLIGHT.HOSTNAME)
        self.host.primary_user = primary_user
        self.host.santa_version = self.parsed_json.get(
            _PREFLIGHT.SANTA_VERSION)
        self.host.os_version = self.parsed_json.get(_PREFLIGHT.OS_VERSION)
        self.host.os_build = self.parsed_json.get(_PREFLIGHT.OS_BUILD)
        self.host.last_preflight_dt = datetime.datetime.utcnow()
        self.host.last_preflight_ip = self.request.remote_addr

        reported_mode = self.parsed_json.get(_PREFLIGHT.CLIENT_MODE)
        if reported_mode != self.host.client_mode:

            message = 'Client mode mismatch (Expected: %s, Actual: %s)' % (
                self.host.client_mode, reported_mode)
            logging.warning(message)

            # If the client_mode doesn't correspond to a known value, report it as
            # UNKNOWN.
            if reported_mode not in constants.HOST_MODE.SET_ALL:
                reported_mode = constants.HOST_MODE.UNKNOWN

            tables.HOST.InsertRow(device_id=uuid,
                                  timestamp=datetime.datetime.utcnow(),
                                  action=constants.HOST_ACTION.COMMENT,
                                  hostname=self.host.hostname,
                                  platform=constants.PLATFORM.MACOS,
                                  users=[self.host.primary_user],
                                  mode=reported_mode,
                                  comment=message)

        if self.parsed_json.get(_PREFLIGHT.REQUEST_CLEAN_SYNC):
            logging.info('Client requested clean sync')
            self.host.rule_sync_dt = None

        # Save the SantaHost entity.
        futures.append(self.host.put_async())

        # If the big red button is pressed, override the self.host.client_mode
        # set in datastore with either MONITOR or LOCKDOWN for this response only.
        actual_client_mode = self.host.client_mode
        big_red_button = big_red.BigRedButton()
        if big_red_button.stop_stop_stop:
            actual_client_mode = constants.CLIENT_MODE.MONITOR
        elif big_red_button.go_go_go:
            actual_client_mode = constants.CLIENT_MODE.LOCKDOWN

        # Prepare the response.
        response = {
            _PREFLIGHT.BATCH_SIZE: (settings.SANTA_EVENT_BATCH_SIZE),
            _PREFLIGHT.CLIENT_MODE:
            actual_client_mode,
            _PREFLIGHT.WHITELIST_REGEX:
            (self.host.directory_whitelist_regex
             if self.host.directory_whitelist_regex is not None else
             settings.SANTA_DIRECTORY_WHITELIST_REGEX),
            _PREFLIGHT.BLACKLIST_REGEX:
            (self.host.directory_blacklist_regex
             if self.host.directory_blacklist_regex is not None else
             settings.SANTA_DIRECTORY_BLACKLIST_REGEX),
            _PREFLIGHT.CLEAN_SYNC:
            not self.host.rule_sync_dt,
            _PREFLIGHT.BUNDLES_ENABLED: (settings.SANTA_BUNDLES_ENABLED),
            _PREFLIGHT.TRANSITIVE_WHITELISTING_ENABLED:
            (self.host.transitive_whitelisting_enabled),
        }

        # Verify all futures resolved successfully.
        for future in futures:
            future.check_success()

        # If this is the first preflight, create a FIRST_SEEN HostRow. This has to
        # occur after the new SantaHost entity is put(), since SantaHost.recorded_dt
        # is an auto_now_add.
        if first_seen:
            new_host = ndb.Key('Host', uuid).get()
            tables.HOST.InsertRow(device_id=uuid,
                                  timestamp=new_host.recorded_dt,
                                  action=constants.HOST_ACTION.FIRST_SEEN,
                                  hostname=new_host.hostname,
                                  platform=constants.PLATFORM.MACOS,
                                  users=[new_host.primary_user],
                                  mode=new_host.client_mode)

        # If there was a user change, create a USERS_CHANGE HostRow.
        if users_change:
            tables.HOST.InsertRow(device_id=uuid,
                                  timestamp=self.host.recorded_dt,
                                  action=constants.HOST_ACTION.USERS_CHANGE,
                                  hostname=self.host.hostname,
                                  platform=constants.PLATFORM.MACOS,
                                  users=[self.host.primary_user],
                                  mode=self.host.client_mode)

        self.respond_json(response)
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS-IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Unit tests for user.py."""

from upvote.gae import settings
from upvote.gae.datastore import test_utils
from upvote.gae.datastore.models import user as user_models
from upvote.gae.lib.testing import basetest
from upvote.gae.utils import user_utils
from upvote.shared import constants

_TEST_EMAIL = user_utils.UsernameToEmail('testemail')

# Done for the sake of brevity.
USER = constants.USER_ROLE.USER
TRUSTED_USER = constants.USER_ROLE.TRUSTED_USER
ADMINISTRATOR = constants.USER_ROLE.ADMINISTRATOR


class UserTest(basetest.UpvoteTestCase):
    """Test User model."""
    def setUp(self):
        super(UserTest, self).setUp()
        self._voting_weights = settings.VOTING_WEIGHTS

        self.PatchEnv(settings.ProdEnv, ENABLE_BIGQUERY_STREAMING=True)
示例#8
0
def RandomEmail():
    return user_utils.UsernameToEmail('noreply+%s' % RandomLetters(8))
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(host_models.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 host_models.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_utils.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 = host_models.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)
示例#10
0
 def testStr_Whitespace(self):
     expected = [user_utils.UsernameToEmail('aaa')]
     actual = mail_utils._SanitizeAddrs('  aaa  ')
     self.assertEqual(expected, actual)
示例#11
0
 def testList_Email(self):
     expected = [user_utils.UsernameToEmail('aaa')]
     actual = mail_utils._SanitizeAddrs([user_utils.UsernameToEmail('aaa')])
     self.assertListEqual(expected, actual)
示例#12
0
 def testUsernameToEmail(self):
   self.assertEqual('user@' + settings.USER_EMAIL_DOMAIN,
                    user_utils.UsernameToEmail('user'))
示例#13
0
 def testAdminGetUnknownUser(self):
   """Admin attempting to get information on an unknown user."""
   with self.LoggedInUser(admin=True):
     unknown_user = user_utils.UsernameToEmail('blahblahblah')
     self.testapp.get(self.ROUTE % unknown_user, status=httplib.NOT_FOUND)