Esempio n. 1
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)

        from guillotina.traversal import traverse
        obj, tail = await traverse(self.request, self.request.container, path)

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

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

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

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

        try:
            view.__route__.matches(self.request, tail or [])
        except (KeyError, IndexError):
            view = None

        if view is None:
            return ws.send_str(ujson.dumps({'error': 'Not found'}))

        ViewClass = view.__class__
        view_permission = get_view_permission(ViewClass)
        if not security.check_permission(view_permission, view):
            return ws.send_str(ujson.dumps({'error': 'No view access'}))

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

        view_result = await view()
        if IAioHTTPResponse.providedBy(view_result):
            raise Exception('Do not accept raw aiohttp exceptions in ws')
        else:
            from guillotina.traversal import apply_rendering
            resp = await apply_rendering(view, self.request, view_result)

        # Return the value, body is always encoded
        ws.send_str(resp.body.decode('utf-8'))

        # Wait for possible value
        self.request.execute_futures()
Esempio n. 2
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. 3
0
    async def handle_ws_request(self, ws, message):
        method = app_settings["http_methods"]["GET"]
        try:
            frame_id = message["id"]
        except KeyError:
            frame_id = "0"

        parsed = parse.urlparse(message.get("path", message.get("value")))
        path = tuple(p for p in parsed.path.split("/") if p)

        from guillotina.traversal import traverse

        obj, tail = await traverse(self.request, task_vars.container.get(),
                                   path)

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

        permission = get_utility(IPermission, name="guillotina.AccessContent")

        security = get_security_policy()
        allowed = security.check_permission(permission.id, obj)
        if not allowed:
            return await ws.send_bytes(orjson.dumps({"error": "Not allowed"}))

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

        try:
            view.__route__.matches(self.request, tail or [])
        except (KeyError, IndexError):
            view = None

        if view is None:
            return await ws.send_bytes(
                orjson.dumps({
                    "error": "Not found",
                    "id": frame_id
                }))

        ViewClass = view.__class__
        view_permission = get_view_permission(ViewClass)
        if not security.check_permission(view_permission, view):
            return await ws.send_bytes(
                orjson.dumps({
                    "error": "No view access",
                    "id": frame_id
                }))

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

        view_result = await view()
        if IResponse.providedBy(view_result):
            raise Exception("Do not accept raw ASGI exceptions in ws")
        else:
            from guillotina.traversal import apply_rendering

            resp = await apply_rendering(view, self.request, view_result)

        # Return the value, body is always encoded
        response_object = orjson.dumps({
            "data": resp.body.decode("utf-8"),
            "id": frame_id
        })
        await ws.send_bytes(response_object)

        # Wait for possible value
        self.request.execute_futures()
Esempio n. 4
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. 5
0
    async def _handle(self, request, message):
        tm = get_tm()
        txn = get_transaction()
        if txn.status in (Status.ABORTED, Status.COMMITTED, Status.CONFLICT):
            # start txn
            txn = await tm.begin()

        method = app_settings["http_methods"][message["method"].upper()]
        endpoint = urlparse(message["endpoint"]).path
        path = tuple(p for p in endpoint.split("/") if p)
        obj, tail = await traverse(request, task_vars.container.get(), path)

        if tail and len(tail) > 0:
            # convert match lookups
            view_name = routes.path_to_view_name(tail)
            # remove query params from view name
            view_name = view_name.split("?")[0]
        elif not tail:
            view_name = ""
        else:
            raise

        permission = get_utility(IPermission, name="guillotina.AccessContent")

        security = get_security_policy()
        allowed = security.check_permission(permission.id, obj)
        if not allowed:
            return {
                "success": False,
                "body": {
                    "reason": "Not allowed"
                },
                "status": 401
            }

        try:
            view = query_multi_adapter((obj, request), method, name=view_name)
        except AttributeError:
            view = None

        try:
            view.__route__.matches(request, tail or [])
        except (KeyError, IndexError, AttributeError):
            view = None

        if view is None:
            return {
                "success": False,
                "body": {
                    "reason": "Not found"
                },
                "status": 404
            }

        ViewClass = view.__class__
        view_permission = get_view_permission(ViewClass)
        if not security.check_permission(view_permission, view):
            return {
                "success": False,
                "body": {
                    "reason": "No view access"
                },
                "status": 401,
            }

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

        view_result = await view()

        if self.eager_commit:
            await tm.commit()

        return self._gen_result(view_result)
Esempio n. 6
0
    async def _handle(self, request, message):
        method = app_settings['http_methods'][message['method'].upper()]
        endpoint = urlparse(message['endpoint']).path
        path = tuple(p for p in endpoint.split('/') if p)
        obj, tail = await traverse(request, self.request.container, path)

        if tail and len(tail) > 0:
            # convert match lookups
            view_name = routes.path_to_view_name(tail)
            # remove query params from view name
            view_name = view_name.split('?')[0]
        elif not tail:
            view_name = ''
        else:
            raise

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

        security = get_adapter(self.request, IInteraction)
        allowed = security.check_permission(permission.id, obj)
        if not allowed:
            return {
                'success': False,
                'body': {
                    'reason': 'Not allowed'
                },
                'status': 401
            }

        try:
            view = query_multi_adapter((obj, request), method, name=view_name)
        except AttributeError:
            view = None

        try:
            view.__route__.matches(request, tail or [])
        except (KeyError, IndexError, AttributeError):
            view = None

        if view is None:
            return {
                'success': False,
                'body': {
                    'reason': 'Not found'
                },
                'status': 404
            }

        ViewClass = view.__class__
        view_permission = get_view_permission(ViewClass)
        if not security.check_permission(view_permission, view):
            return {
                'success': False,
                'body': {
                    'reason': 'No view access'
                },
                'status': 401
            }

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

        # Include request's security in view
        view.request.security = self.request.security
        view_result = await view()

        if self.eager_commit:
            await request._tm.commit(request)

        return self._gen_result(view_result)
Esempio n. 7
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. 8
0
    async def handle_ws_request(self, ws, message):
        method = app_settings['http_methods']['GET']
        try:
            frame_id = message['id']
        except KeyError:
            frame_id = '0'

        parsed = parse.urlparse(message.get('path', message.get('value')))
        path = tuple(p for p in parsed.path.split('/') if p)

        from guillotina.traversal import traverse
        obj, tail = await traverse(self.request, self.request.container, path)

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

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

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

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

        try:
            view.__route__.matches(self.request, tail or [])
        except (KeyError, IndexError):
            view = None

        if view is None:
            return await ws.send_str(ujson.dumps({
                'error': 'Not found',
                'id': frame_id
            }))

        ViewClass = view.__class__
        view_permission = get_view_permission(ViewClass)
        if not security.check_permission(view_permission, view):
            return await ws.send_str(ujson.dumps({
                'error': 'No view access',
                'id': frame_id
            }))

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

        view_result = await view()
        if IAioHTTPResponse.providedBy(view_result):
            raise Exception('Do not accept raw aiohttp exceptions in ws')
        else:
            from guillotina.traversal import apply_rendering
            resp = await apply_rendering(view, self.request, view_result)

        # Return the value, body is always encoded
        response_object = ujson.dumps({
            'data': resp.body.decode('utf-8'),
            'id': frame_id
        })
        await ws.send_str(response_object)

        # Wait for possible value
        self.request.execute_futures()
Esempio n. 9
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)