Esempio n. 1
0
async def test_create_annotation(db, guillotina_main):
    root = get_utility(IApplication, name='root')
    db = root['db']
    request = get_mocked_request(db)
    login(request)

    async with managed_transaction(request=request, write=True):
        container = await create_content_in_container(
            db, 'Container', 'container', request=request,
            title='Container')
        ob = await create_content_in_container(
            container, 'Item', 'foobar', request=request)

        annotations = IAnnotations(ob)
        data = AnnotationData()
        data['foo'] = 'bar'
        await annotations.async_set('foobar', data)

    async with managed_transaction(request=request, write=True):
        container = await db.async_get('container')
        ob = await container.async_get('foobar')
        annotations = IAnnotations(ob)
        assert 'foobar' in (await annotations.async_keys())
        await annotations.async_del('foobar')

    async with managed_transaction(request=request, write=True):
        container = await db.async_get('container')
        ob = await container.async_get('foobar')
        annotations = IAnnotations(ob)
        assert 'foobar' not in (await annotations.async_keys())
        await container.async_del('foobar')
        await db.async_del('container')
Esempio n. 2
0
async def iter_databases(root=None):
    if root is None:
        root = get_utility(IApplication, name='root')

    loaded = []

    for _, db in root:
        if IDatabase.providedBy(db):
            yield db
            loaded.append(db.id)

    last_checked = None

    while last_checked is None or set(last_checked) != set(loaded):
        # we need to continue checking until we're sure there aren't any
        # new storage objects that have been added since we started
        last_checked = loaded[:]

        # from all dynamic storages
        for _, config in list_or_dict_items(app_settings['storages']):
            ctype = config.get('type', config['storage'])
            factory = get_adapter(root, IDatabaseManager, name=ctype, args=[config])
            for db_name in await factory.get_names():
                if db_name in loaded:
                    continue
                db = await factory.get_database(db_name)
                loaded.append(db.id)
                yield db
Esempio n. 3
0
async def get_containers(request):
    root = get_utility(IApplication, name='root')
    for _id, db in root:
        if IDatabase.providedBy(db):
            tm = request._tm = db.get_transaction_manager()
            request._db_id = _id
            async with tm.lock:
                # reset _txn to make sure to create a new ob
                request._txn = None
                txn = await tm.begin(request)
                items = {}
                async for c_id, container in db.async_items():
                    items[c_id] = container
                await tm.abort(txn=txn)

            for _, container in items.items():
                request._txn = txn = await tm.begin(request)
                container._p_jar = request._txn
                request.container = container
                request._container_id = container.id
                if hasattr(request, 'container_settings'):
                    del request.container_settings
                yield txn, tm, container
                try:
                    # do not rely on consumer of object to always close it.
                    # there is no harm in aborting twice
                    await tm.abort(txn=txn)
                except Exception:
                    logger.warn('Error aborting transaction', exc_info=True)
Esempio n. 4
0
async def test_write_large_blob_data(db, guillotina_main):
    root = get_utility(IApplication, name='root')
    db = root['db']
    request = get_mocked_request(db)
    login(request)

    async with managed_transaction(request=request):
        container = await db.async_get('container')
        if container is None:
            container = await create_content_in_container(
                db, 'Container', 'container', request=request,
                title='Container')

        blob = Blob(container)
        container.blob = blob

        multiplier = 999999

        blobfi = blob.open('w')
        await blobfi.async_write(b'foobar' * multiplier)

    async with managed_transaction(request=request):
        container = await db.async_get('container')
        assert await container.blob.open().async_read() == (b'foobar' * multiplier)
        assert container.blob.size == len(b'foobar' * multiplier)
        assert container.blob.chunks == 6

        await db.async_del('container')
Esempio n. 5
0
def dummy_request(dummy_guillotina, monkeypatch):
    from guillotina.interfaces import IApplication
    from guillotina.component import get_utility
    root = get_utility(IApplication, name='root')
    db = root['db']

    request = get_mocked_request(db)
    return request
Esempio n. 6
0
async def test_async_util_started_and_stopped(dummy_guillotina):
    util = get_utility(ITestAsyncUtility)
    util.state == 'init'

    config_utility = {
        "provides": "guillotina.test_package.ITestAsyncUtility",
        "factory": "guillotina.test_package.AsyncUtility",
        "settings": {}
    }
    dummy_guillotina.root.add_async_utility('test', config_utility)
    util2 = get_utility(ITestAsyncUtility)
    assert util != util2
    # Let the game start
    await asyncio.sleep(0.1)
    assert util2.state == 'initialize'
    await close_utilities(dummy_guillotina)
    assert util2.state == 'finalize'
Esempio n. 7
0
    async def get_database(self, name: str) -> IDatabase:
        if name not in self.app:
            config = deepcopy(self.config)
            factory = get_utility(
                IDatabaseConfigurationFactory, name=config['storage'])
            self.app[name] = await apply_coroutine(factory, name, config)
            await notify(DatabaseInitializedEvent(self.app[name]))

        return self.app[name]
Esempio n. 8
0
 async def del_async_utility(self, key):
     self.cancel_async_utility(key)
     config = self._async_utilities[key]['config']
     interface = import_class(config['provides'])
     utility = get_utility(interface)
     if hasattr(utility, 'finalize'):
         await lazy_apply(utility.finalize, app=self.app)
     gsm = get_global_components()
     gsm.unregisterUtility(utility, provided=interface)
     del self._async_utilities[key]
Esempio n. 9
0
def reindex_in_future(context, request, security=False):
    '''
    Function to reindex a tree of content in the catalog.
    '''
    search = query_utility(ICatalogUtility)
    if search is not None:
        pool = get_utility(IAsyncJobPool)
        pool.add_job_after_commit(
            search.reindex_all_content, request=request,
            args=[context, security], kwargs={'request': request})
Esempio n. 10
0
async def test_run_jobs(guillotina):
    pool = get_utility(IAsyncJobPool)
    job = pool.add_job(JobRunner(), args=['foobar'])
    assert pool.num_running == 1
    assert pool.num_pending == 0
    await asyncio.sleep(0.1)
    assert pool.num_running == 1
    job.func.wait = False
    await asyncio.sleep(0.1)
    assert pool.num_running == 0
    assert pool.num_pending == 0
    assert job.func.done
Esempio n. 11
0
def hash_password(password, salt=None, algorithm='sha512'):
    if salt is None:
        salt = uuid.uuid4().hex

    if isinstance(salt, str):
        salt = salt.encode('utf-8')

    if isinstance(password, str):
        password = password.encode('utf-8')

    hash_func = get_utility(IPasswordHasher, name=algorithm)
    hashed_password = hash_func(password, salt)
    return '{}:{}:{}'.format(algorithm, salt.decode('utf-8'), hashed_password)
Esempio n. 12
0
def apply_concrete_behaviors():
    '''
    Configured behaviors for an object should always be applied and can't
    be removed.

    Should be called once at startup instead of doing alsoProvides every
    time an object is created
    '''
    for type_name, factory in get_utilities_for(IResourceFactory):
        for behavior in factory.behaviors:
            behavior_registration = get_utility(
                IBehavior, name=behavior.__identifier__)
            if behavior_registration.marker is not None:
                classImplements(factory._callable, behavior_registration.marker)
Esempio n. 13
0
async def test_run_many_jobs(guillotina, dummy_request):
    pool = get_utility(IAsyncJobPool)
    jobs = [pool.add_job(JobRunner(), args=['foobar'], request=dummy_request)
            for _ in range(20)]
    assert pool.num_running == 5
    assert pool.num_pending == 15

    for job in jobs:
        job.func.wait = False

    await asyncio.sleep(0.1)
    assert pool.num_running == 0
    assert pool.num_pending == 0

    for job in jobs:
        assert job.func.done
Esempio n. 14
0
async def run_async(func, *args, **kwargs) -> object:
    '''
    Run a non-async function in an executor

    >>> async def foobar(): return 'hi'
    >>> await run_async(foobar)
    'hi'

    :param func: function to run as coroutiune if one
    :param *args: args to call function with
    :param **kwargs: kwargs to call function with
    '''
    root = get_utility(IApplication, name='root')
    loop = asyncio.get_event_loop()
    func = partial(func, *args, **kwargs)
    return await loop.run_in_executor(root.executor, func)
Esempio n. 15
0
    def _global_roles_for(self, principal):
        """On a principal (user/group) get global roles."""
        roles = {}
        groups = get_utility(IGroups)
        if self.principal and principal == self.principal.id:
            # Its the actual user id
            # We return all the global roles (including group)
            roles = self.principal.roles.copy()

            for group in self.principal.groups:
                roles.update(groups.get_principal(group).roles)
            return roles

        # We are asking for group id so only group roles
        if groups:
            group = groups.get_principal(principal)
            return group.roles.copy()
Esempio n. 16
0
async def get_database(db_id, root=None):
    if root is None:
        root = get_utility(IApplication, name='root')

    if db_id in root:
        db = root[db_id]
        if IDatabase.providedBy(db):
            return db

    for _, config in list_or_dict_items(app_settings['storages']):
        ctype = config.get('type', config['storage'])
        factory = get_adapter(root, IDatabaseManager, name=ctype, args=[config])
        databases = await factory.get_names()
        if db_id in databases:
            return await factory.get_database(db_id)

    return None
Esempio n. 17
0
async def test_create_blob(db, guillotina_main):
    root = get_utility(IApplication, name='root')
    db = root['db']
    request = get_mocked_request(db)
    login(request)

    async with managed_transaction(request=request):
        container = await create_content_in_container(
            db, 'Container', 'container', request=request,
            title='Container')

        blob = Blob(container)
        container.blob = blob

    async with managed_transaction(request=request):
        container = await db.async_get('container')
        assert blob.bid == container.blob.bid
        assert blob.resource_zoid == container._p_oid
        await db.async_del('container')
Esempio n. 18
0
    async def __call__(self):
        factory = self.factory
        result = {
            'title': factory.type_name,
            '$schema': 'http://json-schema.org/draft-04/schema#',
            'type': 'object',
            'required': [],
            'definitions': {},
            'properties': {}
        }

        # Base object class serialized
        for name, field in get_fields_in_order(factory.schema):
            if field.required:
                result['required'].append(name)
            serializer = get_multi_adapter(
                (field, factory.schema, self.request),
                ISchemaFieldSerializeToJson)
            result['properties'][name] = await serializer()

        invariants = []
        for i in factory.schema.queryTaggedValue('invariants', []):
            invariants.append("%s.%s" % (i.__module__, i.__name__))
        result['invariants'] = invariants

        # Behavior serialization
        for schema in factory.behaviors or ():
            schema_serializer = get_multi_adapter(
                (schema, self.request), ISchemaSerializeToJson)

            serialization = await schema_serializer()
            result['properties'][schema_serializer.name] = \
                {'$ref': '#/definitions/' + schema_serializer.name},
            result['definitions'][schema_serializer.name] = serialization

            behavior = get_utility(IBehavior, name=schema_serializer.name)

            definition = result['definitions'][schema_serializer.name]
            definition['title'] = behavior.title or schema_serializer.short_name
            definition['description'] = behavior.description

        return result
Esempio n. 19
0
    def _global_permissions_for(self, principal, permission):
        """On a principal (user + group) get global permissions."""
        groups = get_utility(IGroups)
        if self.principal and principal == self.principal.id:
            # Its the actual user
            permissions = self.principal.permissions.copy()
            if permission in permissions:
                return level_setting_as_boolean('p', permissions[permission])

            for group in self.principal.groups:
                permissions = groups.get_principal(principal).permissions
                if permission in permissions:
                    return level_setting_as_boolean('p', permissions[permission])

        if groups:
            # Its a group
            permissions = groups.get_principal(principal).permissions
            if permission in permissions:
                return level_setting_as_boolean('p', permissions[permission])
        return None
Esempio n. 20
0
async def test_add_sync_utility(guillotina, loop):

    util = get_utility(IQueueUtility)
    var = []

    async def printHi(msg):
        await asyncio.sleep(0.01)
        var.append(msg)

    request = utils.get_mocked_request(guillotina.db)
    root = await utils.get_root(request)

    await util.add(AsyncMockView(root, request, printHi, 'hola1'))
    await util.add(AsyncMockView(root, request, printHi, 'hola2'))
    await util.add(AsyncMockView(root, request, printHi, 'hola3'))
    await util.add(AsyncMockView(root, request, printHi, 'hola4'))
    await util._queue.join()
    assert 'hola1' in var
    assert 'hola2' in var
    assert 'hola3' in var
    assert 'hola4' in var
    assert len(var) == 4
Esempio n. 21
0
async def get_user_info(context, request):
    """Return information about the logged in user.
    """
    result = {}
    groups = set()
    principal = IInteraction(request).principal
    result[principal.id] = {
        'roles': principal.roles,
        'groups': principal.groups,
        'permissions': principal.permissions,
        'properties': principal.properties
    }
    groups.update(principal.groups)

    group_search = get_utility(IGroups)
    result['groups'] = {}
    for group in groups:
        group_object = group_search.get_principal(group)
        result['groups'][group_object.id] = {
            'roles': group_object.roles,
            'groups': group_object.groups
        }

    return result
Esempio n. 22
0
def change_transaction_strategy(strategy='none'):
    root = get_utility(IApplication, name='root')
    for _id, db in root:
        if IDatabase.providedBy(db):
            db._storage._transaction_strategy = strategy
Esempio n. 23
0
 async def run(self, arguments, settings, app):
     root = get_utility(IApplication, name='root')
     for _id, db in root:
         if IDatabase.providedBy(db):
             print(f'Initializing database: {_id}')
             await db._storage.create()
Esempio n. 24
0
 def get_executor(self):
     root = get_utility(IApplication, name='root')
     if not hasattr(root, '_pw_executor'):
         root._pw_executor = ThreadPoolExecutor(max_workers=2)
     return root._pw_executor
Esempio n. 25
0
async def app_initialized(event):
    factory = get_utility(IResourceFactory, "Container")
    # factory = get_cached_factory("Container")
    factory.behaviors = (IDublinCore, ICMSBehavior, IBlocks)
    load_cached_schema()
Esempio n. 26
0
 def __init__(self, server, loop):
     self.server = server
     self.loop = loop
     self.root = get_utility(IApplication, name='root')
     self.db = self.root['db']
Esempio n. 27
0
async def app_cleanup(event):
    util = get_utility(IKafkaProducerUtility)
    try:
        await util.stop_active_consumers()
    except Exception:
        pass
Esempio n. 28
0
 async def run(self, arguments, settings, app):
     login()
     utility = get_utility(IEvolutionUtility)
     async for _, _, container in get_containers():
         if await utility.is_installed(container):
             await utility.evolve(container)
Esempio n. 29
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. 30
0
async def close_utilities(app):
    root = get_utility(IApplication, name='root')
    for key in list(root._async_utilities.keys()):
        logger.info('Removing ' + key)
        await root.del_async_utility(key)
Esempio n. 31
0
 def __init__(self, host, port):
     self.host = host
     self.port = port
     self.client = aiohttp.ClientSession()
     self.root = get_utility(IApplication, name="root")
     self.db = self.root["db"]
Esempio n. 32
0
async def test_txn_uses_cached_hits_on_annotations(redis_container,
                                                   guillotina_main):
    util = get_utility(ICacheUtility)
    await util.initialize()

    async with transaction(db=await get_database("db")) as txn:
        root = await txn.manager.get_root()
        container = await create_container(root, "container")

        with pytest.raises(KeyError):
            # should set in cache as empty though
            await txn.get_annotation(container, "foobar")
        # should be registered as cache miss
        assert txn._cache._hits == 0
        assert txn._cache._misses == 2

        with pytest.raises(KeyError):
            # do again, should be hit this time
            await txn.get_annotation(container, "foobar")

        assert txn._cache._hits == 1
        assert txn._cache._misses == 2

        # now set a value for it and we'll retrieve it again
        annotations_container = IAnnotations(container)
        adata = AnnotationData()
        await annotations_container.async_set("foobar", adata)

    async with transaction(db=await get_database("db")) as txn:
        # everything here should be hits!
        root = await txn.manager.get_root()
        container = await root.async_get("container")

        adata = await txn.get_annotation(container, "foobar")
        # should be registered as cache miss
        assert txn._cache._hits == 2
        assert txn._cache._misses == 0

    async with transaction(db=await get_database("db")) as txn:
        # now, edit the value
        root = await txn.manager.get_root()
        container = await root.async_get("container")

        adata = await txn.get_annotation(container, "foobar")
        adata["foo"] = "bar"
        adata.register()
        # should be registered as cache miss
        assert txn._cache._hits == 2
        assert txn._cache._misses == 0

    async with transaction(db=await get_database("db")) as txn:
        # everything here should be hits!
        root = await txn.manager.get_root()
        container = await root.async_get("container")

        adata = await txn.get_annotation(container, "foobar")
        assert adata["foo"] == "bar"
        # should be registered as cache miss
        assert txn._cache._hits == 2
        assert txn._cache._misses == 0

    # same again, but clear cache implementation
    await util.clear()

    async with transaction(db=await get_database("db")) as txn:
        # everything here should be hits!
        root = await txn.manager.get_root()
        container = await root.async_get("container")

        adata = await txn.get_annotation(container, "foobar")
        assert adata["foo"] == "bar"
        # should be registered as cache miss
        assert txn._cache._hits == 0
        assert txn._cache._misses == 2
Esempio n. 33
0
async def test_catch_client_error(own_dummy_request):
    util = get_utility(IS3BlobStore)
    with pytest.raises(botocore.exceptions.ClientError):
        await _test_exc_backoff(util)
Esempio n. 34
0
 async def run(self, arguments, settings, app):
     self.arguments = arguments
     root = get_utility(IApplication, name='root')
     for _id, db in root:
         if IDatabase.providedBy(db):
             await self.generate_test_data(db)
Esempio n. 35
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. 36
0
async def test_send_mail_print(guillotina_main, event_loop):

    util = get_utility(IMailer)
    await util.send(
        recipient="*****@*****.**", subject="Test Mail", html="<h1>Good mail</h1>", sender="*****@*****.**"
    )
Esempio n. 37
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. 38
0
 def __init__(self, server, loop):
     self.server = server
     self.loop = loop
     self.root = get_utility(IApplication, name='root')
     self.db = self.root['db']
Esempio n. 39
0
async def stats(context, request):
    utility = get_utility(ICacheUtility)
    return await utility.get_stats()
Esempio n. 40
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. 41
0
async def duplicate(
    context: IResource,
    destination: Optional[Union[IResource, str]] = None,
    new_id: Optional[str] = None,
    check_permission: bool = True,
    reset_acl: bool = False,
) -> IResource:
    if destination is not None:
        if isinstance(destination, str):
            destination_ob = None
            if destination.startswith("/"):
                container = task_vars.container.get()
                if container:
                    try:
                        destination_ob = await navigate_to(container, destination)
                    except KeyError:
                        pass
            else:
                try:
                    destination_ob = await get_object_by_uid(destination)
                except KeyError:
                    pass
        else:
            destination_ob = destination

        if destination_ob is None:
            raise PreconditionFailed(context, "Could not find destination object")
    else:
        destination_ob = context.__parent__

    if check_permission:
        policy = get_security_policy()
        if not policy.check_permission("guillotina.AddContent", destination_ob):
            raise PreconditionFailed(
                context, "You do not have permission to add content to " "the destination object"
            )

    if new_id is not None:
        if await destination_ob.async_contains(new_id):
            raise PreconditionFailed(context, f"Destination already has object with the id {new_id}")
    else:
        count = 1
        new_id = f"{context.id}-duplicate-{count}"
        while await destination_ob.async_contains(new_id):
            count += 1
            new_id = f"{context.id}-duplicate-{count}"

    from guillotina.content import create_content_in_container

    creators = context.creators
    contributors = context.contributors
    user_id = get_authenticated_user_id()
    if reset_acl:
        creators = [user_id]
        contributors = [user_id]
    new_obj = await create_content_in_container(
        destination_ob,
        context.type_name,
        new_id,
        id=new_id,
        creators=creators,
        contributors=contributors,
        check_security=check_permission,
        check_constraints=True,
    )
    for key in context.__dict__.keys():
        if key.startswith("__") or key.startswith("_BaseObject"):
            continue
        if key in ("id", "creators", "contributors"):
            continue
        new_obj.__dict__[key] = context.__dict__[key]

    if reset_acl:
        new_obj.__acl__ = None
        get_owner = get_utility(IGetOwner)
        roleperm = IPrincipalRoleManager(new_obj)
        owner = await get_owner(new_obj, user_id)
        if owner is not None:
            roleperm.assign_role_to_principal("guillotina.Owner", owner)
    else:
        new_obj.__acl__ = context.__acl__

    for behavior in context.__behaviors__:
        new_obj.add_behavior(behavior)
    # need to copy annotation data as well...
    # load all annotations for context
    [b for b in await get_all_behaviors(context, load=True)]
    annotations_container = IAnnotations(new_obj)
    for anno_id, anno_data in context.__gannotations__.items():
        new_anno_data = AnnotationData()
        for key, value in anno_data.items():
            new_anno_data[key] = value
        await annotations_container.async_set(anno_id, new_anno_data)

    await notify(
        ObjectDuplicatedEvent(
            new_obj, context, destination_ob, new_id, payload={"id": new_id, "destination": destination}
        )
    )
    return new_obj
Esempio n. 42
0
async def clear(context, request):
    utility = get_utility(ICacheUtility)
    await utility.clear()
    return {"success": True}
async def test_utility_is_installed(my_requester):
    utility = get_utility(IEvolutionUtility)

    async with ctx(my_requester) as container:
        assert await utility.is_installed(container) is True
Esempio n. 44
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()
async def test_utility_is_not_installed(my_requester):
    utility = get_utility(IEvolutionUtility)

    async with ctx(my_requester, install_evolution=False) as container:
        assert await utility.is_installed(container) is False
Esempio n. 46
0
    async def __call__(self):
        """To create a content."""
        data = await self.get_data()
        type_ = data.get('@type', None)
        id_ = data.get('id', None)
        behaviors = data.get('@behaviors', None)

        if not type_:
            raise ErrorResponse('RequiredParam',
                                _("Property '@type' is required"),
                                reason=error_reasons.REQUIRED_PARAM_MISSING,
                                status=412)

        # Generate a temporary id if the id is not given
        new_id = None
        if not id_:
            generator = query_adapter(self.request, IIDGenerator)
            if generator is not None:
                new_id = generator(data)
                if isinstance(new_id, str) and not valid_id(new_id):
                    raise ErrorResponse('PreconditionFailed',
                                        'Invalid id: {}'.format(new_id),
                                        status=412,
                                        reason=error_reasons.INVALID_ID)
        else:
            if not isinstance(id_, str) or not valid_id(id_):
                raise ErrorResponse('PreconditionFailed',
                                    'Invalid id: {}'.format(id_),
                                    status=412,
                                    reason=error_reasons.INVALID_ID)
            new_id = id_

        user = get_authenticated_user_id(self.request)

        options = {'creators': (user, ), 'contributors': (user, )}
        if 'uid' in data:
            options['_p_oid'] = data.pop('uid')

        # Create object
        try:
            obj = await create_content_in_container(self.context, type_,
                                                    new_id, **options)
        except ValueError as e:
            return ErrorResponse('CreatingObject', str(e), status=412)

        for behavior in behaviors or ():
            obj.add_behavior(behavior)

        # Update fields
        deserializer = query_multi_adapter((obj, self.request),
                                           IResourceDeserializeFromJson)
        if deserializer is None:
            return ErrorResponse('DeserializationError',
                                 'Cannot deserialize type {}'.format(
                                     obj.type_name),
                                 status=412,
                                 reason=error_reasons.DESERIALIZATION_FAILED)

        await deserializer(data, validate_all=True, create=True)

        # Local Roles assign owner as the creator user
        get_owner = get_utility(IGetOwner)
        roleperm = IPrincipalRoleManager(obj)
        owner = await get_owner(obj, user)
        if owner is not None:
            roleperm.assign_role_to_principal('guillotina.Owner', owner)

        data['id'] = obj.id
        await notify(ObjectAddedEvent(obj, self.context, obj.id, payload=data))

        absolute_url = query_multi_adapter((obj, self.request), IAbsoluteURL)

        headers = {
            'Access-Control-Expose-Headers': 'Location',
            'Location': absolute_url()
        }

        serializer = query_multi_adapter((obj, self.request),
                                         IResourceSerializeToJsonSummary)
        response = await serializer()
        return Response(content=response, status=201, headers=headers)
Esempio n. 47
0
    async def create_request(self):
        req_data = self.data['req_data']
        url = req_data['url']
        parsed = urlparse(url)
        dct = {
            'method':
            req_data['method'],
            'url':
            yarl.URL(url),
            'path':
            parsed.path,
            'headers':
            CIMultiDict(req_data['headers']),
            'raw_headers':
            tuple((k.encode('utf-8'), v.encode('utf-8'))
                  for k, v in req_data['headers'].items())
        }

        message = self.base_request._message._replace(**dct)

        payload_writer = mock.Mock()
        payload_writer.write_eof.side_effect = noop
        payload_writer.drain.side_effect = noop

        protocol = mock.Mock()
        protocol.transport = test_utils._create_transport(None)
        protocol.writer = payload_writer

        request = self.base_request.__class__(
            message,
            EmptyPayload(),
            protocol,
            payload_writer,
            self.task,
            self.task._loop,
            client_max_size=self.base_request._client_max_size,
            state=self.base_request._state.copy())
        g_task_vars.request.set(request)
        request.annotations = req_data.get('annotations', {})

        if self.data.get('db_id'):
            root = get_utility(IApplication, name='root')
            db = await root.async_get(self.data['db_id'])
            g_task_vars.db.set(db)
            # Add a transaction Manager to request
            tm = db.get_transaction_manager()
            g_task_vars.tm.set(tm)
            # Start a transaction
            txn = await tm.begin()
            # Get the root of the tree
            context = await tm.get_root(txn=txn)

            if self.data.get('container_id'):
                container = await context.async_get(self.data['container_id'])
                if container is None:
                    raise Exception(
                        f'Could not find container: {self.data["container_id"]}'
                    )
                g_task_vars.container.set(container)
                annotations_container = IAnnotations(container)
                container_settings = await annotations_container.async_get(
                    REGISTRY_DATA_KEY)
                layers = container_settings.get(ACTIVE_LAYERS_KEY, [])
                for layer in layers:
                    try:
                        alsoProvides(request, import_class(layer))
                    except ModuleNotFoundError:
                        pass
                g_task_vars.registry.set(container_settings)
        return request
async def auth_callback(context, request):
    provider = request.matchdict['provider']

    if provider in utils.oauth1_providers:
        oauth_verifier = request.url.query.get('oauth_verifier')
        oauth_token = request.url.query.get('oauth_token')
        client = utils.get_client(provider, oauth_token=oauth_token)
        cache_utility = get_utility(ICacheUtility)
        request_token = await cache_utility.get(CACHE_PREFIX + oauth_token)
        if request_token is None:
            raise web.HTTPBadRequest(
                reason='Failed to obtain proper request token.')
        oauth_token, oauth_token_secret, otoken_data = await client.get_access_token(  # noqa
            oauth_verifier, oauth_token)

        client_args = dict(oauth_token=oauth_token,
                           oauth_token_secret=oauth_token_secret)
    else:
        client = utils.get_client(provider)
        if 'error' in request.url.query:
            raise HTTPBadRequest(content=dict(request.url.query))

        if 'code' not in request.url.query:
            raise HTTPBadRequest(content=dict(request.url.query))

        code = request.url.query['code']

        if 'callback' not in request.url.query:
            callback = str(request.url.with_path('@callback/' + provider))
        else:
            callback = request.url.query['callback']

        forwarded_proto = request.headers.get('X-Forwarded-Proto', None)
        if forwarded_proto and forwarded_proto != request.scheme:
            callback = callback.replace(request.scheme + '://',
                                        forwarded_proto + '://')

        otoken, otoken_data = await client.get_access_token(
            code, redirect_uri=callback)

        client_args = dict(access_token=otoken,
                           refresh_token=otoken_data['refresh_token'])

    if 'expires_in' in otoken_data:
        timeout = otoken_data['expires_in']
    else:
        timeout = 60 * 60 * 1

    client = utils.get_client(provider, **client_args)
    user, user_data = await client.user_info()

    jwt_token, data = authenticate_user(
        user.id, {
            'first_name': user.first_name,
            'last_name': user.last_name,
            'email': user.email,
            'username': user.username,
            'client': provider,
            'client_args': client_args,
            'allowed_scopes': user_data.get('allowed_scopes'),
            'scope': request.url.query.get('scope').split(' '),
            'identifier': 'oauth'
        },
        timeout=timeout)

    await notify(UserLogin(user, jwt_token))

    result = {'exp': data['exp'], 'token': jwt_token}
    if app_settings.get('auth_callback_url'):
        url = yarl.URL(app_settings['auth_callback_url']).with_query(result)
        return HTTPFound(str(url))
    return result
Esempio n. 49
0
async def test_vacuum_with_sub_indexes(es_requester):
    async with es_requester as requester:
        await add_content(requester, num_folders=2, num_items=5, path='/db/guillotina/')

        cresp, _ = await requester(
            'POST',
            '/db/guillotina/',
            data=json.dumps({
                '@type': 'UniqueIndexContent',
                'title': 'UniqueIndexContent',
                'id': 'foobar'
            })
        )
        await add_content(requester, num_folders=2, num_items=5, path='/db/guillotina/foobar')

        search = get_utility(ICatalogUtility)
        content_index_name = 'guillotina-db-guillotina__uniqueindexcontent-{}'.format(
            get_short_oid(cresp['@uid'])
        )
        container, request, txn, tm = await setup_txn_on_container(requester)
        aiotask_context.set('request', request)

        async def _test():
            assert await search.get_doc_count(container) == 13
            assert await search.get_doc_count(index_name=content_index_name) == 12

        await run_with_retries(_test, requester)

        for key in await container.async_keys():
            if key == 'foobar':
                continue
            ob = await container.async_get(key)
            await search.remove(container, [ob], request=request)

        await asyncio.sleep(1)

        foobar = await container.async_get('foobar')
        for key in await foobar.async_keys():
            ob = await foobar.async_get(key)
            await search.remove(container, [ob], request=request)

        await asyncio.sleep(1)

        await search.index(container, {
            'foobar1': {
                'title': 'foobar',
                'type_name': 'Item'
            }
        })
        await search.index(container, {
            'foobar2': {
                'title': 'foobar',
                'type_name': 'Item',
                '__indexes__': [content_index_name]
            }
        })

        async def __test():
            assert await search.get_doc_count(container) == 2
            assert await search.get_doc_count(index_name=content_index_name) == 1

        await run_with_retries(__test, requester)

        vacuum = Vacuum(txn, tm, request, container)
        await vacuum.setup()
        await vacuum.check_missing()
        await vacuum.check_orphans()

        assert len(vacuum.orphaned) == 2
        assert len(vacuum.out_of_date) == 0
        assert len(vacuum.missing) == 24

        async def ___test():
            assert await search.get_doc_count(container) == 13
            assert await search.get_doc_count(index_name=content_index_name) == 12

        await run_with_retries(___test, requester)

        await tm.abort(txn=txn)
Esempio n. 50
0
 def __init__(self, client):
     self.client = client
     self.root = get_utility(IApplication, name="root")
     self.db = self.root["db"]
Esempio n. 51
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. 52
0
async def make_app(config_file=None, settings=None, loop=None, server_app=None):
    '''
    Make application from configuration

    :param config_file: path to configuration file to load
    :param settings: dictionary of settings
    :param loop: if not using with default event loop
    :param settings: provide your own aiohttp application
    '''
    # reset app_settings
    startup_vars = {}
    for key in app_settings.keys():
        if key[0] == '_':
            startup_vars[key] = app_settings[key]

    app_settings.clear()
    app_settings.update(startup_vars)
    app_settings.update(deepcopy(default_settings))

    if loop is None:
        loop = asyncio.get_event_loop()

    # chainmap task factory is actually very important
    # default task factory uses inheritance in a way
    # that bubbles back down. So it's possible for a sub-task
    # to clear out the request of the parent task
    loop.set_task_factory(aiotask_context.chainmap_task_factory)

    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')

    # Create root Application
    root = ApplicationRoot(config_file, loop)
    provide_utility(root, IApplication, 'root')

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

    app_configurator = ApplicationConfigurator(
        settings.get('applications') or [],
        config, root, settings
    )

    configure.scan('guillotina.renderers')
    configure.scan('guillotina.api')
    configure.scan('guillotina.content')
    configure.scan('guillotina.registry')
    configure.scan('guillotina.auth')
    configure.scan('guillotina.json')
    configure.scan('guillotina.behaviors')
    configure.scan('guillotina.languages')
    configure.scan('guillotina.permissions')
    configure.scan('guillotina.security.security_local')
    configure.scan('guillotina.security.policy')
    configure.scan('guillotina.auth.participation')
    configure.scan('guillotina.catalog.index')
    configure.scan('guillotina.catalog.catalog')
    configure.scan('guillotina.files')
    configure.scan('guillotina.annotations')
    configure.scan('guillotina.constraintypes')
    configure.scan('guillotina.subscribers')
    configure.scan('guillotina.db.strategies')
    configure.scan('guillotina.db.cache')
    configure.scan('guillotina.db.writer')
    configure.scan('guillotina.db.factory')
    configure.scan('guillotina.exc_resp')
    configure.scan('guillotina.fields')
    configure.scan('guillotina.migrations')

    # always load guillotina
    app_configurator.configure_application('guillotina')
    app_configurator.configure_all_applications()

    apply_concrete_behaviors()

    # update *after* plugins loaded
    update_app_settings(settings)

    if 'logging' in app_settings:
        try:
            logging.config.dictConfig(app_settings['logging'])
        except Exception:
            logger.error('Could not setup logging configuration', exc_info=True)

    # Make and initialize aiohttp app
    if server_app is None:
        server_app = make_aiohttp_application()
    root.app = server_app
    server_app.root = root
    server_app.config = config

    optimize_settings(app_settings)

    await notify(ApplicationConfiguredEvent(server_app, loop))

    for key, dbconfig in list_or_dict_items(app_settings['databases']):
        factory = get_utility(
            IDatabaseConfigurationFactory, name=dbconfig['storage'])
        root[key] = await factory(key, dbconfig, loop)
        await notify(DatabaseInitializedEvent(root[key]))

    for key, file_path in list_or_dict_items(app_settings['static']):
        path = resolve_path(file_path).resolve()
        if not path.exists():
            raise Exception('Invalid static directory {}'.format(file_path))
        if path.is_dir():
            root[key] = StaticDirectory(path)
        else:
            root[key] = StaticFile(path)

    for key, file_path in list_or_dict_items(app_settings['jsapps']):
        path = resolve_path(file_path).resolve()
        if not path.exists() or not path.is_dir():
            raise Exception('Invalid jsapps directory {}'.format(file_path))
        root[key] = JavaScriptApplication(path)

    root.set_root_user(app_settings['root_user'])

    if app_settings.get('jwk') and\
            app_settings.get('jwk').get('k') and\
            app_settings.get('jwk').get('kty'):
        key = jwk.JWK.from_json(json.dumps(app_settings.get('jwk')))
        app_settings['jwk'] = key
        # {"k":"QqzzWH1tYqQO48IDvW7VH7gvJz89Ita7G6APhV-uLMo","kty":"oct"}

    if not app_settings.get('debug') and app_settings['jwt'].get('secret'):
        # validate secret
        secret = app_settings['jwt']['secret']
        if secret == 'secret':
            logger.warning(
                'You are using a very insecure secret key in production mode. '
                'It is strongly advised that you provide a better value for '
                '`jwt.secret` in your config.')
        elif not secure_passphrase(app_settings['jwt']['secret']):
            logger.warning(
                'You are using a insecure secret key in production mode. '
                'It is recommended that you provide a more complex value for '
                '`jwt.secret` in your config.')

    # Set router root
    server_app.router.set_root(root)
    server_app.on_cleanup.append(cleanup_app)

    for util in app_settings.get('utilities') or []:
        logger.warn('Adding : ' + util['provides'])
        root.add_async_utility(util['provides'], util, loop=loop)

    for key, util in app_settings['load_utilities'].items():
        logger.info('Adding ' + key + ' : ' + util['provides'])
        root.add_async_utility(key, util, loop=loop)

    # Load cached Schemas
    load_cached_schema()

    await notify(ApplicationInitializedEvent(server_app, loop))

    return server_app
Esempio n. 53
0
async def __add_to_pool(func: Callable[..., Coroutine[Any, Any, Any]], request,
                        args, kwargs):
    # make add_job async
    util = get_utility(IAsyncJobPool)
    util.add_job(func, request=request, args=args, kwargs=kwargs)
Esempio n. 54
0
async def close_dbs(app):
    root = get_utility(IApplication, name='root')
    for db in root:
        if IDatabase.providedBy(db[1]):
            await db[1].finalize()
Esempio n. 55
0
async def startup_app(config_file=None,
                      settings=None,
                      loop=None,
                      server_app=None):
    """
    Make application from configuration

    :param config_file: path to configuration file to load
    :param settings: dictionary of settings
    :param loop: if not using with default event loop
    :param settings: provide your own asgi application
    """
    assert loop is not None

    # reset app_settings
    startup_vars = {}
    for key in app_settings.keys():
        if key[0] == "_":
            startup_vars[key] = app_settings[key]

    app_settings.clear()
    app_settings.update(startup_vars)
    app_settings.update(deepcopy(default_settings))

    if config_file is not None:
        from guillotina.commands import get_settings

        settings = get_settings(config_file)
    elif settings is None:
        raise Exception("Neither configuration or settings")

    # Create root Application
    root = ApplicationRoot(config_file, loop)
    provide_utility(root, IApplication, "root")

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

    app_configurator = ApplicationConfigurator(
        settings.get("applications") or [], config, root, settings)

    configure.scan("guillotina.renderers")
    configure.scan("guillotina.api")
    configure.scan("guillotina.content")
    configure.scan("guillotina.registry")
    configure.scan("guillotina.auth")
    configure.scan("guillotina.json")
    configure.scan("guillotina.behaviors")
    configure.scan("guillotina.languages")
    configure.scan("guillotina.permissions")
    configure.scan("guillotina.security.security_local")
    configure.scan("guillotina.security.policy")

    if settings.get("load_catalog"):
        configure.scan("guillotina.catalog.index")
        configure.scan("guillotina.catalog.catalog")

    configure.scan("guillotina.files")
    configure.scan("guillotina.annotations")
    configure.scan("guillotina.constraintypes")
    configure.scan("guillotina.subscribers")
    configure.scan("guillotina.db.strategies")
    configure.scan("guillotina.db.storages.vacuum")
    configure.scan("guillotina.db.cache")
    configure.scan("guillotina.db.writer")
    configure.scan("guillotina.db.factory")
    configure.scan("guillotina.exc_resp")
    configure.scan("guillotina.fields")
    configure.scan("guillotina.migrations")

    # always load guillotina
    app_configurator.configure_application("guillotina")
    app_configurator.configure_all_applications()

    apply_concrete_behaviors()

    # update *after* plugins loaded
    update_app_settings(settings)

    if "logging" in app_settings:
        try:
            logging.config.dictConfig(app_settings["logging"])
        except Exception:
            app_logger.error("Could not setup logging configuration",
                             exc_info=True)

    # Make and initialize asgi app
    root.app = server_app
    server_app.root = root
    server_app.config = config
    server_app.settings = app_settings

    for k, v in _moved.items():
        # for b/w compatibility, convert these
        if k in app_settings:
            app_settings[v] = app_settings[k]
            del app_settings[k]

    optimize_settings(app_settings)

    await notify(ApplicationConfiguredEvent(server_app, loop))

    for key, dbconfig in list_or_dict_items(app_settings["databases"]):
        factory = get_utility(IDatabaseConfigurationFactory,
                              name=dbconfig["storage"])
        root[key] = await factory(key, dbconfig, loop)
        await notify(DatabaseInitializedEvent(root[key]))

    for key, file_path in list_or_dict_items(app_settings["static"]):
        path = resolve_path(file_path).resolve()
        if not path.exists():
            raise Exception("Invalid static directory {}".format(file_path))
        if path.is_dir():
            root[key] = StaticDirectory(path)
        else:
            root[key] = StaticFile(path)

    for key, file_path in list_or_dict_items(app_settings["jsapps"]):
        path = resolve_path(file_path).resolve()
        if not path.exists() or not path.is_dir():
            raise Exception("Invalid jsapps directory {}".format(file_path))
        root[key] = JavaScriptApplication(path)

    root.set_root_user(app_settings["root_user"])

    if app_settings.get("jwk") and app_settings.get("jwk").get(
            "k") and app_settings.get("jwk").get("kty"):
        key = jwk.JWK.from_json(json.dumps(app_settings.get("jwk")))
        app_settings["jwk"] = key
        # {"k":"QqzzWH1tYqQO48IDvW7VH7gvJz89Ita7G6APhV-uLMo","kty":"oct"}

    if not app_settings.get("debug") and app_settings["jwt"].get("secret"):
        # validate secret
        secret = app_settings["jwt"]["secret"]
        if secret == "secret":
            app_logger.warning(
                "You are using a very insecure secret key in production mode. "
                "It is strongly advised that you provide a better value for "
                "`jwt.secret` in your config.")
        elif not secure_passphrase(app_settings["jwt"]["secret"]):
            app_logger.warning(
                "You are using a insecure secret key in production mode. "
                "It is recommended that you provide a more complex value for "
                "`jwt.secret` in your config.")

    # Set router root
    server_app.router.set_root(root)
    server_app.on_cleanup.append(cleanup_app)

    for key, util in app_settings["load_utilities"].items():
        app_logger.info("Adding " + key + " : " + util["provides"])
        await notify(BeforeAsyncUtilityLoadedEvent(key, util))
        result = root.add_async_utility(key, util, loop=loop)
        if result is not None:
            await notify(AfterAsyncUtilityLoadedEvent(key, util, *result))

    # Load cached Schemas
    load_cached_schema()

    await notify(ApplicationInitializedEvent(server_app, loop))

    return server_app
Esempio n. 56
0
async def grantinfo(context, request):
    """ principals -> roles """
    search = request.query.get("search")
    if search is not None:
        search = search.lower()

    result = {"available_roles": [], "entries": []}

    # Inherit
    inheritMap = IInheritPermissionMap(context)
    permissions = inheritMap.get_locked_permissions()
    if len(permissions) > 0:
        blocked_permissions = permissions
        result["inherit"] = False
    else:
        result["inherit"] = True

    # Roles
    roles = local_roles()
    valid_roles = [
        role for role in roles
        if role in app_settings.get("available_roles", [])
    ]
    for role in valid_roles:
        role_obj = get_utility(IRole, name=role)
        result["available_roles"].append({
            "id": role,
            "title": role_obj.title,
            "description": role_obj.description
        })

    prinrole = IPrincipalRoleMap(context)
    settings = [
        setting for setting in prinrole.get_principals_and_roles()
        if setting[0] in valid_roles
    ]
    valid_settings = {}
    default_roles = {role: None for role in valid_roles}

    try:
        container = get_current_container()
        users = await container.async_get("users")
        groups = await container.async_get("groups")
    except (AttributeError, KeyError, ContainerNotFound):
        return None

    for data in settings:
        if data[1] not in valid_settings:
            user = await users.async_get(data[1])
            if user:
                valid_settings[data[1]] = {
                    "id": data[1],
                    "disabled": user.disabled,
                    "login": None,
                    "roles": deepcopy(default_roles),
                    "title": user.name,
                    "type": "user",
                    "origin": "dbusers",
                }
            else:
                group = await groups.async_get(data[1])
                if group:
                    valid_settings[data[1]] = {
                        "id": data[1],
                        "disabled": group.disabled,
                        "login": None,
                        "roles": deepcopy(default_roles),
                        "title": group.name,
                        "type": "group",
                        "origin": "dbusers",
                    }
                else:
                    valid_settings[data[1]] = {
                        "id": data[1],
                        "disabled": False,
                        "login": None,
                        "roles": deepcopy(default_roles),
                        "title": data[1],
                        "type": "user",
                        "origin": "system",
                    }
        valid_settings[data[1]]["roles"].update({data[0]: data[2]})

    result["entries"] = list(valid_settings.values())

    if search is not None:
        catalog = query_utility(ICatalogUtility)
        query_result = await catalog.search(container,
                                            {"type_name": ["User", "Group"]})
        for obj in query_result["items"]:
            ident = obj.get("id", "")
            if search in ident.lower() and ident not in valid_settings:
                result["entries"].append({
                    "id": ident,
                    "disabled": False,
                    "login": None,
                    "roles": deepcopy(default_roles),
                    "title": obj.get("title", ""),
                    "type": obj.get("type_name").lower(),
                })

    return result
Esempio n. 57
0
async def close_utilities(app):
    root = get_utility(IApplication, name="root")
    for key in list(root._async_utilities.keys()):
        app_logger.info("Removing " + key)
        await root.del_async_utility(key)
Esempio n. 58
0
async def close_dbs(app):
    root = get_utility(IApplication, name="root")
    for db in root:
        if IDatabase.providedBy(db[1]):
            await db[1].finalize()
Esempio n. 59
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)