コード例 #1
0
ファイル: uploadpkg.py プロジェクト: StrayDawg/simian
    def get(self):
        """GET method.

    With no parameters, return the URL to use to submit uploads via
    multipart/form-data.

    With mode and key parameters, return status of the previous uploadpkg
    operation to the calling client.

    This method actually acts as a helper to the starting and finishing
    of the uploadpkg post() method.

    Parameters:
      mode: optionally, 'success' or 'error'
      key: optionally, blobstore key that was uploaded
    """
        if not handlers.IsHttps(self):
            # TODO(user): Does blobstore support https yet? If so, we can
            # enforce security in app.yaml and not do this check here.
            return

        gaeserver.DoMunkiAuth()

        mode = self.request.get('mode')
        msg = self.request.get('msg', None)
        if mode == 'success':
            self.response.out.write(self.request.get('key'))
        elif mode == 'error':
            self.response.set_status(400)
            self.response.out.write(msg)
        else:
            upload_url = blobstore.create_upload_url(
                '/uploadpkg', gs_bucket_name=util.GetBlobstoreGSBucket())
            self.response.out.write(upload_url)
コード例 #2
0
ファイル: auth.py プロジェクト: timhberry/simian
def DoAnyAuth(is_admin=None, require_level=None):
    """Verify that any form of auth has occured.

  Includes DoUserAuth and gaeserver.DoMunkiAuth.

  Args:
    is_admin: bool, default False, when True,
        requires that the user is an admin.
    require_level: int, default None, when defined,
        requires that a session be at level x.
  Returns:
    users.User() object if DoUserAuth succeeded
    models.AuthSession entity if DoMunkiAuth succeeded
  Raises:
    NotAuthenticated: there is no authentication user for this request.
    IsAdminMismatch: the current user is not an administrator.
    gaeserver.NotAuthenticated: there is no authentication user for this
        request.
  """
    # TODO(user): The unexpected return of two different return classes
    # here can be hard to code around.  We should fix this someday if we
    # start using the return value more frequently, rather than just
    # calling this as a procedure to cause auth to occur.
    try:
        return DoUserAuth(is_admin=is_admin)
    except IsAdminMismatch:
        raise
    except NotAuthenticated:
        pass

    # gaeserver.NotAuthenticated will be raised in the case of failure.
    return gaeserver.DoMunkiAuth(require_level=require_level)
コード例 #3
0
ファイル: auth.py プロジェクト: timhberry/simian
    def get(self):
        """GET."""
        logout = self.request.get('logout')

        session = gaeserver.DoMunkiAuth()
        if logout:
            gaeserver.LogoutSession(session)
コード例 #4
0
ファイル: applesus.py プロジェクト: timhberry/simian
    def post(self):
        """Returns auth token for get method."""
        session = gaeserver.DoMunkiAuth()

        asd = gaeserver.AuthSessionSimianServer()
        token = None
        for s in asd.GetByUuid(session.uuid):
            if s.level != gaeserver.LEVEL_APPLESUS:
                continue
            if asd.IsExpired(s):
                continue

            assert s.key().name().startswith('t_')
            token = s.key().name()[2:]

        if not token:
            auth1 = gaeserver.AuthSimianServer()
            # create new token suitable only for applesus.
            # original token will be destroyed on postflight.
            token = auth1.SessionCreateUserAuthToken(
                session.uuid, level=gaeserver.LEVEL_APPLESUS)

        munki_header = self.request.headers.get(MUNKI_CLIENT_ID_HEADER_KEY, '')
        # Also store munki header, which contain OS X version and track.
        d = {
            'cookies': auth.CreateAuthTokenCookieStr(token),
            'header': self._SanitazeMunkiHeader(munki_header),
        }

        self.response.out.write(_EncodeMsg(d))
コード例 #5
0
ファイル: uauth.py プロジェクト: zeroluck/simian
  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
コード例 #6
0
ファイル: pkgsinfo.py プロジェクト: timhberry/simian
    def put(self, filename):
        """PUT

    Args:
      filename: string like Firefox-1.0.dmg
    """
        session = gaeserver.DoMunkiAuth(
            require_level=gaeserver.LEVEL_UPLOADPKG)

        filename = urllib.unquote(filename)
        hash_str = self.request.get('hash')
        catalogs = self.request.get('catalogs', None)
        manifests = self.request.get('manifests', None)
        install_types = self.request.get('install_types')

        if catalogs == '':
            catalogs = []
        elif catalogs:
            catalogs = catalogs.split(',')
        if manifests == '':
            manifests = []
        elif manifests:
            manifests = manifests.split(',')
        if install_types:
            install_types = install_types.split(',')

        mpl = MunkiPackageInfoPlistStrict(self.request.body)
        try:
            mpl.Parse()
        except plist.PlistError, e:
            logging.exception('Invalid pkginfo plist PUT: \n%s\n',
                              self.request.body)
            self.response.set_status(httplib.BAD_REQUEST)
            self.response.out.write(str(e))
            return
コード例 #7
0
ファイル: deletepkg.py プロジェクト: zeroluck/simian
  def post(self):
    """POST

    Parameters:
      filename: filename of package e.g. 'Firefox-1.0.dmg'
    """
    session = gaeserver.DoMunkiAuth(require_level=gaeserver.LEVEL_UPLOADPKG)

    filename = self.request.get('filename')
    pkginfo = models.PackageInfo.get_by_key_name(filename)
    if not pkginfo:
      self.response.set_status(404)
      self.response.out.write('Pkginfo does not exist: %s' % filename)
      return

    plist = pkginfo.plist
    catalogs = pkginfo.catalogs
    install_types = pkginfo.install_types

    #logging.info('Deleting package: %s', filename)
    blobstore_key = pkginfo.blobstore_key
    # Delete the PackageInfo entity, and then the package Blobstore entity.
    pkginfo.delete()
    gae_util.SafeBlobDel(blobstore_key)
    # Recreate catalogs so references to this package don't exist anywhere.
    for catalog in catalogs:
      models.Catalog.Generate(catalog)

    # Log admin delete to Datastore.
    user = session.uuid
    admin_log = models.AdminPackageLog(
        user=user, action='deletepkg', filename=filename, catalogs=catalogs,
        install_types=install_types, plist=plist)
    admin_log.put()
コード例 #8
0
ファイル: uploadfile.py プロジェクト: tristansgray/simian
    def put(self, file_type=None, file_name=None):
        """UploadFile PUT handler.

    Returns:
      A webapp.Response() response.
    """
        session = gaeserver.DoMunkiAuth()
        uuid = main_common.SanitizeUUID(session.uuid)

        if not file_type or not file_name:
            logging.warning('file_type=%s , file_name=%s', file_type,
                            file_name)
            self.error(httplib.NOT_FOUND)
            return

        if file_type == 'log':
            key = '%s_%s' % (uuid, file_name)
            l = models.ClientLogFile(key_name=key)
            l.log_file = self.request.body
            l.uuid = uuid
            l.name = file_name
            try:
                l.put()
            except (apiproxy_errors.RequestTooLargeError,
                    datastore_errors.BadRequestError):
                # detastore raises BadRequestError now, if file too large.
                logging.warning(
                    'UploadFile may be log too large; truncating...')
                # Datastore has a 1MB entity limit and models.ClientLogFile.log_file
                # uses zlib compression. Anecdotal evidence of a handlful of log files
                # over 8MB in size compress down to well under 1MB. Therefore, slice
                # the top of the log data off at a conversative max, before retrying the
                # Datastore put.
                max_log_size_bytes = 5 * 1024 * 1024
                l.log_file = (
                    '*** Log truncated by Simian due to size ***\n\n' +
                    self.request.body[-1 * max_log_size_bytes:])
                l.put()

            c = models.Computer.get_by_key_name(uuid)
            recipients = c.upload_logs_and_notify
            c.upload_logs_and_notify = None
            c.put()

            # c.upload_logs_and_notify may be None from a previous upload, as multiple
            # files may be uploaded in different requests per execution.
            if recipients:
                recipients = recipients.split(',')
                deferred.defer(SendNotificationEmail, recipients, c,
                               settings.SERVER_HOSTNAME)
        else:
            self.error(httplib.NOT_FOUND)
コード例 #9
0
ファイル: applesus.py プロジェクト: timhberry/simian
    def get(self, msg='', unused_provided_by_softwareupdate=''):
        """AppleSUS get handler.

    Args:
      name: str, catalog name to get.
      unused_provided_by_softwareupdate: Apple softwareupdate appends filename
        to our url.
    """
        if msg:
            # Clients first POST to this handler and receive a URL with an embedded,
            # encrypted cookie-set containing an Auth1Token.  When GET is called on
            # this URL, we must decode and unpack the cookie/Auth1Token, and set
            # the HTTP_COOKIE environment variable for DoMunkiAuth to validate.
            try:
                d = _DecodeMsg(msg)
            except ValueError:
                self.response.set_status(httplib.BAD_REQUEST)
                return
            os.environ['HTTP_COOKIE'] = str(d['cookies'])
            self.request.headers[MUNKI_CLIENT_ID_HEADER_KEY] = d['header']

        session = gaeserver.DoMunkiAuth(require_level=gaeserver.LEVEL_APPLESUS)
        client_id = handlers.GetClientIdForRequest(self.request,
                                                   session=session)

        # get only major.minor os_version, stripping miniscule versioning.
        # i.e. 10.6.6 becomes 10.6, 10.23.6.x.x becomes 10.23
        full_os_version = client_id.get('os_version', '')
        os_version = '.'.join(full_os_version.split('.', 2)[:2])
        track = client_id.get('track', 'stable')
        catalog_name = '%s_%s' % (os_version, track)

        catalog = models.AppleSUSCatalog.MemcacheWrappedGet(catalog_name)
        if not catalog:
            logging.warning('Apple SUS catalog not found: %s', catalog_name)
            self.response.set_status(httplib.NOT_FOUND)
            return

        header_date_str = self.request.headers.get('If-Modified-Since', '')
        catalog_date = catalog.mtime
        if handlers.IsClientResourceExpired(catalog_date, header_date_str):
            self.response.headers['Last-Modified'] = catalog_date.strftime(
                handlers.HEADER_DATE_FORMAT)
            self.response.headers['Content-Type'] = 'text/xml; charset=utf-8'
            self.response.out.write(catalog.plist)
        else:
            self.response.set_status(httplib.NOT_MODIFIED)
コード例 #10
0
ファイル: applesus.py プロジェクト: smusa/simian
  def put(self, name):
    """AppleSUS put handler.

    Args:
      name: str, catalog name to put.
    """
    gaeserver.DoMunkiAuth(require_level=gaeserver.LEVEL_UPLOADPKG)

    # try loading for validation's sake
    c = plist.AppleSoftwareCatalogPlist(self.request.body)
    try:
      c.Parse()
    except plist.PlistError, e:
      logging.exception('Invalid Apple SUS catalog format: %s', str(e))
      self.response.set_status(400)
      self.response.out.write(str(e))
      return
コード例 #11
0
ファイル: uploadpkg.py プロジェクト: StrayDawg/simian
    def post(self):
        """POST method.

    This method behaves a little strangely.  BlobstoreUploadHandler
    only allows returns statuses of 301, 302, 303 (not even 200), so
    one must redirect away to return more information to the caller.

    Parameters:
      file: package file contents
      pkginfo: packageinfo file contents
      name: filename of package e.g. 'Firefox-1.0.dmg'
    """
        # Only blobstore/upload service/scotty requests should be
        # invoking this handler.
        if not handlers.IsBlobstore():
            logging.critical('POST to /uploadpkg not from Blobstore: %s',
                             self.request.headers)
            self.redirect('/')

        gaeserver.DoMunkiAuth(require_level=gaeserver.LEVEL_UPLOADPKG)

        user = self.request.get('user')
        filename = self.request.get('name')
        install_types = self.request.get('install_types')
        catalogs = self.request.get('catalogs', None)
        manifests = self.request.get('manifests', None)
        if catalogs is None or not install_types or not user or not filename:
            msg = 'uploadpkg POST required parameters missing'
            logging.error(msg)
            self.redirect('/uploadpkg?mode=error&msg=%s' % msg)
            return
        if catalogs == '':
            catalogs = []
        else:
            catalogs = catalogs.split(',')
        if manifests in ['', None]:
            manifests = []
        else:
            manifests = manifests.split(',')
        install_types = install_types.split(',')

        upload_files = self.get_uploads('file')
        upload_pkginfo_files = self.get_uploads('pkginfo')
        if not len(upload_pkginfo_files) and not self.request.get('pkginfo'):
            self.redirect('/uploadpkg?mode=error&msg=No%20file%20received')
            return

        if len(upload_pkginfo_files):
            # obtain the pkginfo from a blob, and then throw it away.  this is
            # a necessary hack because the upload handler grabbed it, but we don't
            # intend to keep it in blobstore.
            pkginfo_str = gae_util.GetBlobAndDel(upload_pkginfo_files[0].key())
        else:
            # otherwise, grab the form parameter.
            pkginfo_str = self.request.get('pkginfo')

        blob_info = upload_files[0]
        blobstore_key = str(blob_info.key())

        # Parse, validate, and encode the pkginfo plist.
        plist = plist_lib.MunkiPackageInfoPlist(pkginfo_str)
        try:
            plist.Parse()
        except plist_lib.PlistError:
            logging.exception('Invalid pkginfo plist uploaded:\n%s\n',
                              pkginfo_str)
            gae_util.SafeBlobDel(blobstore_key)
            self.redirect(
                '/uploadpkg?mode=error&msg=No%20valid%20pkginfo%20received')
            return

        filename = plist['installer_item_location']
        pkgdata_sha256 = plist['installer_item_hash']

        # verify the blob was actually written; in case Blobstore failed to write
        # the blob but still POSTed to this handler (very, very rare).
        blob_info = blobstore.BlobInfo.get(blobstore_key)
        if not blob_info:
            logging.critical(
                'Blobstore returned a key for %s that does not exist: %s',
                filename, blobstore_key)
            self.redirect('/uploadpkg?mode=error&msg=Blobstore%20failure')
            return

        # Obtain a lock on the PackageInfo entity for this package.
        lock = 'pkgsinfo_%s' % filename
        if not gae_util.ObtainLock(lock, timeout=5.0):
            gae_util.SafeBlobDel(blobstore_key)
            self.redirect(
                '/uploadpkg?mode=error&msg=Could%20not%20lock%20pkgsinfo')
            return

        old_blobstore_key = None
        pkg = models.PackageInfo.get_or_insert(filename)
        if not pkg.IsSafeToModify():
            gae_util.ReleaseLock(lock)
            gae_util.SafeBlobDel(blobstore_key)
            self.redirect(
                '/uploadpkg?mode=error&msg=Package%20is%20not%20modifiable')
            return

        if pkg.blobstore_key:
            # a previous blob exists.  delete it when the update has succeeded.
            old_blobstore_key = pkg.blobstore_key

        pkg.blobstore_key = blobstore_key
        pkg.name = plist.GetPackageName()
        pkg.filename = filename
        pkg.user = user
        pkg.catalogs = catalogs
        pkg.manifests = manifests
        pkg.install_types = install_types
        pkg.plist = plist
        pkg.pkgdata_sha256 = pkgdata_sha256

        # update the PackageInfo model with the new plist string and blobstore key.
        try:
            pkg.put()
            success = True
        except db.Error:
            logging.exception('error on PackageInfo.put()')
            success = False

        # if it failed, delete the blob that was just uploaded -- it's
        # an orphan.
        if not success:
            gae_util.SafeBlobDel(blobstore_key)
            # if this is a new entity (get_or_insert puts), attempt to delete it.
            if not old_blobstore_key:
                gae_util.SafeEntityDel(pkg)
            gae_util.ReleaseLock(lock)
            self.redirect('/uploadpkg?mode=error')
            return

        # if an old blob was associated with this Package, delete it.
        # the new blob that was just uploaded has replaced it.
        if old_blobstore_key:
            gae_util.SafeBlobDel(old_blobstore_key)

        gae_util.ReleaseLock(lock)

        # Generate catalogs for newly uploaded pkginfo plist.
        for catalog in pkg.catalogs:
            models.Catalog.Generate(catalog, delay=1)

        # Log admin upload to Datastore.
        admin_log = models.AdminPackageLog(user=user,
                                           action='uploadpkg',
                                           filename=filename,
                                           catalogs=catalogs,
                                           manifests=manifests,
                                           install_types=install_types,
                                           plist=pkg.plist.GetXml())
        admin_log.put()

        self.redirect('/uploadpkg?mode=success&key=%s' % blobstore_key)
コード例 #12
0
    def post(self):
        """Reports get handler.

    Returns:
      A webapp.Response() response.
    """
        session = gaeserver.DoMunkiAuth()
        uuid = main_common.SanitizeUUID(session.uuid)
        report_type = self.request.get('_report_type')
        feedback_requested = self.request.get('_feedback')
        message = None
        details = None
        client_id = None
        computer = None

        if report_type == 'preflight' or report_type == 'postflight':
            client_id_str = urllib.unquote(self.request.get('client_id'))
            client_id = common.ParseClientId(client_id_str, uuid=uuid)
            user_settings_str = self.request.get('user_settings')
            user_settings = None
            try:
                if user_settings_str:
                    user_settings = util.Deserialize(
                        urllib.unquote(str(user_settings_str)))
            except util.DeserializeError:
                logging.warning('Client %s sent broken user_settings: %s',
                                client_id_str, user_settings_str)

            pkgs_to_install = self.request.get_all('pkgs_to_install')
            apple_updates_to_install = self.request.get_all(
                'apple_updates_to_install')

            computer = models.Computer.get_by_key_name(uuid)
            ip_address = os.environ.get('REMOTE_ADDR', '')
            report_feedback = None
            if report_type == 'preflight':
                # if the UUID is known to be lost/stolen, log this connection.
                if models.ComputerLostStolen.IsLostStolen(uuid):
                    logging.warning('Connection from lost/stolen machine: %s',
                                    uuid)
                    models.ComputerLostStolen.LogLostStolenConnection(
                        computer=computer, ip_address=ip_address)

                # we want to get feedback now, before preflight_datetime changes.
                if feedback_requested:
                    client_exit = self.request.get('client_exit', None)
                    report_feedback = self.GetReportFeedback(
                        uuid,
                        report_type,
                        computer=computer,
                        ip_address=ip_address,
                        client_exit=client_exit)
                    self.response.out.write(report_feedback)

                    # if report feedback calls for a client exit, log it.
                    if report_feedback == common.ReportFeedback.EXIT:
                        if not client_exit:
                            # client didn't ask for an exit, which means server decided.
                            client_exit = 'Connection from defined exit IP address'
                        common.WriteClientLog(models.PreflightExitLog,
                                              uuid,
                                              computer=computer,
                                              exit_reason=client_exit)

            common.LogClientConnection(report_type,
                                       client_id,
                                       user_settings,
                                       pkgs_to_install,
                                       apple_updates_to_install,
                                       computer=computer,
                                       ip_address=ip_address,
                                       report_feedback=report_feedback)

        elif report_type == 'install_report':
            computer = models.Computer.get_by_key_name(uuid)

            self._LogInstalls(self.request.get_all('installs'), computer)

            for removal in self.request.get_all('removals'):
                common.WriteClientLog(models.ClientLog,
                                      uuid,
                                      computer=computer,
                                      action='removal',
                                      details=removal)

            for problem in self.request.get_all('problem_installs'):
                common.WriteClientLog(models.ClientLog,
                                      uuid,
                                      computer=computer,
                                      action='install_problem',
                                      details=problem)
        elif report_type == 'preflight_exit':
            # NOTE(user): only remains for older clients.
            message = self.request.get('message')
            computer = common.WriteClientLog(models.PreflightExitLog,
                                             uuid,
                                             exit_reason=message)
        elif report_type == 'broken_client':
            # Default reason of "objc" to support legacy clients, existing when objc
            # was the only broken state ever reported.
            reason = self.request.get('reason', 'objc')
            details = self.request.get('details')
            logging.warning('Broken Munki client (%s): %s', reason, details)
            common.WriteBrokenClient(uuid, reason, details)
        elif report_type == 'msu_log':
            details = {}
            for k in ['time', 'user', 'source', 'event', 'desc']:
                details[k] = self.request.get(k, None)
            common.WriteComputerMSULog(uuid, details)
        else:
            # unknown report type; log all post params.
            params = []
            for param in self.request.arguments():
                params.append('%s=%s' % (param, self.request.get_all(param)))
            common.WriteClientLog(models.ClientLog,
                                  uuid,
                                  action='unknown',
                                  details=str(params))

        # If the client asked for feedback, get feedback and respond.
        # Skip this if the report_type is preflight, as report feedback was
        # retrieved before LogComputerConnection changed preflight_datetime.
        if feedback_requested and report_type != 'preflight':
            self.response.out.write(
                self.GetReportFeedback(
                    uuid,
                    report_type,
                    message=message,
                    details=details,
                    computer=computer,
                ))
コード例 #13
0
    def post(self):
        """Reports get handler.

    Returns:
      A webapp.Response() response.
    """
        session = gaeserver.DoMunkiAuth()
        uuid = main_common.SanitizeUUID(session.uuid)
        report_type = self.request.get('_report_type')
        report_feedback = {}
        message = None
        details = None
        client_id = None
        computer = None

        if report_type == 'preflight' or report_type == 'postflight':
            client_id_str = urllib.unquote(self.request.get('client_id'))
            client_id = common.ParseClientId(client_id_str, uuid=uuid)
            user_settings_str = self.request.get('user_settings')
            user_settings = None
            try:
                if user_settings_str:
                    user_settings = util.Deserialize(
                        urllib.unquote(str(user_settings_str)))
            except util.DeserializeError:
                logging.warning('Client %s sent broken user_settings: %s',
                                client_id_str, user_settings_str)

            pkgs_to_install = self.request.get_all('pkgs_to_install')
            apple_updates_to_install = self.request.get_all(
                'apple_updates_to_install')

            computer = models.Computer.get_by_key_name(uuid)
            ip_address = os.environ.get('REMOTE_ADDR', '')
            if report_type == 'preflight':
                # we want to get feedback now, before preflight_datetime changes.
                client_exit = self.request.get('client_exit', None)
                report_feedback = self.GetReportFeedback(
                    uuid,
                    report_type,
                    computer=computer,
                    ip_address=ip_address,
                    client_exit=client_exit)

                if self.request.get('json') == '1':
                    self.response.out.write(JSON_PREFIX +
                                            json.dumps(report_feedback))
                else:
                    # For legacy clients that accept a single string, not JSON.
                    feedback_to_send = 'OK'
                    for feedback in LEGACY_FEEDBACK_LIST:
                        if report_feedback.get(feedback.lower()):
                            feedback_to_send = feedback
                    self.response.out.write(feedback_to_send)

                # if report feedback calls for a client exit, log it.
                if report_feedback.get('exit'):
                    if not client_exit:
                        # client didn't ask for an exit, which means server decided.
                        client_exit = 'Connection from defined exit IP address'
                    common.WriteClientLog(models.PreflightExitLog,
                                          uuid,
                                          computer=computer,
                                          exit_reason=client_exit)

            common.LogClientConnection(report_type,
                                       client_id,
                                       user_settings,
                                       pkgs_to_install,
                                       apple_updates_to_install,
                                       computer=computer,
                                       ip_address=ip_address,
                                       report_feedback=report_feedback)

        elif report_type == 'install_report':
            computer = models.Computer.get_by_key_name(uuid)

            self._LogInstalls(self.request.get_all('installs'), computer)

            for removal in self.request.get_all('removals'):
                common.WriteClientLog(models.ClientLog,
                                      uuid,
                                      computer=computer,
                                      action='removal',
                                      details=removal)

            for problem in self.request.get_all('problem_installs'):
                common.WriteClientLog(models.ClientLog,
                                      uuid,
                                      computer=computer,
                                      action='install_problem',
                                      details=problem)
        elif report_type == 'broken_client':
            # Default reason of "objc" to support legacy clients, existing when objc
            # was the only broken state ever reported.
            reason = self.request.get('reason', 'objc')
            details = self.request.get('details')
            logging.warning('Broken Munki client (%s): %s', reason, details)
            common.WriteBrokenClient(uuid, reason, details)
        elif report_type == 'msu_log':
            details = {}
            for k in ['time', 'user', 'source', 'event', 'desc']:
                details[k] = self.request.get(k, None)
            common.WriteComputerMSULog(uuid, details)
        else:
            # unknown report type; log all post params.
            params = []
            for param in self.request.arguments():
                params.append('%s=%s' % (param, self.request.get_all(param)))
            common.WriteClientLog(models.ClientLog,
                                  uuid,
                                  action='unknown',
                                  details=str(params))
コード例 #14
0
  def testDoMunkiAuth(self):
    """Test DoMunkiAuth()."""
    level = 123
    cookie_str = 'foo=bar'
    token = 'cookie value for auth.AUTH_TOKEN_COOKIE'
    uuid = 'session uuid'
    mock_valobj = self.mox.CreateMockAnything()
    mock_valobj.value = token
    mock_session = self.mox.CreateMockAnything()
    mock_session.uuid = 'session uuid'

    mock_environ = self.mox.CreateMockAnything()
    mock_cookie = self.mox.CreateMockAnything()
    mock_auth1 = self.mox.CreateMockAnything()

    self.stubs.Set(gaeserver.os, 'environ', mock_environ)
    self.mox.StubOutWithMock(gaeserver.Cookie, 'SimpleCookie', True)
    self.mox.StubOutWithMock(gaeserver, 'AuthSimianServer', True)

    # 0: fake_noauth=True, nothing to mock

    # test 1: missing cookie
    mock_environ.get('HTTP_COOKIE', None).AndReturn(None)

    # test 2: cookie is malformed
    mock_environ.get('HTTP_COOKIE', None).AndReturn(cookie_str)
    gaeserver.Cookie.SimpleCookie().AndReturn(mock_cookie)
    mock_cookie.load(cookie_str).AndRaise(TypeError)

    # test 3: cookie exists, but isn't ours
    mock_environ.get('HTTP_COOKIE', None).AndReturn(cookie_str)
    gaeserver.Cookie.SimpleCookie().AndReturn(mock_cookie)
    mock_cookie.load(cookie_str).AndRaise(gaeserver.Cookie.CookieError)

    # test 4: cookie exists, is ours, but token isn't authenticated
    mock_environ.get('HTTP_COOKIE', None).AndReturn(cookie_str)
    gaeserver.Cookie.SimpleCookie().AndReturn(mock_cookie)
    mock_cookie.load(cookie_str).AndReturn(None)
    mock_cookie.__contains__(
        gaeserver.auth.AUTH_TOKEN_COOKIE).AndReturn(False)

    # test 5: GetSessionIfAuthOK() returns false, bad token
    mock_environ.get('HTTP_COOKIE', None).AndReturn(cookie_str)
    gaeserver.Cookie.SimpleCookie().AndReturn(mock_cookie)
    mock_cookie.load(cookie_str).AndReturn(None)
    mock_cookie.__contains__(
        gaeserver.auth.AUTH_TOKEN_COOKIE).AndReturn(True)
    mock_cookie.__getitem__(
        gaeserver.auth.AUTH_TOKEN_COOKIE).AndReturn(mock_valobj)
    gaeserver.AuthSimianServer().AndReturn(mock_auth1)
    mock_cookie.__getitem__(
        gaeserver.auth.AUTH_TOKEN_COOKIE).AndReturn(mock_valobj)
    mock_auth1.GetSessionIfAuthOK(token, gaeserver.LEVEL_BASE).AndRaise(
        gaeserver.base.AuthSessionError)

    # 6: test all success!
    mock_environ.get('HTTP_COOKIE', None).AndReturn(cookie_str)
    gaeserver.Cookie.SimpleCookie().AndReturn(mock_cookie)
    mock_cookie.load(cookie_str).AndReturn(None)
    mock_cookie.__contains__(
        gaeserver.auth.AUTH_TOKEN_COOKIE).AndReturn(True)
    mock_cookie.__getitem__(
        gaeserver.auth.AUTH_TOKEN_COOKIE).AndReturn(mock_valobj)
    gaeserver.AuthSimianServer().AndReturn(mock_auth1)
    mock_cookie.__getitem__(
        gaeserver.auth.AUTH_TOKEN_COOKIE).AndReturn(mock_valobj)
    mock_auth1.GetSessionIfAuthOK(token, level).AndReturn(mock_session)

    self.mox.ReplayAll()
    self.assertRaises(
        gaeserver.NotAuthenticated,
        gaeserver.DoMunkiAuth, fake_noauth=True)  # 0
    self.assertRaises(gaeserver.NotAuthenticated, gaeserver.DoMunkiAuth)  # 1
    self.assertRaises(gaeserver.NotAuthenticated, gaeserver.DoMunkiAuth)  # 2
    self.assertRaises(gaeserver.NotAuthenticated, gaeserver.DoMunkiAuth)  # 3
    self.assertRaises(gaeserver.NotAuthenticated, gaeserver.DoMunkiAuth)  # 4
    self.assertRaises(gaeserver.NotAuthenticated, gaeserver.DoMunkiAuth)  # 5
    session = gaeserver.DoMunkiAuth(require_level=level)  # 6
    self.assertEqual(uuid, session.uuid)  # 6
    self.mox.VerifyAll()
コード例 #15
0
ファイル: uploadpkg.py プロジェクト: smusa/simian
    def post(self):
        """POST

    This method behaves a little strangely.  BlobstoreUploadHandler
    only allows returns statuses of 301, 302, 303 (not even 200), so
    one must redirect away to return more information to the caller.

    Parameters:
      file: package file contents
      pkginfo: packageinfo file contents
      name: filename of package e.g. 'Firefox-1.0.dmg'
    """
        # Only blobstore/upload service/scotty requests should be
        # invoking this handler.
        if not handlers.IsBlobstore():
            logging.critical('POST to /uploadpkg not from Blobstore: %s',
                             self.request.headers)
            self.redirect('/')

        gaeserver.DoMunkiAuth(require_level=gaeserver.LEVEL_UPLOADPKG)

        user = self.request.get('user')
        filename = self.request.get('name')
        install_types = self.request.get('install_types')
        catalogs = self.request.get('catalogs', None)
        manifests = self.request.get('manifests', None)
        if catalogs is None or not install_types or not user or not filename:
            msg = 'uploadpkg POST required parameters missing'
            logging.error(msg)
            self.redirect('/uploadpkg?mode=error&msg=%s' % msg)
            return
        if catalogs == '':
            catalogs = []
        else:
            catalogs = catalogs.split(',')
        if manifests in ['', None]:
            manifests = []
        else:
            manifests = manifests.split(',')
        install_types = install_types.split(',')

        upload_files = self.get_uploads('file')
        upload_pkginfo_files = self.get_uploads('pkginfo')
        if not len(upload_pkginfo_files) and not self.request.get('pkginfo'):
            self.redirect('/uploadpkg?mode=error&msg=No%20file%20received')
            return

        if len(upload_pkginfo_files):
            # obtain the pkginfo from a blob, and then throw it away.  this is
            # a necessary hack because the upload handler grabbed it, but we don't
            # intend to keep it in blobstore.
            pkginfo_str = gae_util.GetBlobAndDel(upload_pkginfo_files[0].key())
        else:
            # otherwise, grab the form parameter.
            pkginfo_str = self.request.get('pkginfo')

        blob_info = upload_files[0]
        blobstore_key = str(blob_info.key())

        # Parse, validate, and encode the pkginfo plist.
        plist = plist_lib.MunkiPackageInfoPlist(pkginfo_str)
        try:
            plist.Parse()
        except plist_lib.PlistError, e:
            logging.exception('Invalid pkginfo plist uploaded:\n%s\n',
                              pkginfo_str)
            gae_util.SafeBlobDel(blobstore_key)
            self.redirect(
                '/uploadpkg?mode=error&msg=No%20valid%20pkginfo%20received')
            return