Exemple #1
0
 async def resolve(self, request):
     result = None
     try:
         result = await self.real_resolve(request)
     except Exception as e:
         logger.error(
             "Exception on resolve execution",
             exc_info=e)
         raise e
     if result is not None:
         return result
     else:
         raise HTTPNotFound()
Exemple #2
0
def generate_unauthorized_response(e, request):
    # We may need to check the roles of the users to show the real error
    eid = uuid.uuid4().hex
    message = _('Not authorized to render operation') + ' ' + eid
    user = get_authenticated_user_id(request)
    extra = {
        'r': _url(request),
        'u': user
    }
    logger.error(
        message,
        exc_info=e,
        extra=extra)
    return UnauthorizedResponse(message)
Exemple #3
0
def schema_compatible(value, schema_or_field):
    """The schema_compatible function converts any value to zope.schema
    compatible data when possible, raising a TypeError for unsupported values.
    This is done by using the ISchemaCompatible converters.
    """
    if value is None:
        return value

    try:
        return getMultiAdapter((value, schema_or_field), IJSONToValue)
    except ComponentLookupError:
        logger.error((u'Deserializer not found for field type '
                      u'"{0:s}" with value "{1:s}" and it was '
                      u'deserialized to None.').format(schema_or_field, value))
        return None
def schema_compatible(value, schema_or_field):
    """The schema_compatible function converts any value to zope.schema
    compatible data when possible, raising a TypeError for unsupported values.
    This is done by using the ISchemaCompatible converters.
    """
    if value is None:
        return value

    try:
        return getMultiAdapter((value, schema_or_field), IJSONToValue)
    except ComponentLookupError:
        logger.error((u'Deserializer not found for field type '
                      u'"{0:s}" with value "{1:s}" and it was '
                      u'deserialized to None.').format(
            schema_or_field, value))
        return None
Exemple #5
0
    async def initialize(self, app=None):
        # loop
        self.app = app
        while True:
            got_obj = False
            try:
                priority, view = await self._queue.get()
                got_obj = True
                if view.request.conn.transaction_manager is None:
                    # Connection was closed
                    # Open DB
                    db = view.request.application[view.request._db_id]
                    if SHARED_CONNECTION:
                        view.request.conn = db.conn
                    else:
                        # Create a new conection
                        view.request.conn = db.open()
                    view.context = view.request.conn.get(view.context._p_oid)

                txn = view.request.conn.transaction_manager.begin(view.request)
                try:
                    view_result = await view()
                    if isinstance(view_result, ErrorResponse):
                        await abort(txn, view.request)
                    elif isinstance(view_result, UnauthorizedResponse):
                        await abort(txn, view.request)
                    else:
                        await commit(txn, view.request)
                except Unauthorized:
                    await abort(txn, view.request)
                except Exception as e:
                    logger.error(
                        "Exception on writing execution",
                        exc_info=e)
                    await abort(txn, view.request)
            except KeyboardInterrupt or MemoryError or SystemExit or asyncio.CancelledError:
                self._exceptions = True
                raise
            except Exception as e:  # noqa
                self._exceptions = True
                logger.error('Worker call failed', exc_info=e)
            finally:
                if SHARED_CONNECTION is False and hasattr(view.request, 'conn'):
                    view.request.conn.close()
                if got_obj:
                    self._queue.task_done()
Exemple #6
0
    async def initialize(self, app=None):
        # loop
        self.app = app
        while True:
            got_obj = False
            try:
                priority, view = await self._queue.get()
                got_obj = True
                if view.request.conn.transaction_manager is None:
                    # Connection was closed
                    # Open DB
                    db = view.request.application[view.request._db_id]
                    if SHARED_CONNECTION:
                        view.request.conn = db.conn
                    else:
                        # Create a new conection
                        view.request.conn = db.open()
                    view.context = view.request.conn.get(view.context._p_oid)

                txn = view.request.conn.transaction_manager.begin(view.request)
                try:
                    view_result = await view()
                    if isinstance(view_result, ErrorResponse):
                        await sync(view.request)(txn.abort)
                    elif isinstance(view_result, UnauthorizedResponse):
                        await sync(view.request)(txn.abort)
                    else:
                        await sync(view.request)(txn.commit)
                except Unauthorized:
                    await sync(view.request)(txn.abort)
                    view_result = UnauthorizedResponse(
                        _('Not authorized to render operation'))
                except Exception as e:
                    logger.error("Exception on writing execution", exc_info=e)
                    await sync(view.request)(txn.abort)
                    view_result = ErrorResponse(
                        'ServiceError', _('Error on execution of operation'))
            except KeyboardInterrupt or MemoryError or SystemExit or asyncio.CancelledError:
                self._exceptions = True
                raise
            except Exception as e:  # noqa
                self._exceptions = True
                logger.error('Worker call failed', exc_info=e)
            finally:
                if got_obj:
                    self._queue.task_done()
Exemple #7
0
def generate_error_response(e, request, error, status=400):
    # We may need to check the roles of the users to show the real error
    eid = uuid.uuid4().hex
    message = _('Error on execution of view') + ' ' + eid
    user = get_authenticated_user_id(request)
    extra = {
        'r': _url(request),
        'u': user
    }
    logger.error(
        message,
        exc_info=e,
        extra=extra)

    return ErrorResponse(
        error,
        message,
        status
    )
Exemple #8
0
    async def real_resolve(self, request):
        """Main function to resolve a request."""
        alsoProvides(request, IRequest)
        alsoProvides(request, IDefaultLayer)

        request._futures = {}

        request.security = IInteraction(request)

        method = app_settings['http_methods'][request.method]

        language = language_negotiation(request)
        language_object = language(request)

        try:
            resource, tail = await self.traverse(request)
        except Exception as _exc:
            request.resource = request.tail = None
            request.exc = _exc
            # XXX should only should traceback if in some sort of dev mode?
            raise HTTPBadRequest(text=json.dumps({
                'success': False,
                'exception_message': str(_exc),
                'exception_type': getattr(type(_exc), '__name__', str(type(_exc))),  # noqa
                'traceback': traceback.format_exc()
            }))

        request.resource = resource
        request.tail = tail

        if request.resource is None:
            raise HTTPBadRequest(text='Resource not found')

        traverse_to = None
        if tail and len(tail) == 1:
            view_name = tail[0]
        elif tail is None or len(tail) == 0:
            view_name = ''
        else:
            view_name = tail[0]
            traverse_to = tail[1:]

        await self.apply_authorization(request)

        translator = queryMultiAdapter(
            (language_object, resource, request),
            ITranslated)
        if translator is not None:
            resource = translator.translate()

        # Add anonymous participation
        if len(request.security.participations) == 0:
            # logger.info("Anonymous User")
            request.security.add(AnonymousParticipation(request))

        # Site registry lookup
        try:
            view = queryMultiAdapter(
                (resource, request), method, name=view_name)
        except AttributeError:
            view = None

        # Traverse view if its needed
        if traverse_to is not None and view is not None:
            if not ITraversableView.providedBy(view):
                return None
            else:
                try:
                    view = view.publishTraverse(traverse_to)
                except Exception as e:
                    logger.error(
                        "Exception on view execution",
                        exc_info=e)
                    return None

        permission = getUtility(IPermission, name='plone.AccessContent')

        allowed = request.security.checkPermission(permission.id, resource)

        if not allowed:
            # Check if its a CORS call:
            if IOPTIONS != method or not app_settings['cors']:
                # Check if the view has permissions explicit
                if view is None or not view.__allow_access__:
                    logger.warn("No access content {content} with {auths}".format(
                        content=resource,
                        auths=str([x.principal.id
                                   for x in request.security.participations])))
                    raise HTTPUnauthorized()

        if view is None and method == IOPTIONS:
            view = DefaultOPTIONS(resource, request)

        checker = getCheckerForInstancesOf(view.__class__)
        if checker is not None:
            view = ProxyFactory(view, checker)
        # We want to check for the content negotiation

        renderer = content_type_negotiation(request, resource, view)
        renderer_object = renderer(request)

        rendered = queryMultiAdapter(
            (renderer_object, view, request), IRendered)

        if rendered is not None:
            return MatchInfo(resource, request, view, rendered)
        else:
            return None
Exemple #9
0
def make_app(config_file=None, settings=None):
    app_settings.update(_delayed_default_settings)

    # Initialize aiohttp app
    app = web.Application(router=TraversalRouter())

    # Create root Application
    root = ApplicationRoot(config_file)
    root.app = app
    provideUtility(root, IApplication, 'root')

    # Initialize global (threadlocal) ZCA configuration
    app.config = ConfigurationMachine()
    registerCommonDirectives(app.config)

    if config_file is not None:
        with open(config_file, 'r') as config:
            settings = json.load(config)
    elif settings is None:
        raise Exception('Neither configuration or settings')

    import plone.server
    configure.include("zope.component")
    configure.include("zope.annotation")
    configure.include("plone.server", "meta.zcml")  # bbb
    configure.scan('plone.server.translation')
    configure.scan('plone.server.renderers')
    configure.scan('plone.server.api')
    configure.scan('plone.server.content')
    configure.scan('plone.server.security')
    configure.scan('plone.server.json')
    configure.scan('plone.server.behaviors')
    configure.scan('plone.server.languages')
    configure.scan('plone.server.permissions')
    configure.scan('plone.server.migrate.migrations')
    configure.scan('plone.server.auth.participation')
    configure.scan('plone.server.auth.principalrole')
    configure.scan('plone.server.catalog.index')
    configure.scan('plone.server.catalog.catalog')
    configure.scan('plone.server.framing')
    configure.scan('plone.server.file')
    configure.scan('plone.server.types')
    load_application(plone.server, root, settings)

    for ep in iter_entry_points('plone.server'):
        # auto-include applications
        # What an "app" include consists of...
        # 1. load zcml if present
        # 2. load "includeme" module function if present
        # 3. load app_settings dict if present in the module
        if ep.module_name not in settings.get('applications', []):
            continue

        load_application(ep.load(), root, settings)
    try:
        app.config.execute_actions()
    except ConfigurationConflictError as e:
        logger.error(str(e._conflicts))
        raise e

    # XXX we clear now to save some memory
    # it's unclear to me if this is necesary or not but it seems to me that
    # we don't need things registered in both components AND here.
    configure.clear()

    # update *after* plugins loaded
    update_app_settings(settings)

    content_type = ContentNegotiatorUtility(
        'content_type', app_settings['renderers'].keys())
    language = ContentNegotiatorUtility(
        'language', app_settings['languages'].keys())

    provideUtility(content_type, IContentNegotiation, 'content_type')
    provideUtility(language, IContentNegotiation, 'language')

    for database in app_settings['databases']:
        for key, dbconfig in database.items():
            factory = getUtility(
                IDatabaseConfigurationFactory, name=dbconfig['storage'])
            root[key] = factory(key, dbconfig)

    for static in app_settings['static']:
        for key, file_path in static.items():
            root[key] = StaticFile(file_path)

    root.set_root_user(app_settings['root_user'])

    if RSA is not None and not app_settings.get('rsa'):
        key = RSA.generate(2048)
        pub_jwk = {'k': key.publickey().exportKey('PEM')}
        priv_jwk = {'k': key.exportKey('PEM')}
        app_settings['rsa'] = {
            'pub': pub_jwk,
            'priv': priv_jwk
        }

    # Set router root
    app.router.set_root(root)

    for utility in getAllUtilitiesRegisteredFor(IAsyncUtility):
        # In case there is Utilties that are registered from zcml
        ident = asyncio.ensure_future(utility.initialize(app=app), loop=app.loop)
        root.add_async_utility(ident, {})

    app.on_cleanup.append(close_utilities)

    for util in app_settings['utilities']:
        root.add_async_utility(util)

    # Load cached Schemas
    load_cached_schema()

    return app
Exemple #10
0
    async def __call__(self):
        ws = web.WebSocketResponse()
        await ws.prepare(self.request)

        async for msg in ws:
            if msg.tp == aiohttp.WSMsgType.text:
                message = ujson.loads(msg.data)
                if message['op'] == 'close':
                    await ws.close()
                elif message['op'] == 'GET':
                    method = app_settings['http_methods']['GET']
                    path = tuple(p for p in message['value'].split('/') if p)

                    # avoid circular import
                    from plone.server.traversal import do_traverse

                    obj, tail = await do_traverse(
                        self.request, self.request.site, path)

                    traverse_to = None

                    if tail and len(tail) == 1:
                        view_name = tail[0]
                    elif tail is None or len(tail) == 0:
                        view_name = ''
                    else:
                        view_name = tail[0]
                        traverse_to = tail[1:]

                    permission = getUtility(
                        IPermission, name='plone.AccessContent')

                    allowed = IInteraction(self.request).check_permission(
                        permission.id, obj)
                    if not allowed:
                        response = {
                            'error': 'Not allowed'
                        }
                        ws.send_str(ujson.dumps(response))

                    try:
                        view = queryMultiAdapter(
                            (obj, self.request), method, name=view_name)
                    except AttributeError:
                        view = None

                    if traverse_to is not None:
                        if view is None or not ITraversableView.providedBy(view):
                            response = {
                                'error': 'Not found'
                            }
                            ws.send_str(ujson.dumps(response))
                        else:
                            try:
                                view = view.publishTraverse(traverse_to)
                            except Exception as e:
                                logger.error(
                                    "Exception on view execution",
                                    exc_info=e)
                                response = {
                                    'error': 'Not found'
                                }
                                ws.send_str(ujson.dumps(response))

                    view_result = await view()
                    if isinstance(view_result, Response):
                        view_result = view_result.response

                    # Return the value
                    ws.send_str(ujson.dumps(view_result))

                    # Wait for possible value
                    futures_to_wait = self.request._futures.values()
                    if futures_to_wait:
                        await asyncio.gather(futures_to_wait)
                        self.request._futures = {}
                else:
                    await ws.close()
            elif msg.tp == aiohttp.WSMsgType.error:
                logger.debug('ws connection closed with exception {0:s}'
                             .format(ws.exception()))

        logger.debug('websocket connection closed')

        return {}
Exemple #11
0
def make_app(config_file=None, settings=None):
    app_settings.update(_delayed_default_settings)

    # Initialize aiohttp app
    app = web.Application(
        router=TraversalRouter(),
        **settings.get('aiohttp_settings', {}))

    # Create root Application
    root = ApplicationRoot(config_file)
    root.app = app
    provideUtility(root, IApplication, 'root')

    # Initialize global (threadlocal) ZCA configuration
    app.config = ConfigurationMachine()
    registerCommonDirectives(app.config)

    if config_file is not None:
        with open(config_file, 'r') as config:
            settings = json.load(config)
    elif settings is None:
        raise Exception('Neither configuration or settings')

    import plone.server
    configure.include("zope.component")
    configure.include("zope.annotation")
    configure.include("plone.server", "meta.zcml")  # bbb
    configure.scan('plone.server.translation')
    configure.scan('plone.server.renderers')
    configure.scan('plone.server.api')
    configure.scan('plone.server.content')
    configure.scan('plone.server.auth')
    configure.scan('plone.server.json')
    configure.scan('plone.server.behaviors')
    configure.scan('plone.server.languages')
    configure.scan('plone.server.permissions')
    configure.scan('plone.server.migrate.migrations')
    configure.scan('plone.server.auth.checker')
    configure.scan('plone.server.auth.security_local')
    configure.scan('plone.server.auth.policy')
    configure.scan('plone.server.auth.participation')
    configure.scan('plone.server.catalog.index')
    configure.scan('plone.server.catalog.catalog')
    configure.scan('plone.server.framing')
    configure.scan('plone.server.file')
    configure.scan('plone.server.types')
    load_application(plone.server, root, settings)

    for ep in iter_entry_points('plone.server'):
        # auto-include applications
        # What an "app" include consists of...
        # 1. load zcml if present
        # 2. load "includeme" module function if present
        # 3. load app_settings dict if present in the module
        if ep.module_name not in settings.get('applications', []):
            continue

        load_application(ep.load(), root, settings)
    try:
        app.config.execute_actions()
    except ConfigurationConflictError as e:
        logger.error(str(e._conflicts))
        raise e

    # XXX we clear now to save some memory
    # it's unclear to me if this is necesary or not but it seems to me that
    # we don't need things registered in both components AND here.
    configure.clear()

    # update *after* plugins loaded
    update_app_settings(settings)

    content_type = ContentNegotiatorUtility(
        'content_type', app_settings['renderers'].keys())
    language = ContentNegotiatorUtility(
        'language', app_settings['languages'].keys())

    provideUtility(content_type, IContentNegotiation, 'content_type')
    provideUtility(language, IContentNegotiation, 'language')

    for database in app_settings['databases']:
        for key, dbconfig in database.items():
            factory = getUtility(
                IDatabaseConfigurationFactory, name=dbconfig['storage'])
            root[key] = factory(key, dbconfig)

    for static in app_settings['static']:
        for key, file_path in static.items():
            path = pathlib.Path(file_path)
            if path.is_dir():
                root[key] = StaticDirectory(path)
            else:
                root[key] = StaticFile(path)

    root.set_root_user(app_settings['root_user'])

    if RSA is not None and not app_settings.get('rsa'):
        key = RSA.generate(2048)
        pub_jwk = {'k': key.publickey().exportKey('PEM')}
        priv_jwk = {'k': key.exportKey('PEM')}
        app_settings['rsa'] = {
            'pub': pub_jwk,
            'priv': priv_jwk
        }

    # Set router root
    app.router.set_root(root)

    for utility in getAllUtilitiesRegisteredFor(IAsyncUtility):
        # In case there is Utilties that are registered from zcml
        ident = asyncio.ensure_future(utility.initialize(app=app), loop=app.loop)
        root.add_async_utility(ident, {})

    app.on_cleanup.append(close_utilities)

    for util in app_settings['utilities']:
        root.add_async_utility(util)

    # Load cached Schemas
    load_cached_schema()

    return app
Exemple #12
0
    async def __call__(self):
        ws = web.WebSocketResponse()
        await ws.prepare(self.request)

        async for msg in ws:
            if msg.tp == aiohttp.MsgType.text:
                message = ujson.loads(msg.data)
                if message['op'] == 'close':
                    await ws.close()
                elif message['op'] == 'GET':
                    method = app_settings['http_methods']['GET']
                    path = tuple(p for p in message['value'].split('/') if p)

                    # avoid circular import
                    from plone.server.traversal import do_traverse

                    obj, tail = await do_traverse(self.request,
                                                  self.request.site, path)

                    traverse_to = None

                    if tail and len(tail) == 1:
                        view_name = tail[0]
                    elif tail is None or len(tail) == 0:
                        view_name = ''
                    else:
                        view_name = tail[0]
                        traverse_to = tail[1:]

                    permission = getUtility(IPermission,
                                            name='plone.AccessContent')

                    allowed = self.request.security.checkPermission(
                        permission.id, obj)
                    if not allowed:
                        response = {'error': 'Not allowed'}
                        ws.send_str(ujson.dumps(response))

                    try:
                        view = queryMultiAdapter((obj, self.request),
                                                 method,
                                                 name=view_name)
                    except AttributeError:
                        view = None

                    if traverse_to is not None:
                        if view is None or not ITraversableView.providedBy(
                                view):
                            response = {'error': 'Not found'}
                            ws.send_str(ujson.dumps(response))
                        else:
                            try:
                                view = view.publishTraverse(traverse_to)
                            except Exception as e:
                                logger.error("Exception on view execution",
                                             exc_info=e)
                                response = {'error': 'Not found'}
                                ws.send_str(ujson.dumps(response))

                    view_result = await view()
                    if isinstance(view_result, Response):
                        view_result = view_result.response

                    ws.send_str(ujson.dumps(view_result))
                else:
                    await ws.close()
            elif msg.tp == aiohttp.MsgType.error:
                logger.debug(
                    'ws connection closed with exception {0:s}'.format(
                        ws.exception()))

        logger.debug('websocket connection closed')

        return {}