Esempio n. 1
0
    async def resolve(self, request: IRequest) -> BaseMatchInfo:
        '''
        Resolve a request
        '''
        # prevent: https://github.com/aio-libs/aiohttp/issues/3335
        request.url

        request.record('start')
        result = None
        try:
            result = await self.real_resolve(request)
        except (response.Response, aiohttp.web_exceptions.HTTPException) as exc:
            await abort(request)
            return BasicMatchInfo(request, exc)
        except Exception:
            logger.error("Exception on resolve execution",
                         exc_info=True, request=request)
            await abort(request)
            return BasicMatchInfo(
                request, response.HTTPInternalServerError())

        if result is not None:
            return result
        else:
            await abort(request)
            return BasicMatchInfo(request, response.HTTPNotFound())
Esempio n. 2
0
    async def resolve(self,
                      request: IRequest) -> BaseMatchInfo:  # type: ignore
        '''
        Resolve a request
        '''
        # prevent: https://github.com/aio-libs/aiohttp/issues/3335
        request.url

        request.record('start')
        result = None
        try:
            result = await self.real_resolve(request)
        except (response.Response,
                aiohttp.web_exceptions.HTTPException) as exc:
            await abort()
            return BasicMatchInfo(request, exc)
        except Exception:
            logger.error("Exception on resolve execution",
                         exc_info=True,
                         request=request)
            await abort()
            return BasicMatchInfo(request, response.HTTPInternalServerError())

        if result is not None:
            return result
        else:
            await abort()
            return BasicMatchInfo(request, response.HTTPNotFound())
Esempio n. 3
0
    async def __call__(self):
        tm = get_tm()
        await tm.abort()
        ws = self.request.get_ws()
        await ws.prepare()

        async for msg in ws:
            try:
                message = msg.json
            except WebSocketJsonDecodeError:
                # We only care about json messages
                logger.warning(
                    "Invalid websocket payload, ignored: {}".format(msg))
                continue

            if message["op"].lower() == "close":
                break
            elif message["op"].lower() == "get":
                txn = await tm.begin()
                try:
                    await self.handle_ws_request(ws, message)
                except Exception:
                    logger.error("Exception on ws", exc_info=True)
                finally:
                    # only currently support GET requests which are *never*
                    # supposed to be commits
                    await tm.abort(txn=txn)

        logger.debug("websocket connection closed")
        await ws.close()
Esempio n. 4
0
    async def __call__(self):
        tm = get_tm(self.request)
        await tm.abort(self.request)
        ws = web.WebSocketResponse()
        await ws.prepare(self.request)

        async for msg in ws:
            if msg.type == aiohttp.WSMsgType.text:
                try:
                    message = ujson.loads(msg.data)
                except ValueError:
                    logger.warning('Invalid websocket payload, ignored: {}'.format(
                        msg.data))
                    continue
                if message['op'] == 'close':
                    await ws.close()
                elif message['op'].lower() == 'get':
                    txn = await tm.begin(request=self.request)
                    try:
                        await self.handle_ws_request(ws, message)
                    except Exception:
                        logger.error('Exception on ws', exc_info=True)
                    finally:
                        # only currently support GET requests which are *never*
                        # supposed to be commits
                        await tm.abort(txn=txn)
            elif msg.type == aiohttp.WSMsgType.error:
                logger.debug('ws connection closed with exception {0:s}'
                             .format(ws.exception()))

        logger.debug('websocket connection closed')

        return {}
Esempio n. 5
0
    async def resolve(self,
                      request: IRequest) -> BaseMatchInfo:  # type: ignore
        """
        Resolve a request
        """
        request.record("start")
        result = None
        try:
            result = await self.real_resolve(request)
        except response.Response as exc:
            await abort()
            return BasicMatchInfo(request, exc)
        except asyncio.CancelledError:
            logger.info("Request cancelled", request=request)
            await abort()
            return BasicMatchInfo(request, response.HTTPClientClosedRequest())
        except Exception:
            logger.error("Exception on resolve execution",
                         exc_info=True,
                         request=request)
            await abort()
            return BasicMatchInfo(request, response.HTTPInternalServerError())

        if result is not None:
            return result
        else:
            await abort()
            return BasicMatchInfo(request, response.HTTPNotFound())
Esempio n. 6
0
    async def __call__(self):
        tm = get_tm()
        await tm.abort()
        ws = web.WebSocketResponse()
        await ws.prepare(self.request)

        async for msg in ws:
            if msg.type == aiohttp.WSMsgType.text:
                try:
                    message = ujson.loads(msg.data)
                except ValueError:
                    logger.warning(
                        'Invalid websocket payload, ignored: {}'.format(
                            msg.data))
                    continue
                if message['op'] == 'close':
                    await ws.close()
                elif message['op'].lower() == 'get':
                    txn = await tm.begin()
                    try:
                        await self.handle_ws_request(ws, message)
                    except Exception:
                        logger.error('Exception on ws', exc_info=True)
                    finally:
                        # only currently support GET requests which are *never*
                        # supposed to be commits
                        await tm.abort(txn=txn)
            elif msg.type == aiohttp.WSMsgType.error:
                logger.debug(
                    'ws connection closed with exception {0:s}'.format(
                        ws.exception()))

        logger.debug('websocket connection closed')

        return {}
Esempio n. 7
0
    async def handle_ws_request(self, ws, message):
        method = app_settings['http_methods']['GET']
        path = tuple(p for p in message['value'].split('/') if p)

        # avoid circular import
        from guillotina.traversal import do_traverse

        obj, tail = await do_traverse(self.request, self.request.container,
                                      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='guillotina.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 = await view.publish_traverse(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(*list(futures_to_wait))
            self.request._futures = {}
Esempio n. 8
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)
Esempio n. 9
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)
Esempio n. 10
0
async def traverse(
        request: IRequest, parent: IBaseObject,
        path: Tuple[str, ...]) -> Tuple[IBaseObject, Tuple[str, ...]]:
    """Do not use outside the main router function."""
    if IApplication.providedBy(parent):
        request.application = parent

    if len(path) == 0:
        return parent, path

    assert request is not None  # could be used for permissions, etc

    if not ITraversable.providedBy(parent):
        # not a traversable context
        return parent, path
    try:
        if path[0][0] == "_" or path[0] in (".", ".."):
            raise HTTPUnauthorized()
        if path[0][0] == "@":
            # shortcut
            return parent, path

        if IAsyncContainer.providedBy(parent):
            context = await parent.async_get(path[0], suppress_events=True)
            if context is None:
                return parent, path
        else:
            context = parent[path[0]]
    except (TypeError, KeyError, AttributeError):
        return parent, path

    if IDatabase.providedBy(context):
        task_vars.db.set(context)
        # Add a transaction Manager to request
        tm = context.get_transaction_manager()
        task_vars.tm.set(tm)
        # Start a transaction
        txn = await tm.begin(
            read_only=not app_settings["check_writable_request"](request))
        # Get the root of the tree
        context = await tm.get_root(txn=txn)

    if IContainer.providedBy(context):
        task_vars.container.set(context)
        # make sure to unset before we attempt to load in case
        # there is an existing registry object set on task_vars
        task_vars.registry.set(None)
        registry = await get_registry(context)
        layers = registry.get(ACTIVE_LAYERS_KEY, [])
        for layer in layers:
            try:
                alsoProvides(request, import_class(layer))
            except ModuleNotFoundError:
                logger.error("Can not apply layer " + layer, request=request)

    return await traverse(request, context, path[1:])
Esempio n. 11
0
async def traverse(request, parent, path):
    """Do not use outside the main router function."""
    if IApplication.providedBy(parent):
        request.application = parent

    if not path:
        return parent, path

    assert request is not None  # could be used for permissions, etc

    if not ITraversable.providedBy(parent):
        # not a traversable context
        return parent, path
    try:
        if path[0][0] == '_' or path[0] in ('.', '..'):
            raise HTTPUnauthorized()
        if path[0][0] == '@':
            # shortcut
            return parent, path

        if IAsyncContainer.providedBy(parent):
            context = await parent.async_get(path[0], suppress_events=True)
            if context is None:
                return parent, path
        else:
            context = parent[path[0]]
    except (TypeError, KeyError, AttributeError):
        return parent, path

    if IDatabase.providedBy(context):
        request._db_write_enabled = app_settings['check_writable_request'](
            request)
        request._db_id = context.id
        # Add a transaction Manager to request
        tm = request._tm = context.get_transaction_manager()
        # Start a transaction
        txn = await tm.begin(request=request)
        # Get the root of the tree
        context = await tm.get_root(txn=txn)

    if IContainer.providedBy(context):
        request._container_id = context.id
        request.container = context
        annotations_container = IAnnotations(request.container)
        request.container_settings = await annotations_container.async_get(
            REGISTRY_DATA_KEY)
        layers = request.container_settings.get(ACTIVE_LAYERS_KEY, [])
        for layer in layers:
            try:
                alsoProvides(request, import_class(layer))
            except ModuleNotFoundError:
                logger.error('Can not apply layer ' + layer, request=request)

    return await traverse(request, context, path[1:])
Esempio n. 12
0
    async def initialize(self, app=None):
        # loop
        self.app = app
        while True:
            got_obj = False
            try:
                view = await self._queue.get()
                got_obj = True
                txn = get_transaction(view.request)
                tm = get_tm(view.request)
                if txn is None or (txn.status in (
                        Status.ABORTED, Status.COMMITTED, Status.CONFLICT) and
                        txn._db_conn is None):
                    txn = await tm.begin(view.request)
                else:
                    # still finishing current transaction, this connection
                    # will be cut off, so we need to wait until we no longer
                    # have an active transaction on the reqeust...
                    await self.add(view)
                    await asyncio.sleep(1)
                    continue

                try:
                    aiotask_context.set('request', view.request)
                    view_result = await view()
                    if isinstance(view_result, ErrorResponse):
                        await tm.commit(txn=txn)
                    elif isinstance(view_result, UnauthorizedResponse):
                        await tm.abort(txn=txn)
                    else:
                        await tm.commit(txn=txn)
                except Unauthorized:
                    await tm.abort(txn=txn)
                except Exception as e:
                    logger.error(
                        "Exception on writing execution",
                        exc_info=e)
                    await tm.abort(txn=txn)
            except (KeyboardInterrupt, MemoryError, SystemExit,
                    asyncio.CancelledError, GeneratorExit, RuntimeError):
                self._exceptions = True
                raise
            except Exception as e:  # noqa
                self._exceptions = True
                logger.error('Worker call failed', exc_info=e)
            finally:
                aiotask_context.set('request', None)
                if got_obj:
                    try:
                        view.request.execute_futures()
                    except AttributeError:
                        pass
                    self._queue.task_done()
Esempio n. 13
0
async def traverse(request, parent, path):
    """Do not use outside the main router function."""
    if IApplication.providedBy(parent):
        request.application = parent

    if not path:
        return parent, path

    assert request is not None  # could be used for permissions, etc

    if not ITraversable.providedBy(parent):
        # not a traversable context
        return parent, path
    try:
        if path[0][0] == '_' or path[0] in ('.', '..'):
            raise HTTPUnauthorized()
        if path[0][0] == '@':
            # shortcut
            return parent, path

        if IAsyncContainer.providedBy(parent):
            context = await parent.async_get(path[0], suppress_events=True)
            if context is None:
                return parent, path
        else:
            context = parent[path[0]]
    except (TypeError, KeyError, AttributeError):
        return parent, path

    if IDatabase.providedBy(context):
        request._db_write_enabled = app_settings['check_writable_request'](request)
        request._db_id = context.id
        # Add a transaction Manager to request
        tm = request._tm = context.get_transaction_manager()
        # Start a transaction
        txn = await tm.begin(request=request)
        # Get the root of the tree
        context = await tm.get_root(txn=txn)

    if IContainer.providedBy(context):
        request._container_id = context.id
        request.container = context
        annotations_container = IAnnotations(request.container)
        request.container_settings = await annotations_container.async_get(REGISTRY_DATA_KEY)
        layers = request.container_settings.get(ACTIVE_LAYERS_KEY, [])
        for layer in layers:
            try:
                alsoProvides(request, import_class(layer))
            except ModuleNotFoundError:
                logger.error('Can not apply layer ' + layer, request=request)

    return await traverse(request, context, path[1:])
Esempio n. 14
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, request=request)
         await abort(request)
         raise e
     if result is not None:
         return result
     else:
         await abort(request)
         raise HTTPNotFound()
Esempio n. 15
0
    async def initialize(self, app=None):
        # loop
        self.app = app
        while True:
            got_obj = False
            try:
                view = await self.queue.get()
                got_obj = True
                txn = get_transaction(view.request)
                tm = get_tm(view.request)
                if txn is None or (txn.status in (
                        Status.ABORTED, Status.COMMITTED, Status.CONFLICT) and
                        txn._db_conn is None):
                    txn = await tm.begin(view.request)
                else:
                    # still finishing current transaction, this connection
                    # will be cut off, so we need to wait until we no longer
                    # have an active transaction on the reqeust...
                    await self.add(view)
                    await asyncio.sleep(1)
                    continue

                try:
                    aiotask_context.set('request', view.request)
                    await view()
                    await tm.commit(txn=txn)
                except Exception as e:
                    logger.error(
                        "Exception on writing execution",
                        exc_info=e)
                    await tm.abort(txn=txn)
            except (RuntimeError, SystemExit, GeneratorExit, KeyboardInterrupt,
                    asyncio.CancelledError, KeyboardInterrupt):
                # dive, these errors mean we're exit(ing)
                self._exceptions = True
                return
            except Exception as e:  # noqa
                self._exceptions = True
                logger.error('Worker call failed', exc_info=e)
            finally:
                try:
                    aiotask_context.set('request', None)
                except (RuntimeError, ValueError):
                    pass
                if got_obj:
                    try:
                        view.request.execute_futures()
                    except AttributeError:
                        pass
                    self.queue.task_done()
Esempio n. 16
0
def schema_compatible(value, schema_or_field):
    """The schema_compatible function converts any value to guillotina.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
Esempio n. 17
0
    async def initialize(self, app=None):
        # loop
        self.app = app
        while True:
            got_obj = False
            try:
                func, tvars = await self.queue.get()
                got_obj = True
                load_task_vars(tvars)
                txn = get_transaction()
                tm = get_tm()
                if txn is None or (
                    txn.status in (Status.ABORTED, Status.COMMITTED, Status.CONFLICT) and txn._db_conn is None
                ):
                    txn = await tm.begin()
                else:
                    # still finishing current transaction, this connection
                    # will be cut off, so we need to wait until we no longer
                    # have an active transaction on the reqeust...
                    await self.add((func, tvars))
                    await asyncio.sleep(1)
                    continue

                try:
                    await func()
                    await tm.commit(txn=txn)
                except Exception as e:
                    logger.error("Exception on writing execution", exc_info=e)
                    await tm.abort(txn=txn)
            except (
                RuntimeError,
                SystemExit,
                GeneratorExit,
                KeyboardInterrupt,
                asyncio.CancelledError,
                KeyboardInterrupt,
            ):
                # dive, these errors mean we're exit(ing)
                self._exceptions = True
                return
            except Exception as e:  # noqa
                self._exceptions = True
                logger.error("Worker call failed", exc_info=e)
            finally:
                if got_obj:
                    execute.execute_futures()
                    self.queue.task_done()
Esempio n. 18
0
 def generate_error_response(self, e, request, error, status=500):
     # We may need to check the roles of the users to show the real error
     eid = uuid.uuid4().hex
     if isinstance(e, asyncio.CancelledError):  # pragma: no cover
         message = _("Cancelled execution of view") + " " + eid
         logger.warning(message, exc_info=e, eid=eid, request=request)
     else:
         message = _("Error on execution of view") + " " + eid
         logger.error(message, exc_info=e, eid=eid, request=request)
     data = {
         "message": message,
         "reason": error_reasons.UNKNOWN.name,
         "details": error_reasons.UNKNOWN.details,
         "eid": eid,
     }
     if app_settings.get("debug"):
         data["traceback"] = traceback.format_exc()
     return response.HTTPInternalServerError(content=data)
Esempio n. 19
0
def generate_error_response(e, request, error, status=500):
    # We may need to check the roles of the users to show the real error
    eid = uuid.uuid4().hex
    http_response = query_adapter(
        e, IErrorResponseException, kwargs={
            'error': error,
            'eid': eid
        })
    if http_response is not None:
        return http_response
    message = _('Error on execution of view') + ' ' + eid
    logger.error(message, exc_info=e, eid=eid, request=request)
    return response.HTTPInternalServerError(content={
        'message': message,
        'reason': error_reasons.UNKNOWN.name,
        'details': error_reasons.UNKNOWN.details,
        'eid': eid
    })
Esempio n. 20
0
def generate_error_response(e, request, error, status=500):
    # We may need to check the roles of the users to show the real error
    eid = uuid.uuid4().hex
    http_response = query_adapter(
        e, IErrorResponseException, kwargs={
            'error': error,
            'eid': eid
        })
    if http_response is not None:
        return http_response
    message = _('Error on execution of view') + ' ' + eid
    logger.error(message, exc_info=e, eid=eid, request=request)
    return response.HTTPInternalServerError(content={
        'message': message,
        'reason': error_reasons.UNKNOWN.name,
        'details': error_reasons.UNKNOWN.details,
        'eid': eid
    })
Esempio n. 21
0
 async def resolve(self, request: IRequest) -> MatchInfo:
     '''
     Resolve a request
     '''
     request.record('start')
     result = None
     try:
         result = await self.real_resolve(request)
     except HTTPException as exc:
         await abort(request)
         return BasicMatchInfo(request, exc)
     except Exception as e:
         logger.error("Exception on resolve execution",
                      exc_info=e,
                      request=request)
         await abort(request)
         raise e
     if result is not None:
         return result
     else:
         await abort(request)
         return BasicMatchInfo(request, HTTPNotFound())
Esempio n. 22
0
def generate_error_response(e, request, error, status=500):
    # We may need to check the roles of the users to show the real error
    eid = uuid.uuid4().hex
    http_response = query_adapter(e,
                                  IErrorResponseException,
                                  kwargs={
                                      "error": error,
                                      "eid": eid
                                  })
    if http_response is not None:
        return http_response
    message = _("Error on execution of view") + " " + eid
    logger.error(message, exc_info=e, eid=eid, request=request)
    data = {
        "message": message,
        "reason": error_reasons.UNKNOWN.name,
        "details": error_reasons.UNKNOWN.details,
        "eid": eid,
    }
    if app_settings.get("debug"):
        data["traceback"] = traceback.format_exc()
    return response.HTTPInternalServerError(content=data)
Esempio n. 23
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
                txn = get_transaction(view.request)
                if txn is None:
                    tm = get_tm(view.request)
                    txn = tm.begin(view.request)

                try:
                    view_result = await view()
                    if isinstance(view_result, ErrorResponse):
                        await txn.commit()
                    elif isinstance(view_result, UnauthorizedResponse):
                        await txn.abort()
                    else:
                        await txn.commit()
                except Unauthorized:
                    await txn.abort()
                except Exception as e:
                    logger.error("Exception on writing execution", exc_info=e)
                    await txn.abort()
            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()
Esempio n. 24
0
    async def resolve(self, request: IRequest) -> MatchInfo:
        '''
        Resolve a request
        '''
        request.record('start')
        result = None
        try:
            result = await self.real_resolve(request)
        except (response.Response, aiohttp.web_exceptions.HTTPException) as exc:
            await abort(request)
            return BasicMatchInfo(request, exc)
        except Exception:
            logger.error("Exception on resolve execution",
                         exc_info=True, request=request)
            await abort(request)
            return BasicMatchInfo(
                request, response.HTTPInternalServerError())

        if result is not None:
            return result
        else:
            await abort(request)
            return BasicMatchInfo(request, response.HTTPNotFound())
Esempio n. 25
0
    async def real_resolve(self, request: IRequest) -> Optional[MatchInfo]:
        """Main function to resolve a request."""
        security = get_adapter(request, IInteraction)

        if request.method not in app_settings['http_methods']:
            raise HTTPMethodNotAllowed(
                method=request.method,
                allowed_methods=[k for k in app_settings['http_methods'].keys()])
        method = app_settings['http_methods'][request.method]

        try:
            resource, tail = await self.traverse(request)
        except ConflictError:
            # can also happen from connection errors so we bubble this...
            raise
        except Exception as _exc:
            logger.error('Unhandled exception occurred', exc_info=True)
            request.resource = request.tail = None
            request.exc = _exc
            data = {
                'success': False,
                'exception_message': str(_exc),
                'exception_type': getattr(type(_exc), '__name__', str(type(_exc))),  # noqa
            }
            if app_settings.get('debug'):
                data['traceback'] = traceback.format_exc()
            raise HTTPBadRequest(content={
                'reason': data
            })

        request.record('traversed')

        await notify(ObjectLoadedEvent(resource))
        request.resource = resource
        request.tail = tail

        if request.resource is None:
            await notify(TraversalResourceMissEvent(request, tail))
            raise HTTPNotFound(content={
                "reason": 'Resource not found'
            })

        if tail and len(tail) > 0:
            # convert match lookups
            view_name = routes.path_to_view_name(tail)
        elif not tail:
            view_name = ''

        request.record('beforeauthentication')
        await self.apply_authorization(request)
        request.record('authentication')

        for language in get_acceptable_languages(request):
            translator = query_adapter((resource, request), ILanguage,
                                       name=language)
            if translator is not None:
                resource = translator.translate()
                break

        # Add anonymous participation
        if len(security.participations) == 0:
            security.add(AnonymousParticipation(request))

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

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

        # Check security on context to AccessContent unless
        # is view allows explicit or its OPTIONS
        permission = get_utility(IPermission, name='guillotina.AccessContent')
        if not security.check_permission(permission.id, resource):
            # Check if its a CORS call:
            if IOPTIONS != method:
                # Check if the view has permissions explicit
                if view is None or not view.__allow_access__:
                    logger.info(
                        "No access content {content} with {auths}".format(
                            content=resource,
                            auths=str([x.principal.id
                                       for x in security.participations])),
                        request=request)
                    raise HTTPUnauthorized(
                        content={
                            "reason": "You are not authorized to access content",
                            "content": str(resource),
                            "auths": [x.principal.id
                                      for x in security.participations]
                        }
                    )

        if not view and len(tail) > 0:
            # we should have a view in this case because we are matching routes
            await notify(TraversalViewMissEvent(request, tail))
            return None

        request.found_view = view
        request.view_name = view_name
        request.record('viewfound')

        ViewClass = view.__class__
        view_permission = get_view_permission(ViewClass)
        if not security.check_permission(view_permission, view):
            if IOPTIONS != method:
                raise HTTPUnauthorized(
                    content={
                        "reason": "You are not authorized to view",
                        "content": str(resource),
                        "auths": [x.principal.id
                                  for x in security.participations]
                    }
                )

        try:
            view.__route__.matches(request, tail or [])
        except (KeyError, IndexError):
            await notify(TraversalRouteMissEvent(request, tail))
            return None
        except AttributeError:
            pass

        if hasattr(view, 'prepare'):
            view = (await view.prepare()) or view

        request.record('authorization')

        return MatchInfo(resource, request, view)
Esempio n. 26
0
    async def real_resolve(self, request: IRequest) -> Optional[MatchInfo]:
        """Main function to resolve a request."""
        if request.method not in app_settings['http_methods']:
            raise HTTPMethodNotAllowed(
                method=request.method,
                allowed_methods=[
                    k for k in app_settings['http_methods'].keys()
                ])
        method = app_settings['http_methods'][request.method]

        try:
            resource, tail = await self.traverse(request)
        except ConflictError:
            # can also happen from connection errors so we bubble this...
            raise
        except Exception as _exc:
            logger.error('Unhandled exception occurred', exc_info=True)
            request.resource = request.tail = None
            request.exc = _exc
            data = {
                'success': False,
                'exception_message': str(_exc),
                'exception_type': getattr(type(_exc), '__name__',
                                          str(type(_exc))),  # noqa
            }
            if app_settings.get('debug'):
                data['traceback'] = traceback.format_exc()
            raise HTTPBadRequest(content={'reason': data})

        request.record('traversed')

        await notify(ObjectLoadedEvent(resource))
        request.resource = resource
        request.tail = tail

        if request.resource is None:
            await notify(TraversalResourceMissEvent(request, tail))
            raise HTTPNotFound(content={"reason": 'Resource not found'})

        if tail and len(tail) > 0:
            # convert match lookups
            view_name = routes.path_to_view_name(tail)
        elif not tail:
            view_name = ''

        request.record('beforeauthentication')
        authenticated = await authenticate_request(request)
        # Add anonymous participation
        if authenticated is None:
            authenticated = AnonymousUser()
            set_authenticated_user(authenticated)
        request.record('authentication')

        policy = get_security_policy(authenticated)

        for language in get_acceptable_languages(request):
            translator = query_adapter((resource, request),
                                       ILanguage,
                                       name=language)
            if translator is not None:
                resource = translator.translate()
                break

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

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

        # Check security on context to AccessContent unless
        # is view allows explicit or its OPTIONS
        permission = get_utility(IPermission, name='guillotina.AccessContent')
        if not policy.check_permission(permission.id, resource):
            # Check if its a CORS call:
            if IOPTIONS != method:
                # Check if the view has permissions explicit
                if view is None or not view.__allow_access__:
                    logger.info(
                        "No access content {content} with {auth}".format(
                            content=resource, auth=authenticated.id),
                        request=request)
                    raise HTTPUnauthorized(
                        content={
                            "reason":
                            "You are not authorized to access content",
                            "content": str(resource),
                            "auth": authenticated.id
                        })

        if not view and len(tail) > 0:
            # we should have a view in this case because we are matching routes
            await notify(TraversalViewMissEvent(request, tail))
            return None

        request.found_view = view
        request.view_name = view_name
        request.record('viewfound')

        ViewClass = view.__class__
        view_permission = get_view_permission(ViewClass)
        if view_permission is None:
            # use default view permission
            view_permission = app_settings['default_permission']
        if not policy.check_permission(view_permission, view):
            if IOPTIONS != method:
                raise HTTPUnauthorized(
                    content={
                        "reason": "You are not authorized to view",
                        "content": str(resource),
                        "auth": authenticated.id
                    })

        try:
            view.__route__.matches(request, tail or [])
        except (KeyError, IndexError):
            await notify(TraversalRouteMissEvent(request, tail))
            return None
        except AttributeError:
            pass

        if hasattr(view, 'prepare'):
            view = (await view.prepare()) or view

        request.record('authorization')

        return MatchInfo(resource, request, view)
Esempio n. 27
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 = await view.publish_traverse(traverse_to)
                except Exception as e:
                    logger.error("Exception on view execution", exc_info=e)
                    return None

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

        interaction = IInteraction(request)
        allowed = interaction.check_permission(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)

        if view:
            ViewClass = view.__class__
            view_permission = get_view_permission(ViewClass)
            if not interaction.check_permission(view_permission, view):
                logger.warn("No access for view {content} with {auths}".format(
                    content=resource,
                    auths=str([
                        x.principal.id for x in request.security.participations
                    ])))
                raise HTTPUnauthorized()

        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
Esempio n. 28
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 guillotina.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='guillotina.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 = await view.publish_traverse(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.MsgType.error:
                logger.debug(
                    'ws connection closed with exception {0:s}'.format(
                        ws.exception()))

        logger.debug('websocket connection closed')

        return {}
Esempio n. 29
0
    async def real_resolve(self, request: IRequest) -> MatchInfo:
        """Main function to resolve a request."""
        security = get_adapter(request, IInteraction)

        if request.method not in app_settings['http_methods']:
            raise HTTPMethodNotAllowed()
        method = app_settings['http_methods'][request.method]

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

        try:
            resource, tail = await self.traverse(request)
        except ConflictError:
            # can also happen from connection errors so we bubble this...
            raise
        except Exception as _exc:
            logger.error('Unhandled exception occurred', exc_info=True)
            request.resource = request.tail = None
            request.exc = _exc
            data = {
                'success': False,
                'exception_message': str(_exc),
                'exception_type': getattr(type(_exc), '__name__',
                                          str(type(_exc))),  # noqa
            }
            if app_settings.get('debug'):
                data['traceback'] = traceback.format_exc()
            raise HTTPBadRequest(text=ujson.dumps(data))

        request.record('traversed')

        await notify(ObjectLoadedEvent(resource))
        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:]

        request.record('beforeauthentication')
        await self.apply_authorization(request)
        request.record('authentication')

        translator = query_adapter(language_object,
                                   ITranslated,
                                   args=[resource, request])
        if translator is not None:
            resource = translator.translate()

        # Add anonymous participation
        if len(security.participations) == 0:
            security.add(AnonymousParticipation(request))

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

        request.found_view = view
        request.view_name = view_name

        # 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 = await view.publish_traverse(traverse_to)
                except KeyError:
                    return None  # not found, it's okay.
                except Exception as e:
                    logger.error("Exception on view execution",
                                 exc_info=e,
                                 request=request)
                    return None

        request.record('viewfound')
        permission = get_utility(IPermission, name='guillotina.AccessContent')

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

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

        if view:
            ViewClass = view.__class__
            view_permission = get_view_permission(ViewClass)
            if not security.check_permission(view_permission, view):
                logger.info("No access for view {content} with {auths}".format(
                    content=resource,
                    auths=str(
                        [x.principal.id for x in security.participations])),
                            request=request)
                raise HTTPUnauthorized()

        request.record('authorization')

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

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

        request.record('renderer')

        if rendered is not None:
            return MatchInfo(resource, request, view, rendered)
        else:
            return None
Esempio n. 30
0
def generate_error_response(e, request, error, status=500):
    # 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
    logger.error(message, exc_info=e, eid=eid, request=request)
    return ErrorResponse(error, message, status)
Esempio n. 31
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
    logger.error(message, exc_info=e, eid=eid, request=request)
    return UnauthorizedResponse(message)