def testDoAnyAuth(self): """Test DoAnyAuth().""" email = '*****@*****.**' require_level = 123 with mock.patch.object(auth, 'DoUserAuth', return_value=email) as m: self.assertEqual(auth.DoAnyAuth(is_admin=True), email) m.assert_called_once_with(is_admin=True) with mock.patch.object( auth, 'DoUserAuth', side_effect=auth.IsAdminMismatch): self.assertRaises(auth.IsAdminMismatch, auth.DoAnyAuth, is_admin=True) with mock.patch.object( auth, 'DoUserAuth', side_effect=auth.NotAuthenticated): with mock.patch.object( auth.gaeserver, 'DoMunkiAuth', return_value='user') as m: self.assertEqual(auth.DoAnyAuth( is_admin=True, require_level=require_level), 'user') m.assert_called_once_with(require_level=require_level) with mock.patch.object( auth, 'DoUserAuth', side_effect=auth.NotAuthenticated): with mock.patch.object( auth.gaeserver, 'DoMunkiAuth', side_effect=auth.gaeserver.NotAuthenticated): self.assertRaises( auth.base.NotAuthenticated, auth.DoAnyAuth, is_admin=True, require_level=require_level)
def MockDoAnyAuth(self, fail=False, and_return=None): """Mock calling auth.DoAnyAuth(). Args: fail: bool, whether to fail or not and_return: any, variable to pass to AndReturn, default None """ if 'authDoAnyAuth' not in self._set_mock: self.mox.StubOutWithMock(auth, 'DoAnyAuth') self._set_mock['authDoAnyAuth'] = 1 if fail: auth.DoAnyAuth().AndRaise(auth.NotAuthenticated) else: auth.DoAnyAuth().AndReturn(and_return)
def get(self, name): """Catalog get handler. Args: name: string catalog name to get. Returns: A webapp.Response() response. """ auth.DoAnyAuth() catalog = models.Catalog.MemcacheWrappedGet(name) if not catalog: self.response.set_status(httplib.NOT_FOUND) return header_date_str = self.request.headers.get('If-Modified-Since', '') if not handlers.IsClientResourceExpired(catalog.mtime, header_date_str): self.response.set_status(httplib.NOT_MODIFIED) return self.response.headers['Last-Modified'] = catalog.mtime.strftime( handlers.HEADER_DATE_FORMAT) self.response.headers['Content-Type'] = 'text/xml; charset=utf-8' self.response.out.write(catalog.plist_xml)
def get(self, client_id_str=''): """AppleSUS get handler. Args: name: str, optional, catalog name to get. """ session = auth.DoAnyAuth() client_id = handlers.GetClientIdForRequest( self.request, session=session, client_id_str=client_id_str) # 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', '') or '' 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(404) 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(304)
def testDoAnyAuth(self): """Test DoAnyAuth().""" is_admin = True require_level = 123 self.mox.StubOutWithMock(auth, 'DoUserAuth') self.mox.StubOutWithMock(auth.gaeserver, 'DoMunkiAuth') auth.DoUserAuth(is_admin=is_admin).AndReturn('user') auth.DoUserAuth(is_admin=is_admin).AndRaise(auth.IsAdminMismatch) auth.DoUserAuth(is_admin=is_admin).AndRaise(auth.NotAuthenticated) auth.gaeserver.DoMunkiAuth( require_level=require_level).AndReturn('token') auth.DoUserAuth(is_admin=is_admin).AndRaise(auth.NotAuthenticated) auth.gaeserver.DoMunkiAuth(require_level=require_level).AndRaise( auth.gaeserver.NotAuthenticated) self.mox.ReplayAll() self.assertEqual(auth.DoAnyAuth(is_admin=is_admin), 'user') self.assertRaises(auth.IsAdminMismatch, auth.DoAnyAuth, is_admin=is_admin) self.assertEqual( auth.DoAnyAuth(is_admin=is_admin, require_level=require_level), 'token') self.assertRaises(auth.base.NotAuthenticated, auth.DoAnyAuth, is_admin=is_admin, require_level=require_level) self.mox.VerifyAll()
def get(self, name): """Catalog get handler. Args: name: string catalog name to get. Returns: A webapp.Response() response. """ auth.DoAnyAuth() catalog = models.Catalog.MemcacheWrappedGet(name, 'plist_xml') if catalog: self.response.headers['Content-Type'] = 'text/xml; charset=utf-8' self.response.out.write(catalog) else: self.response.set_status(404)
def get(self, name): auth.DoAnyAuth() try: bucket = settings.ICONS_GCS_BUCKET except AttributeError: logging.warning('Dedicated icons GCS bucket is not set.') self.abort(httplib.BAD_REQUEST) name = name.split('.')[0] icon_path = '/%s/%s.png' % (bucket, base64.urlsafe_b64encode(name)) try: with gcs.open(icon_path, 'r') as gcs_file: self.response.headers['Content-Type'] = 'image/png' self.response.write(gcs_file.read()) except gcs.NotFoundError: self.abort(httplib.NOT_FOUND)
def get(self, client_id_str=''): """Manifest get handler. Args: client_id: optional str client_id; only needed for user requests. Returns: A webapp.Response() response. """ session = auth.DoAnyAuth() client_id = handlers.GetClientIdForRequest(self.request, session=session, client_id_str=client_id_str) try: plist_xml = common.GetComputerManifest(client_id=client_id, packagemap=False) except common.ManifestNotFoundError, e: logging.warning('Invalid manifest requested: %s', str(e)) self.response.set_status(404) return
def get(self, name): auth.DoAnyAuth() if name == '_icon_hashes.plist': # munki 3.1 starts reading hashes from special plist. # to avoid 404 spam in logs, replying with 200. return try: bucket = settings.ICONS_GCS_BUCKET except AttributeError: logging.warning('Dedicated icons GCS bucket is not set.') self.abort(httplib.BAD_REQUEST) name = name.split('.')[0] icon_path = '/%s/%s.png' % (bucket, base64.urlsafe_b64encode(name)) try: with gcs.open(icon_path, 'r') as gcs_file: self.response.headers['Content-Type'] = 'image/png' self.response.write(gcs_file.read()) except gcs.NotFoundError: self.abort(httplib.NOT_FOUND)
def get(self, client_id_str=''): """GET Returns: None if a blob is being returned, or a response object """ session = auth.DoAnyAuth() client_id = handlers.GetClientIdForRequest( self.request, session=session, client_id_str=client_id_str) logging.info('Repair client ID: %s', client_id) filename = None for pkg in models.PackageInfo.all().filter('name =', 'munkitools'): if client_id.get('track', '') in pkg.catalogs: filename = pkg.filename break if filename: logging.info('Sending client: %s', filename) super(ClientRepair, self).get(filename) else: logging.warning('No repair client found.')
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)
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'
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'