Esempio n. 1
0
  def testIsAllowedToViewPacakgesProposalsOff(self):
    """Test PermissionResolver._IsAllowedToViewPackages() without proposals."""
    test_resolver = auth.PermissionResolver('task')
    email_one = '*****@*****.**'
    email_two = '*****@*****.**'
    email_three = '*****@*****.**'

    setattr(auth.settings, 'ENABLE_PROPOSALS_GROUP', False)
    setattr(auth.settings, 'PROPOSALS_GROUP', '')

    self.mox.StubOutWithMock(auth, 'DoUserAuth')
    self.mox.StubOutWithMock(auth, 'IsAdminUser')
    self.mox.StubOutWithMock(auth, 'IsSupportUser')
    auth.IsAdminUser(email_one).AndReturn(True)
    auth.IsAdminUser(email_two).AndReturn(False)
    auth.IsSupportUser(email_two).AndReturn(True)
    auth.IsAdminUser(email_three).AndReturn(False)
    auth.IsSupportUser(email_three).AndReturn(False)

    self.mox.ReplayAll()
    test_resolver.email = email_one
    self.assertTrue(test_resolver._IsAllowedToViewPackages())
    test_resolver.email = email_two
    self.assertTrue(test_resolver._IsAllowedToViewPackages())
    test_resolver.email = email_three
    self.assertFalse(test_resolver._IsAllowedToViewPackages())
    self.mox.VerifyAll()
Esempio n. 2
0
  def get(self):
    """Handle GET."""

    try:
      # already munki authenticated?  return, nothing to do.
      gaeserver.DoMunkiAuth()
      #logging.info('Uauth: session is already authenticated')
      return
    except gaeserver.NotAuthenticated:
      pass

    user = users.get_current_user()
    if not user:
      #logging.error('Uauth: user is not logged in')
      raise NotAuthenticated

    email = user.email()
    if auth.IsAdminUser(email):
      a = gaeserver.AuthSimianServer()
      output = a.SessionCreateUserAuthToken(email, level=gaeserver.LEVEL_ADMIN)
    elif auth.IsSupportUser(email):
      a = gaeserver.AuthSimianServer()
      output = a.SessionCreateUserAuthToken(email, level=gaeserver.LEVEL_BASE)
    else:
      logging.error('Uauth: user %s is not an admin', email)
      raise NotAuthenticated

    if output:
      #logging.info('Uauth: success, token = %s', output)
      self.response.headers['Set-Cookie'] = '%s=%s; secure; httponly;' % (
          auth_init.AUTH_TOKEN_COOKIE, output)
      self.response.out.write(auth_init.AUTH_TOKEN_COOKIE)
    else:
      #logging.info('Uauth: unknown token')
      raise NotAuthenticated
Esempio n. 3
0
    def post(self, uuid=None):
        """POST handler."""
        if not self.IsAdminUser() and not auth.IsSupportUser():
            self.response.set_status(403)
            return

        action = self.request.get('action')

        if action == 'set_inactive':
            c = models.Computer.get_by_key_name(uuid)
            if not c:
                self.response.out.write('UUID not found')
                return
            c.active = False
            c.put(update_active=False)
            msg = 'Host set as inactive.'

        elif action == 'upload_logs':
            c = models.Computer.get_by_key_name(uuid)
            if not c:
                self.response.set_status(404)
                return
            c.upload_logs_and_notify = users.get_current_user().email()
            c.put()
            self.response.set_status(200)
            self.response.headers['Content-Type'] = 'application/json'
            self.response.out.write(
                json.dumps({'email': c.upload_logs_and_notify}))
            return

        else:
            self.response.set_status(400)
            return

        self.redirect('/admin/host/%s?msg=%s' % (uuid, msg))
Esempio n. 4
0
    def _DisplayHost(self, uuid=None, computer=None):
        """Displays the report for a single host.

    Args:
      uuid: str uuid for host to display.
      computer: models.Computer object to display.
    """
        if not computer:
            computer = models.Computer.get_by_key_name(uuid)
        else:
            uuid = computer.uuid
        client_log_files = models.ClientLogFile.all().filter(
            'uuid =', uuid).order('-mtime').fetch(100)
        msu_log = models.ComputerMSULog.all().filter(
            'uuid =', uuid).order('-mtime').fetch(100)
        applesus_installs = models.InstallLog.all().filter(
            'uuid =', uuid).filter(
                'applesus =',
                True).order('-mtime').fetch(SINGLE_HOST_DATA_FETCH_LIMIT)
        installs = models.InstallLog.all().filter('uuid =', uuid).filter(
            'applesus =',
            False).order('-mtime').fetch(SINGLE_HOST_DATA_FETCH_LIMIT)
        exits = models.PreflightExitLog.all().filter(
            'uuid =', uuid).order('-mtime').fetch(SINGLE_HOST_DATA_FETCH_LIMIT)
        install_problems = models.ClientLog.all().filter(
            'action =', 'install_problem').filter(
                'uuid =',
                uuid).order('-mtime').fetch(SINGLE_HOST_DATA_FETCH_LIMIT)
        uptime = None
        if computer:
            AddTimezoneToComputerDatetimes(computer)
            computer.connection_dates.reverse()
            computer.connection_datetimes.reverse()
            if computer.uptime:
                uptime_days = datetime.timedelta(seconds=computer.uptime).days
                uptime_hms = time.strftime('%H:%M:%S',
                                           time.gmtime(computer.uptime))
                uptime = '%d days, %s' % (uptime_days, uptime_hms)
            else:
                uptime = 'unknown'

        values = {
            'uuid_lookup_url': settings.UUID_LOOKUP_URL,
            'owner_lookup_url': settings.OWNER_LOOKUP_URL,
            'computer': computer,
            'applesus_installs': applesus_installs,
            'installs': installs,
            'client_log_files': client_log_files,
            'msu_log': msu_log,
            'install_problems': install_problems,
            'preflight_exits': exits,
            'uptime': uptime,
            'host_report': True,
            'limit': SINGLE_HOST_DATA_FETCH_LIMIT,
            'is_admin': auth.IsAdminUser(),
            'is_support_user': auth.IsSupportUser(),
            'is_security_user': auth.IsSecurityUser(),
        }
        self.response.out.write(
            RenderTemplate('templates/stats_host.html', values))
Esempio n. 5
0
    def _DisplayPackagesList(self):
        """Displays list of all installs/removals/etc."""
        installs, counts_mtime = models.ReportsCache.GetInstallCounts()
        pending, pending_mtime = models.ReportsCache.GetPendingCounts()
        packages = []
        all_packages = self.request.get('all_packages') == '1'
        query = self._GetPackageQuery()
        for p in query:
            if not p.plist:
                self.error(httplib.FORBIDDEN)
                self.response.out.write('Package %s has a broken plist!' %
                                        p.filename)
                return
            pkg = {}
            pkg['count'] = installs.get(p.munki_name,
                                        {}).get('install_count', 'N/A')
            pkg['fail_count'] = installs.get(p.munki_name,
                                             {}).get('install_fail_count',
                                                     'N/A')
            pkg['pending_count'] = pending.get(p.munki_name, 'N/A')
            pkg['duration_seconds_avg'] = installs.get(p.munki_name, {}).get(
                'duration_seconds_avg', None) or 'N/A'
            pkg['unattended'] = p.plist.get('unattended_install', False)
            pkg['unattended_uninstall'] = p.plist.get('unattended_uninstall',
                                                      False)
            force_install_after_date = p.plist.get('force_install_after_date',
                                                   None)
            if force_install_after_date:
                pkg['force_install_after_date'] = force_install_after_date
            pkg['catalogs'] = p.catalog_matrix
            pkg['manifests'] = p.manifest_matrix
            pkg['munki_name'] = p.munki_name or p.plist.GetMunkiName()
            pkg['filename'] = p.filename
            pkg['file_size'] = p.plist.get('installer_item_size', 0) * 1024
            pkg['install_types'] = p.install_types
            pkg['manifest_mod_access'] = p.manifest_mod_access
            pkg['description'] = p.description
            pkg['plist_is_signed'] = p.plist_is_signed()
            packages.append(pkg)

        packages.sort(key=lambda pkg: pkg['munki_name'].lower())

        self.Render(
            self.TEMPLATE, {
                'packages': packages,
                'counts_mtime': counts_mtime,
                'pending_mtime': pending_mtime,
                'report_type': self.REPORT_TYPE,
                'active_pkg': self.request.GET.get('activepkg'),
                'is_support_user': auth.IsSupportUser(),
                'can_upload': auth.HasPermission(auth.UPLOAD),
                'is_admin': auth.IsAdminUser(),
                'all_packages': all_packages,
            })
Esempio n. 6
0
    def _DisplayMain(self):
        """Displays the main Manifest Modification report."""
        error = self.request.get('error')

        mod_type = self.request.get('mod_type') or 'owner'
        model = models.MANIFEST_MOD_MODELS.get(mod_type)
        if mod_type and not model:
            raise ValueError('Invalid mod_type: %s' % mod_type)
        elif mod_type:
            mods_query = model.all().order('-mtime')

        mods = self.Paginate(mods_query, DEFAULT_MANIFEST_MOD_FETCH_LIMIT)

        is_admin = self.IsAdminUser()
        is_support = False
        is_security = False
        if not is_admin:
            is_support = auth.IsSupportUser()
            if not is_support:
                is_security = auth.IsSecurityUser()
        if is_admin:
            munki_pkg_names = models.PackageInfo.GetManifestModPkgNames(
                common.MANIFEST_MOD_ADMIN_GROUP)
            mod_types = MOD_TYPES
        elif is_support:
            munki_pkg_names = models.PackageInfo.GetManifestModPkgNames(
                common.MANIFEST_MOD_SUPPORT_GROUP)
            mod_types = MOD_GROUP_TYPES[common.MANIFEST_MOD_SUPPORT_GROUP]
        elif is_security:
            munki_pkg_names = models.PackageInfo.GetManifestModPkgNames(
                common.MANIFEST_MOD_SECURITY_GROUP)
            mod_types = MOD_GROUP_TYPES[common.MANIFEST_MOD_SECURITY_GROUP]
        else:
            munki_pkg_names = None
            mod_types = []

        data = {
            'mod_types': mod_types,
            'mod_type': mod_type,
            'mods': mods,
            'error': error,
            'can_add_manifest_mods': is_admin or is_support or is_security,
            'munki_pkg_names': munki_pkg_names,
            'install_types': common.INSTALL_TYPES,
            'manifests': common.TRACKS,
            'report_type': 'manifests_admin',
        }
        self.Render('manifest_modifications.html', data)
 def post(self):
     """POST handler."""
     if self.request.get('add_manifest_mod'):
         if (not self.IsAdminUser() and not auth.IsSupportUser()
                 and not auth.IsSecurityUser()):
             self.response.set_status(httplib.FORBIDDEN)
             return
         self._AddManifestModification()
     elif self.IsAdminUser() and self.request.get('delete'):
         self._DeleteManifestModification()
     elif self.IsAdminUser() and self.request.get('enabled'):
         self._ToggleManifestModification()
     else:
         if not self.IsAdminUser():
             self.response.set_status(httplib.FORBIDDEN)
             return
         self.response.set_status(httplib.NOT_FOUND)
Esempio n. 8
0
    def post(self, uuid=None):
        """POST handler."""
        if not self.IsAdminUser() and not auth.IsSupportUser():
            self.response.set_status(403)
            return

        action = self.request.get('action')
        if action == 'set_fixed':
            uuid = self.request.get('uuid')
            c = models.ComputerClientBroken.get_by_key_name(uuid)
            if not c:
                self.response.out.write('UUID not found')
                return
            c.fixed = True
            c.put()

        self.redirect('/admin/brokenclients')
Esempio n. 9
0
    def post(self, report=None, uuid=None):
        """Stats post handler."""
        #logging.debug('POST called: report=%s, uuid=%s', report, uuid)
        if not auth.IsAdminUser() and not auth.IsSupportUser():
            self.response.set_status(403)
            return

        if report not in ['host', 'clientlog', 'brokenclients']:
            self.response.set_status(404)
            return

        action = self.request.get('action')
        if action == 'set_inactive':
            c = models.Computer.get_by_key_name(uuid)
            if not c:
                self.response.out.write('UUID not found')
                return
            c.active = False
            c.put(update_active=False)
        elif action == 'set_loststolen':
            models.ComputerLostStolen.SetLostStolen(uuid)
        elif action == 'upload_logs':
            c = models.Computer.get_by_key_name(uuid)
            if not c:
                self.response.out.write('UUID not found')
                return
            c.upload_logs_and_notify = users.get_current_user().email()
            c.put()
        elif action == 'delete_client_log':
            key = uuid  # for /admin/clientlog/ it's really the uuid_logname
            l = models.ClientLogFile.get_by_key_name(key)
            l.delete()
            return
        elif action == 'set_fixed':
            c = models.ComputerClientBroken.get_by_key_name(uuid)
            if not c:
                self.response.out.write('UUID not found')
                return
            c.fixed = True
            c.put()
        else:
            self.response.set_status(404)

        self.redirect('/admin/%s/%s' % (report, uuid))
Esempio n. 10
0
    def post(self, uuid=None):
        """POST handler."""
        if not self.IsAdminUser() and not auth.IsSupportUser():
            self.response.set_status(httplib.FORBIDDEN)
            return

        action = self.request.get('action')

        if action == 'set_inactive':
            c = models.Computer.get_by_key_name(uuid)
            if not c:
                self.response.out.write('UUID not found')
                return
            c.active = False
            c.put(update_active=False)
            msg = 'Host set as inactive.'

        elif action == 'upload_logs':
            c = models.Computer.get_by_key_name(uuid)
            if not c:
                self.response.set_status(httplib.NOT_FOUND)
                return
            c.upload_logs_and_notify = users.get_current_user().email()
            c.put()
            self.response.set_status(httplib.OK)
            self.response.headers['Content-Type'] = 'application/json'
            self.response.out.write(
                json.dumps({'email': c.upload_logs_and_notify}))
            return
        elif action == 'delete_client_log':
            key = uuid  # for /admin/clientlog/ it's really the uuid_logname
            l = models.ClientLogFile.get_by_key_name(key)
            if not l:
                self.response.set_status(httplib.NOT_FOUND)
                return
            l.delete()
            return
        else:
            self.response.set_status(httplib.BAD_REQUEST)
            return

        self.redirect('/admin/host/%s?msg=%s' % (uuid, msg))
Esempio n. 11
0
  def testDoUserAuthWithAllDomainUsersOff(self):
    self.stubs.Set(auth.settings, 'ALLOW_ALL_DOMAIN_USERS_READ_ACCESS', False)
    self.stubs.Set(auth, 'users', self.mox.CreateMock(auth.users))
    self.mox.StubOutWithMock(auth, 'IsAdminUser')
    self.mox.StubOutWithMock(auth, 'IsSupportUser')
    self.mox.StubOutWithMock(auth, 'IsSecurityUser')
    self.mox.StubOutWithMock(auth, 'IsPhysicalSecurityUser')

    mock_user = self.mox.CreateMockAnything()
    email = '*****@*****.**'
    auth.users.get_current_user().AndReturn(mock_user)
    mock_user.email().AndReturn(email)

    auth.IsAdminUser(email).AndReturn(False)
    auth.IsSupportUser(email).AndReturn(False)
    auth.IsSecurityUser(email).AndReturn(False)
    auth.IsPhysicalSecurityUser(email).AndReturn(True)

    self.mox.ReplayAll()
    self.assertEqual(mock_user, auth.DoUserAuth())
    self.mox.VerifyAll()
Esempio n. 12
0
    def post(self, report=None, uuid=None):
        """Misc post handler."""
        if not self.IsAdminUser() and not auth.IsSupportUser():
            self.response.set_status(403)
            return

        if report not in ['clientlog']:
            self.response.set_status(404)
            return

        action = self.request.get('action')
        if action == 'delete_client_log':
            key = uuid  # for /admin/clientlog/ it's really the uuid_logname
            l = models.ClientLogFile.get_by_key_name(key)
            if not l:
                self.response.set_status(404)
                return
            l.delete()
            return
        else:
            self.response.set_status(404)

        self.redirect('/admin/%s/%s' % (report, uuid))
Esempio n. 13
0
  def _DisplayPackagesList(self):
    """Displays list of all installs/removals/etc."""
    installs, counts_mtime = models.ReportsCache.GetInstallCounts()
    pending, pending_mtime = models.ReportsCache.GetPendingCounts()
    packages = []
    for p in models.PackageInfo.all():
      if not p.plist:
        self.error(403)
        self.response.out.write('Package %s has a broken plist!' % p.filename)
        return
      pkg = {}
      pkg['count'] = installs.get(p.munki_name, {}).get('install_count', 'N/A')
      pkg['fail_count'] = installs.get(p.munki_name, {}).get(
          'install_fail_count', 'N/A')
      pkg['pending_count'] = pending.get(p.munki_name, 'N/A')
      pkg['duration_seconds_avg'] = installs.get(p.munki_name, {}).get(
          'duration_seconds_avg', None) or 'N/A'
      pkg['unattended'] = p.plist.get('unattended_install', False)
      force_install_after_date = p.plist.get('force_install_after_date', None)
      if force_install_after_date:
        pkg['force_install_after_date'] = force_install_after_date
      pkg['catalogs'] = p.catalogs
      pkg['manifests'] = p.manifests
      pkg['munki_name'] = p.munki_name or p.plist.GetMunkiName()
      pkg['filename'] = p.filename
      pkg['file_size'] = p.plist.get('installer_item_size', 0) * 1024
      pkg['install_types'] = p.install_types
      pkg['manifest_mod_access'] = p.manifest_mod_access
      pkg['description'] = p.description
      packages.append(pkg)

    packages.sort(key=lambda pkg: pkg['munki_name'].lower())
    self.Render('packages.html',
        {'packages': packages, 'counts_mtime': counts_mtime,
         'pending_mtime': pending_mtime, 'report_type': 'packages',
         'active_pkg': self.request.GET.get('activepkg'),
         'is_support_user': auth.IsSupportUser()})
    def _DisplayMain(self):
        """Displays the main Manifest Modification report."""
        error_msg = self.request.get('error')

        mod_type = self.request.get('mod_type') or 'owner'
        model = models.MANIFEST_MOD_MODELS.get(mod_type)
        if mod_type and not model:
            error_msg = 'Unknown mod_type provided; defaulting to owner'
            mod_type = 'owner'
            model = models.MANIFEST_MOD_MODELS.get(mod_type)

        mods_query = model.all().order('-mtime')

        filter_value = self.request.get('filter_value')
        filter_field = self.request.get('filter_field')
        if filter_value:
            if filter_field == 'target':
                mods_query.filter(model.TARGET_PROPERTY_NAME, filter_value)
            elif filter_field == 'package':
                mods_query.filter('value', filter_value)
            elif filter_field == 'admin':
                if '@' not in filter_value:
                    filter_value += '@' + settings.AUTH_DOMAIN
                mods_query.filter('user', users.User(email=filter_value))

        mods = self.Paginate(mods_query, DEFAULT_MANIFEST_MOD_FETCH_LIMIT)

        is_admin = self.IsAdminUser()
        is_support = False
        is_security = False
        if not is_admin:
            is_support = auth.IsSupportUser()
            if not is_support:
                is_security = auth.IsSecurityUser()
        if is_admin:
            munki_pkg_names = models.PackageInfo.GetManifestModPkgNames(
                common.MANIFEST_MOD_ADMIN_GROUP)
            mod_types = MOD_TYPES
        elif is_support:
            munki_pkg_names = models.PackageInfo.GetManifestModPkgNames(
                common.MANIFEST_MOD_SUPPORT_GROUP)
            mod_types = MOD_GROUP_TYPES[common.MANIFEST_MOD_SUPPORT_GROUP]
        elif is_security:
            munki_pkg_names = models.PackageInfo.GetManifestModPkgNames(
                common.MANIFEST_MOD_SECURITY_GROUP)
            mod_types = MOD_GROUP_TYPES[common.MANIFEST_MOD_SECURITY_GROUP]
        else:
            munki_pkg_names = None
            mod_types = []

        data = {
            'mod_types': mod_types,
            'mod_type': mod_type,
            'mods': mods,
            'error': error_msg,
            'can_add_manifest_mods': is_admin or is_support or is_security,
            'munki_pkg_names': munki_pkg_names,
            'install_types': common.INSTALL_TYPES,
            'manifests': common.TRACKS,
            'report_type': 'manifests_admin',
            'mods_filter': filter_field,
            'mods_filter_value': filter_value,
        }
        self.Render('manifest_modifications.html', data)
Esempio n. 15
0
File: pkgs.py Progetto: smusa/simian
    def get(self, filename):
        """GET

    Args:
      filename: str, package filename like 'foo.dmg'
    Returns:
      None if a blob is being returned,
      or a response object
    """
        auth_return = auth.DoAnyAuth()
        if hasattr(auth_return, 'email'):
            email = auth_return.email()
            if not auth.IsAdminUser(email) and not auth.IsSupportUser(email):
                raise auth.IsAdminMismatch

        filename = urllib.unquote(filename)
        pkg = models.PackageInfo.MemcacheWrappedGet(filename)

        if pkg is None or not pkg.blobstore_key:
            self.error(404)
            return

        if common.IsPanicModeNoPackages():
            self.error(503)
            return

        # Get the Blobstore BlobInfo for this package; memcache wrapped.
        memcache_key = 'blobinfo_%s' % filename
        blob_info = memcache.get(memcache_key)
        if not blob_info:
            blob_info = blobstore.BlobInfo.get(pkg.blobstore_key)
            if blob_info:
                memcache.set(memcache_key, blob_info,
                             300)  # cache for 5 minutes.
            else:
                logging.critical(
                    'Failure fetching BlobInfo for %s. Verify the blob exists: %s',
                    pkg.filename, pkg.blobstore_key)
                self.error(404)
                return

        header_date_str = self.request.headers.get('If-Modified-Since', '')
        etag_nomatch_str = self.request.headers.get('If-None-Match', 0)
        etag_match_str = self.request.headers.get('If-Match', 0)
        pkg_date = blob_info.creation
        pkg_size_bytes = blob_info.size

        # TODO(user): The below can be simplified once all of our clients
        # have ETag values set on the filesystem for these files.  The
        # parsing of If-Modified-Since could be removed.  Removing it prematurely
        # will cause a re-download of all packages on all clients for 1 iteration
        # until they all have ETag values.

        # Reduce complexity of elif conditional below.
        # If an If-None-Match: ETag is supplied, don't worry about a
        # missing file modification date -- the ETag supplies everything needed.
        if etag_nomatch_str and not header_date_str:
            resource_expired = False
        else:
            resource_expired = handlers.IsClientResourceExpired(
                pkg_date, header_date_str)

        # Client supplied If-Match: etag, but that etag does not match current
        # etag.  return 412.
        if (etag_match_str and pkg.pkgdata_sha256
                and etag_match_str != pkg.pkgdata_sha256):
            self.response.set_status(412)

        # Client supplied no etag or If-No-Match: etag, and the etag did not
        # match, or the client's file is older than the mod time of this package.
        elif ((etag_nomatch_str and pkg.pkgdata_sha256
               and etag_nomatch_str != pkg.pkgdata_sha256)
              or resource_expired):
            self.response.headers['Content-Disposition'] = str(
                'attachment; filename=%s' % filename)
            # header date empty or package has changed, send blob with last-mod date.
            if pkg.pkgdata_sha256:
                self.response.headers['ETag'] = str(pkg.pkgdata_sha256)
            self.response.headers['Last-Modified'] = pkg_date.strftime(
                handlers.HEADER_DATE_FORMAT)
            self.response.headers['X-Download-Size'] = str(pkg_size_bytes)
            self.send_blob(pkg.blobstore_key)
        else:
            # Client doesn't need to do anything, current version is OK based on
            # ETag and/or last modified date.
            if pkg.pkgdata_sha256:
                self.response.headers['ETag'] = str(pkg.pkgdata_sha256)
            self.response.set_status(304)
Esempio n. 16
0
    def get(self, filename=None):
        """GET handler."""
        if not filename:
            self.error(httplib.NOT_FOUND)
            return
        elif not auth.HasPermission(auth.VIEW_PACKAGES):
            self.error(httplib.FORBIDDEN)
            return

        filename = urllib.unquote(filename)
        p = models.PackageInfo.get_by_key_name(filename)
        if not p:
            self.error(httplib.NOT_FOUND)
            self.Render('error.html',
                        {'message': 'PackageInfo not found: %s' % filename})
            return

        p.name = p.plist['name']
        p.display_name = p.plist.get('display_name', '')
        p.unattended = p.plist.get('unattended_install')
        p.unattended_uninstall = p.plist.get('unattended_uninstall')
        p.version = p.plist['version']
        force_install_after_date = p.plist.get('force_install_after_date',
                                               None)
        if force_install_after_date:
            p.force_install_after_date = datetime.datetime.strftime(
                force_install_after_date, '%Y-%m-%d')
            p.force_install_after_date_time = datetime.datetime.strftime(
                force_install_after_date, '%H:%M')

        if self.request.referrer and self.request.referrer.endswith(
                'proposals'):
            return_address = '/admin/proposals'
            return_title = 'proposals'
        else:
            return_address = '/admin/packages'
            return_title = 'package'

        if self.request.get('plist_xml'):
            self.Render(
                'plist.html', {
                    'report_type': 'packages',
                    'plist_type': 'package_plist',
                    'xml': admin.XmlToHtml(p.plist.GetXml()),
                    'title': 'Plist for %s' % p.name,
                    'raw_xml_link': '/pkgsinfo/%s' % filename,
                })
        else:
            categories = ([
                x.strip() for x in settings.LIST_OF_CATEGORIES.split(',') if x
            ])
            manifests_and_catalogs_unlocked = (
                p.blob_info or p.plist.get('PackageCompleteURL'))
            data = {
                'pkg': p,
                'report_type': 'package',
                'tracks': common.TRACKS,
                'install_types': common.INSTALL_TYPES,
                'manifest_mod_groups': common.MANIFEST_MOD_GROUPS,
                'approval_required': settings.APPROVAL_REQUIRED,
                'is_admin_user': self.IsAdminUser(),
                'is_support_user': auth.IsSupportUser(),
                'pkg_safe_to_modify': p.IsSafeToModify(),
                'editxml': self.request.get('editxml'),
                'manifests_and_catalogs_unlocked':
                manifests_and_catalogs_unlocked,
                'return_address': return_address,
                'return_title': return_title,
                'categories': categories
            }

            self.Render('package.html', data)
Esempio n. 17
0
    def _AddManifestModification(self):
        """Adds a new manifest modification to Datastore."""
        mod_type = self.request.get('mod_type')
        target = self.request.get('target').strip()
        munki_pkg_name = self.request.get('munki_pkg_name').strip()
        manifests = self.request.get_all('manifests')
        install_types = self.request.get_all('install_types')

        # Security users are only able to inject specific packages.
        if not self.IsAdminUser():
            grp = None
            if auth.IsSupportUser():
                grp = common.MANIFEST_MOD_SUPPORT_GROUP
                # Support users can only inject items into optional_installs.
                install_types = ['optional_installs']
            elif auth.IsSecurityUser():
                grp = common.MANIFEST_MOD_SECURITY_GROUP
                # Security users can only inject items into managed_installs.
                install_types = ['managed_installs']

            munki_pkg_names = models.PackageInfo.GetManifestModPkgNames(
                grp, only_names=True)
            if munki_pkg_name not in munki_pkg_names:
                self.response.out.write('You are not allowed to inject: %s' %
                                        munki_pkg_name)
                self.response.set_status(403)
                return
            elif mod_type not in [k for k, v in MOD_GROUP_TYPES.get(grp, [])]:
                self.response.out.write(
                    'You are not allowed to inject to: %s' % mod_type)
                self.response.set_status(403)
                return

        # Validation.
        error_msg = None
        if not target or not munki_pkg_name or not install_types:
            error_msg = (
                'target, munki_pkg_name, and install_types are all required')
        if not error_msg:
            for manifest in manifests:
                if manifest not in common.TRACKS:
                    error_msg = 'manifest %s is not in %s' % (manifest,
                                                              common.TRACKS)
        if not error_msg:
            for install_type in install_types:
                if install_type not in common.INSTALL_TYPES:
                    error_msg = 'install_type %s is not in %s' % (
                        install_type, common.INSTALL_TYPES)
        if not error_msg:
            if not models.PackageInfo.all().filter('name =',
                                                   munki_pkg_name).get():
                error_msg = 'No package found with Munki name: %s' % munki_pkg_name
        if error_msg:
            self.redirect('/admin/manifest_modifications?msg=%s' % error_msg)
            return

        mod = models.BaseManifestModification.GenerateInstance(
            mod_type,
            target,
            munki_pkg_name,
            manifests=manifests,
            install_types=install_types,
            user=users.get_current_user())
        mod.put()
        models.BaseManifestModification.ResetModMemcache(mod_type, target)
        msg = 'Manifest Modification successfully saved.'
        self.redirect('/admin/manifest_modifications?mod_type=%s&msg=%s' %
                      (mod_type, msg))
Esempio n. 18
0
    def get(self, filename=None):
        """GET

    Args:
      filename: string like Firefox-1.0.dmg
    """
        auth_return = auth.DoAnyAuth()
        if hasattr(auth_return, 'email'):
            email = auth_return.email()
            if not any((
                    auth.IsAdminUser(email),
                    auth.IsSupportUser(email),
            )):
                raise auth.IsAdminMismatch

        if filename:
            filename = urllib.unquote(filename)
            hash_str = self.request.get('hash')

            if hash_str:
                lock = models.GetLockForPackage(filename)
                try:
                    lock.Acquire(timeout=30, max_acquire_attempts=5)
                except datastore_locks.AcquireLockError:
                    self.response.set_status(httplib.FORBIDDEN)
                    self.response.out.write('Could not lock pkgsinfo')
                    return

            pkginfo = models.PackageInfo.get_by_key_name(filename)
            if pkginfo:
                self.response.headers[
                    'Content-Type'] = 'text/xml; charset=utf-8'
                if hash_str:
                    self.response.headers['X-Pkgsinfo-Hash'] = self._Hash(
                        pkginfo.plist)
                self.response.out.write(pkginfo.plist)
            else:
                if hash_str:
                    lock.Release()
                self.response.set_status(httplib.NOT_FOUND)
                return

            if hash_str:
                lock.Release()
        else:
            query = models.PackageInfo.all()

            filename = self.request.get('filename')
            if filename:
                query.filter('filename', filename)

            install_types = self.request.get_all('install_types')
            for install_type in install_types:
                query.filter('install_types =', install_type)

            catalogs = self.request.get_all('catalogs')
            for catalog in catalogs:
                query.filter('catalogs =', catalog)

            pkgs = []
            for p in query:
                pkg = {}
                for k in p.properties():
                    if k != '_plist':
                        pkg[k] = getattr(p, k)
                pkgs.append(pkg)
            self.response.out.write('<?xml version="1.0" encoding="UTF-8"?>\n')
            self.response.out.write(plist.GetXmlStr(pkgs))
            self.response.headers['Content-Type'] = 'text/xml; charset=utf-8'
Esempio n. 19
0
    def _DisplayHost(self, uuid=None, computer=None):
        """Displays the report for a single host.

    Args:
      uuid: str uuid for host to display.
      computer: models.Computer object to display.
    """
        if not uuid and not computer:
            self.response.set_status(404)
            return
        elif not computer:
            computer = models.Computer.get_by_key_name(uuid)
        else:
            uuid = computer.uuid

        popup = self.request.get('format', None) == 'popup'
        if popup:
            limit = 1
        else:
            limit = SINGLE_HOST_DATA_FETCH_LIMIT
        client_log_files = models.ClientLogFile.all().filter(
            'uuid =', uuid).order('-mtime').fetch(limit)
        msu_log = models.ComputerMSULog.all().filter(
            'uuid =', uuid).order('-mtime').fetch(limit)
        applesus_installs = models.InstallLog.all().filter(
            'uuid =', uuid).filter('applesus =',
                                   True).order('-mtime').fetch(limit)
        installs = models.InstallLog.all().filter('uuid =', uuid).filter(
            'applesus =', False).order('-mtime').fetch(limit)
        exits = models.PreflightExitLog.all().filter(
            'uuid =', uuid).order('-mtime').fetch(limit)
        install_problems = models.ClientLog.all().filter(
            'action =',
            'install_problem').filter('uuid =',
                                      uuid).order('-mtime').fetch(limit)

        tags = {}
        tags_list = []
        if computer:
            # Generate tags data.
            tags_list = models.Tag.GetAllTagNamesForEntity(computer)
            for tag in tags_list:
                tags[tag] = True
            for tag in models.Tag.GetAllTagNames():
                if tag not in tags:
                    tags[tag] = False
            tags = json.dumps(tags, sort_keys=True)

            admin.AddTimezoneToComputerDatetimes(computer)
            computer.connection_dates.reverse()
            computer.connection_datetimes.reverse()

        try:
            uuid_lookup_url = settings.UUID_LOOKUP_URL
        except AttributeError:
            uuid_lookup_url = None

        try:
            owner_lookup_url = settings.OWNER_LOOKUP_URL
        except AttributeError:
            owner_lookup_url = None

        values = {
            'uuid_lookup_url': uuid_lookup_url,
            'owner_lookup_url': owner_lookup_url,
            'computer': computer,
            'applesus_installs': applesus_installs,
            'installs': installs,
            'client_log_files': client_log_files,
            'msu_log': msu_log,
            'install_problems': install_problems,
            'preflight_exits': exits,
            'tags': tags,
            'tags_list': tags_list,
            'host_report': True,
            'limit': SINGLE_HOST_DATA_FETCH_LIMIT,
            'is_support_user': auth.IsSupportUser(),
            'is_security_user': auth.IsSecurityUser(),
            'is_physical_security_user': auth.IsPhysicalSecurityUser(),
        }

        if popup:
            self.Render('host_popup.html', values)
        else:
            self.Render('host.html', values)
Esempio n. 20
0
    def _DisplayHost(self, computer, self_report):
        """Displays the report for a single host.

    Args:
      computer: models.Computer object to display.
      self_report: if True, display as self report.
    """

        uuid = computer.uuid

        popup = self.request.get('format', None) == 'popup'
        if popup:
            limit = 1
        else:
            limit = SINGLE_HOST_DATA_FETCH_LIMIT
        client_log_files = models.ClientLogFile.all().filter(
            'uuid =', uuid).order('-mtime').fetch(limit)
        msu_log = models.ComputerMSULog.all().filter(
            'uuid =', uuid).order('-mtime').fetch(limit)
        applesus_installs = models.InstallLog.all().filter(
            'uuid =', uuid).filter('applesus =',
                                   True).order('-mtime').fetch(limit)
        installs = models.InstallLog.all().filter('uuid =', uuid).filter(
            'applesus =', False).order('-mtime').fetch(limit)
        exits = models.PreflightExitLog.all().filter(
            'uuid =', uuid).order('-mtime').fetch(limit)
        install_problems = models.ClientLog.all().filter(
            'action =',
            'install_problem').filter('uuid =',
                                      uuid).order('-mtime').fetch(limit)

        tags = {}
        tags_list = []
        groups = {}
        groups_list = []
        duplicates = []
        if computer:
            # Generate tags data.
            tags_list = models.Tag.GetAllTagNamesForEntity(computer)
            for tag in tags_list:
                tags[tag] = True
            for tag in models.Tag.GetAllTagNames():
                if tag not in tags:
                    tags[tag] = False
            tags = json.dumps(tags, sort_keys=True)

            # Generate groups data.
            groups_list = models.Group.GetAllGroupNamesForUser(computer.owner)
            for group in groups_list:
                groups[group] = True
            for group in models.Group.GetAllGroupNames():
                if group not in groups:
                    groups[group] = False
            groups = json.dumps(groups, sort_keys=True)

            admin.AddTimezoneToComputerDatetimes(computer)
            computer.connection_dates.reverse()
            computer.connection_datetimes.reverse()
            duplicates = models.Computer.all().filter(
                'serial =', computer.serial).fetch(20)
            duplicates = [e for e in duplicates if e.uuid != computer.uuid]

        try:
            uuid_lookup_url = settings.UUID_LOOKUP_URL
        except AttributeError:
            uuid_lookup_url = None

        try:
            owner_lookup_url = settings.OWNER_LOOKUP_URL
        except AttributeError:
            owner_lookup_url = None

        values = {
            'report_type': 'host',
            'uuid_lookup_url': uuid_lookup_url,
            'owner_lookup_url': owner_lookup_url,
            'client_site_enabled': settings.CLIENT_SITE_ENABLED,
            'computer': computer,
            'applesus_installs': applesus_installs,
            'installs': installs,
            'client_log_files': client_log_files,
            'msu_log': msu_log,
            'install_problems': install_problems,
            'preflight_exits': exits,
            'tags': tags,
            'tags_list': tags_list,
            'groups': groups,
            'groups_list': groups_list,
            'host_report': True,
            'limit': SINGLE_HOST_DATA_FETCH_LIMIT,
            'is_support_user': auth.IsSupportUser(),
            'is_security_user': auth.IsSecurityUser(),
            'is_physical_security_user': auth.IsPhysicalSecurityUser(),
            'self_report': self_report,
            'duplicates': duplicates,
            'tags_xsrf_token': xsrf.XsrfTokenGenerate('tags'),
            'groups_xsrf_token': xsrf.XsrfTokenGenerate('groups'),
        }

        if popup:
            self.Render('host_popup.html', values)
        else:
            self.Render('host.html', values)
    def _AddManifestModification(self):
        """Adds a new manifest modification to Datastore."""
        mod_type = self.request.get('mod_type')
        targets = [
            x.strip() for x in self.request.get('target').split(',')
            if x.strip()
        ]
        munki_pkg_name = self.request.get('munki_pkg_name').strip()
        manifests = self.request.get_all('manifests')
        install_types = self.request.get_all('install_types')
        remove_from_manifest = bool(self.request.get('remove-from-manifest'))

        # Security users are only able to inject specific packages.
        if not self.IsAdminUser():
            grp = None
            if auth.IsSupportUser():
                grp = common.MANIFEST_MOD_SUPPORT_GROUP
                # Support users can only inject items into optional_installs.
                install_types = ['optional_installs']
            elif auth.IsSecurityUser():
                grp = common.MANIFEST_MOD_SECURITY_GROUP
                # Security users can only inject items into managed_installs.
                install_types = ['managed_installs']

            munki_pkg_names = models.PackageInfo.GetManifestModPkgNames(
                grp, only_names=True)
            if munki_pkg_name not in munki_pkg_names:
                self.response.out.write('You are not allowed to inject: %s' %
                                        munki_pkg_name)
                self.response.set_status(httplib.FORBIDDEN)
                return
            elif mod_type not in [k for k, _ in MOD_GROUP_TYPES.get(grp, [])]:
                self.response.out.write(
                    'You are not allowed to inject to: %s' % mod_type)
                self.response.set_status(httplib.FORBIDDEN)
                return

        # Validation.
        error_msg = None
        if not targets or not munki_pkg_name or not install_types:
            error_msg = (
                'target, munki_pkg_name, and install_types are all required')
        if not error_msg:
            for manifest in manifests:
                if manifest not in common.TRACKS:
                    error_msg = 'manifest %s is not in %s' % (manifest,
                                                              common.TRACKS)
        if not error_msg:
            for install_type in install_types:
                if install_type not in common.INSTALL_TYPES:
                    error_msg = 'install_type %s is not in %s' % (
                        install_type, common.INSTALL_TYPES)
        if not error_msg:
            if not models.PackageInfo.all().filter('name =',
                                                   munki_pkg_name).get():
                error_msg = 'No package found with Munki name: %s' % munki_pkg_name
        if not error_msg and len(targets) > MAX_TARGETS_PER_POST:
            error_msg = 'too many targets'
        if error_msg:
            self.redirect('/admin/manifest_modifications?msg=%s' % error_msg)
            return

        to_put = []
        for target in targets:
            mod = models.BaseManifestModification.GenerateInstance(
                mod_type,
                target,
                munki_pkg_name,
                manifests=manifests,
                install_types=install_types,
                user=users.get_current_user(),
                remove=remove_from_manifest)
            to_put.append(mod)

        gae_util.BatchDatastoreOp(db.put, to_put)
        for target in targets:
            models.BaseManifestModification.ResetModMemcache(mod_type, target)

        msg = 'Manifest Modification successfully saved.'
        self.redirect('/admin/manifest_modifications?mod_type=%s&msg=%s' %
                      (mod_type, msg))
Esempio n. 22
0
    def get(self, filename=None):
        """GET

    Args:
      filename: string like Firefox-1.0.dmg
    """
        auth_return = auth.DoAnyAuth()
        if hasattr(auth_return, 'email'):
            email = auth_return.email()
            if not any((
                    auth.IsAdminUser(email),
                    auth.IsSupportUser(email),
            )):
                raise auth.IsAdminMismatch

        if filename:
            filename = urllib.unquote(filename)
            hash_str = self.request.get('hash')

            if hash_str:
                lock = 'pkgsinfo_%s' % filename
                if not gae_util.ObtainLock(lock, timeout=5.0):
                    self.response.set_status(403)
                    self.response.out.write('Could not lock pkgsinfo')
                    return

            pkginfo = models.PackageInfo.get_by_key_name(filename)
            if pkginfo:
                self.response.headers[
                    'Content-Type'] = 'text/xml; charset=utf-8'
                if hash_str:
                    self.response.headers['X-Pkgsinfo-Hash'] = self._Hash(
                        pkginfo.plist)
                self.response.out.write(pkginfo.plist)
            else:
                if hash_str:
                    gae_util.ReleaseLock(lock)
                self.response.set_status(404)
                return

            if hash_str:
                gae_util.ReleaseLock(lock)
        else:
            query = models.PackageInfo.all()

            filename = self.request.get('filename')
            if filename:
                query.filter('filename', filename)

            install_types = self.request.get_all('install_types')
            for install_type in install_types:
                query.filter('install_types =', install_type)

            catalogs = self.request.get_all('catalogs')
            for catalog in catalogs:
                query.filter('catalogs =', catalog)

            pkgs = []
            for p in query:
                pkg = {}
                for k in p.properties():
                    if k != '_plist':
                        pkg[k] = getattr(p, k)
                pkgs.append(pkg)
            self.response.out.write('<?xml version="1.0" encoding="UTF-8"?>\n')
            self.response.out.write(plist.GetXmlStr(pkgs))
            self.response.headers['Content-Type'] = 'text/xml; charset=utf-8'