Beispiel #1
0
async def test_allowsingle(container_requester):
    async with container_requester as requester:
        response, status = await requester(
            "POST", "/db/guillotina/", data=json.dumps({"@type": "Item", "id": "testing"})
        )
        assert status == 201

        response, status = await requester(
            "POST",
            "/db/guillotina/@sharing",
            data=json.dumps(
                {
                    "prinperm": [
                        {
                            "principal": "group1",
                            "permission": "guillotina.AccessContent",
                            "setting": "AllowSingle",
                        }
                    ]
                }
            ),
        )

        assert status == 200

        response, status = await requester(
            "POST",
            "/db/guillotina/testing/@sharing",
            data=json.dumps(
                {
                    "prinperm": [
                        {"principal": "group2", "permission": "guillotina.AccessContent", "setting": "Allow"}
                    ]
                }
            ),
        )

        assert status == 200

        container = await utils.get_container(requester=requester)
        content = await container.async_get("testing")

        user = GuillotinaUser("user1")
        user._groups = ["group1", "group2"]

        utils.login(user=user)
        policy = get_security_policy(user)
        assert policy.check_permission("guillotina.AccessContent", container)
        assert policy.check_permission("guillotina.AccessContent", content)

        user = GuillotinaUser("user2")
        user._groups = ["group1"]

        utils.login(user=user)

        policy = get_security_policy(user)
        assert policy.check_permission("guillotina.AccessContent", container)
        assert not policy.check_permission("guillotina.AccessContent", content)
Beispiel #2
0
async def test_allowsingle(container_requester):
    async with container_requester as requester:
        response, status = await requester('POST',
                                           '/db/guillotina/',
                                           data=json.dumps({
                                               '@type': 'Item',
                                               'id': 'testing'
                                           }))
        assert status == 201

        response, status = await requester('POST',
                                           '/db/guillotina/@sharing',
                                           data=json.dumps({
                                               'prinperm': [{
                                                   'principal':
                                                   'group1',
                                                   'permission':
                                                   'guillotina.AccessContent',
                                                   'setting':
                                                   'AllowSingle'
                                               }]
                                           }))

        assert status == 200

        response, status = await requester('POST',
                                           '/db/guillotina/testing/@sharing',
                                           data=json.dumps({
                                               'prinperm': [{
                                                   'principal': 'group2',
                                                   'permission':
                                                   'guillotina.AccessContent',
                                                   'setting': 'Allow'
                                               }]
                                           }))

        assert status == 200

        container = await utils.get_container(requester=requester)
        content = await container.async_get('testing')

        user = GuillotinaUser('user1')
        user._groups = ['group1', 'group2']

        utils.login(user=user)
        policy = get_security_policy(user)
        assert policy.check_permission('guillotina.AccessContent', container)
        assert policy.check_permission('guillotina.AccessContent', content)

        user = GuillotinaUser('user2')
        user._groups = ['group1']

        utils.login(user=user)

        policy = get_security_policy(user)
        assert policy.check_permission('guillotina.AccessContent', container)
        assert not policy.check_permission('guillotina.AccessContent', content)
Beispiel #3
0
    async def __call__(self):
        user = get_authenticated_user()
        self.policy = get_security_policy(user)
        definition = copy.deepcopy(
            app_settings["swagger"]["base_configuration"])
        vhm = self.request.headers.get("X-VirtualHost-Monster")
        if vhm:
            parsed_url = urlparse(vhm)
            definition["host"] = parsed_url.netloc
            definition["schemes"] = [parsed_url.scheme]
            definition["basePath"] = parsed_url.path
        else:
            definition["host"] = self.request.host
            definition["schemes"] = [get_request_scheme(self.request)]
        if 'version' not in definition['info']:
            definition["info"]["version"] = pkg_resources.get_distribution(
                "guillotina").version

        api_defs = app_settings["api_definition"]

        path = get_full_content_path(self.context)

        for dotted_iface in api_defs.keys():
            iface = resolve_dotted_name(dotted_iface)
            if iface.providedBy(self.context):
                iface_conf = api_defs[dotted_iface]
                self.get_endpoints(iface_conf, path, definition["paths"])

        definition["definitions"] = app_settings["json_schema_definitions"]
        return definition
async def build_security_query(container):
    # The users who has plone.AccessContent permission by prinperm
    # The roles who has plone.AccessContent permission by roleperm
    users = []
    roles = []
    user = get_authenticated_user()
    policy = get_security_policy(user)

    users.append(user.id)
    users.extend(user.groups)

    roles_dict = policy.global_principal_roles(user.id, user.groups)
    roles.extend([key for key, value in roles_dict.items() if value])

    # We got all users and roles
    # users: users and groups

    should_list = [{"match": {"access_roles": x}} for x in roles]
    should_list.extend([{"match": {"access_users": x}} for x in users])

    return {
        "query": {
            "bool": {
                "filter": [{
                    "bool": {
                        "should": should_list,
                        "minimum_should_match": 1
                    }
                }]
            }
        }
    }
Beispiel #5
0
async def addable_types(context, request):
    result = []
    constrains = ICMSConstrainTypes(context, None)

    policy = get_security_policy()

    for id, factory in FACTORY_CACHE.items():
        add = True
        if constrains is not None:
            if not constrains.is_type_allowed(id):
                add = False

        if factory.add_permission:
            if factory.add_permission in PERMISSIONS_CACHE:
                permission = PERMISSIONS_CACHE[factory.add_permission]
            else:
                permission = query_utility(IPermission, name=factory.add_permission)
                PERMISSIONS_CACHE[factory.add_permission] = permission

            if permission is not None and not policy.check_permission(permission.id, context):
                add = False

        if add:
            result.append(id)
    return result
Beispiel #6
0
    def get_default_where_clauses(self,
                                  container: IContainer) -> typing.List[str]:
        users = []
        roles = []
        principal = get_authenticated_user()
        if principal is None:
            # assume anonymous then
            principal = AnonymousUser()
        policy = get_security_policy(principal)

        users.append(principal.id)
        users.extend(principal.groups)
        roles_dict = policy.global_principal_roles(principal.id,
                                                   principal.groups)
        roles.extend([key for key, value in roles_dict.items() if value])

        clauses = [
            "json->'access_users' ?| array['{}']".format("','".join(
                [sqlq(u) for u in users])),
            "json->'access_roles' ?| array['{}']".format("','".join(
                [sqlq(r) for r in roles])),
        ]
        sql_wheres = ["({})".format(" OR ".join(clauses))]
        sql_wheres.append(
            f"""json->>'container_id' = '{sqlq(container.id)}'""")
        sql_wheres.append("""type != 'Container'""")
        sql_wheres.append(f"""parent_id != '{sqlq(TRASHED_ID)}'""")
        return sql_wheres
Beispiel #7
0
async def get_all_types(context, request):
    result = []
    base_url = IAbsoluteURL(context, request)()
    constrains = ICMSConstrainTypes(context, None)

    policy = get_security_policy()

    for id, factory in FACTORY_CACHE.items():
        add = True
        if constrains is not None:
            if not constrains.is_type_allowed(id):
                add = False

        if factory.add_permission:
            if factory.add_permission in PERMISSIONS_CACHE:
                permission = PERMISSIONS_CACHE[factory.add_permission]
            else:
                permission = query_utility(IPermission, name=factory.add_permission)
                PERMISSIONS_CACHE[factory.add_permission] = permission

            if permission is not None and not policy.check_permission(
                permission.id, context
            ):
                add = False
        if add:
            result.append(
                {"@id": base_url + "/@types/" + id, "addable": True, "title": id}
            )
    return result
Beispiel #8
0
async def delete_comment(context, request):
    comment_id = request.matchdict["comment_id"]
    bhr = ICMSBehavior(context)
    if not bhr.allow_discussion:
        raise HTTPUnauthorized(content={"text": "Not available option"})
    await bhr.load()

    if comment_id not in bhr.comments:
        raise ErrorResponse("InvalidComment",
                            "This comment does not exist",
                            status=412)

    user_id = get_authenticated_user_id()
    comment = bhr.comments[comment_id]

    # TODO: We need ?
    policy = get_security_policy()
    if user_id != comment["author_username"] or not policy.check_permission(
            "guillotina.DeleteAllComments", context):
        raise HTTPUnauthorized(
            content={"text": "Not the author or permission"})

    list_to_delete = [comment_id]
    delete_from_list(bhr.comments, list_to_delete)
    for comment in list_to_delete:
        del bhr.comments[comment]

    bhr.register()

    return Response(status=204)
Beispiel #9
0
async def test_inherit(container_requester):
    async with container_requester as requester:
        response, status = await requester(
            "POST", "/db/guillotina/", data=json.dumps({"@type": "Item", "id": "testing"})
        )
        assert status == 201

        response, status = await requester(
            "POST",
            "/db/guillotina/@sharing",
            data=json.dumps(
                {"prinrole": [{"principal": "user1", "role": "guillotina.Reader", "setting": "Allow"}]}
            ),
        )

        assert status == 200

        response, status = await requester(
            "POST",
            "/db/guillotina/testing/@sharing",
            data=json.dumps({"perminhe": [{"permission": "guillotina.ViewContent", "setting": "Deny"}]}),
        )
        assert status == 200

        response, status = await requester("GET", "/db/guillotina/testing/@all_permissions")
        assert status == 200

        container = await utils.get_container(requester=requester)
        content = await container.async_get("testing")

        user = GuillotinaUser("user1")

        utils.login(user=user)

        policy = get_security_policy()
        assert policy.check_permission("guillotina.ViewContent", container)
        assert not policy.check_permission("guillotina.ViewContent", content)

        response, status = await requester("GET", "/db/guillotina/testing")
        assert status == 401

        response, status = await requester(
            "POST",
            "/db/guillotina/testing/@sharing",
            data=json.dumps(
                {
                    "roleperm": [
                        {
                            "permission": "guillotina.ViewContent",
                            "role": "guillotina.Manager",
                            "setting": "Allow",
                        }
                    ]
                }
            ),
        )
        assert status == 200

        response, status = await requester("GET", "/db/guillotina/testing")
        assert status == 200
Beispiel #10
0
    async def __call__(self, include=None, omit=None):
        include = include or []
        omit = omit or []
        result = await super(SerializeFolderToJson,
                             self).__call__(include=include, omit=omit)

        security = get_security_policy()
        length = await self.context.async_len()

        fullobjects = self.request.query.get("fullobjects",
                                             False) in (None, "", "true")

        if (length > MAX_ALLOWED or length == 0) and not fullobjects:
            result["items"] = []
        else:
            result["items"] = []
            async for ident, member in self.context.async_items(
                    suppress_events=True):
                if not ident.startswith("_") and bool(
                        security.check_permission("guillotina.AccessContent",
                                                  member)):
                    if fullobjects:
                        result["items"].append(await get_multi_adapter(
                            (member, self.request), IResourceSerializeToJson)
                                               ())
                    else:
                        result["items"].append(await get_multi_adapter(
                            (member, self.request),
                            IResourceSerializeToJsonSummary)())
        result["length"] = length

        return result
Beispiel #11
0
def set_authenticated_user(user):
    if user is not None and not isinstance(user, AnonymousUser):
        policy = get_security_policy(user)
        policy.invalidate_cache()
        if hasattr(user,
                   "roles") and "guillotina.Authenticated" not in user.roles:
            user.roles["guillotina.Authenticated"] = 1
    task_vars.authenticated_user.set(user)
Beispiel #12
0
def set_authenticated_user(user):
    if user is not None:
        policy = get_security_policy(user)
        policy.invalidate_cache()
        if hasattr(user,
                   'roles') and 'guillotina.Authenticated' not in user.roles:
            user.roles['guillotina.Authenticated'] = 1
    task_vars.authenticated_user.set(user)
Beispiel #13
0
async def test_deny_inherit_accesscontent(container_requester):
    async with container_requester as requester:
        response, status = await requester(
            "POST",
            "/db/guillotina/@sharing",
            data=json.dumps({
                "prinperm": [{
                    "principal": "Anonymous User",
                    "permission": "guillotina.AccessContent",
                    "setting": "Allow",
                }]
            }),
        )
        assert status == 200

        # The owner of item 'testing' is 'root'
        response, status = await requester(
            "POST",
            "/db/guillotina/",
            data=json.dumps({
                "@type": "Item",
                "id": "testing"
            }),
        )
        assert status == 201

        # Only the owner of the object can do AccessContent
        response, status = await requester(
            "POST",
            "/db/guillotina/testing/@sharing",
            data=json.dumps({
                "perminhe": [{
                    "permission": "guillotina.AccessContent",
                    "setting": "Deny"
                }],
                "roleperm": [{
                    "permission": "guillotina.AccessContent",
                    "role": "guillotina.Owner",
                    "setting": "Allow",
                }],
            }),
        )
        assert status == 200

        response, status = await requester(
            "GET", "/db/guillotina/testing/@all_permissions")
        assert status == 200

        container = await utils.get_container(requester=requester)
        content = await container.async_get("testing")

        policy = get_security_policy()
        assert get_authenticated_user() is None  # Anonymous

        # Anonymous user has access to container...
        assert policy.check_permission("guillotina.AccessContent", container)
        # ...but doesn't has access to the item 'testing'
        assert not policy.check_permission("guillotina.AccessContent", content)
Beispiel #14
0
async def create_content_in_container(
    parent: Folder, type_: str, id_: str, request: IRequest = None, check_security=True, **kw
) -> Resource:
    """Utility to create a content.

    This method is the one to use to create content.
    `id_` can be None

    :param parent: where to create content inside of
    :param type_: content type to create
    :param id_: id to give content in parent object
    :param request: <optional>
    :param check_security: be able to disable security checks
    """
    factory = get_cached_factory(type_)

    if check_security and factory.add_permission:
        if factory.add_permission in PERMISSIONS_CACHE:
            permission = PERMISSIONS_CACHE[factory.add_permission]
        else:
            permission = query_utility(IPermission, name=factory.add_permission)
            PERMISSIONS_CACHE[factory.add_permission] = permission

        if permission is not None:
            policy = get_security_policy()
            if not policy.check_permission(permission.id, parent):
                raise NoPermissionToAdd(str(parent), type_)

    constrains = IConstrainTypes(parent, None)
    if constrains is not None:
        if not constrains.is_type_allowed(type_):
            raise NotAllowedContentType(str(parent), type_)

    # We create the object with at least the ID
    obj = factory(id=id_, parent=parent)
    for key, value in kw.items():
        if key == "id":
            # the factory sets id
            continue
        setattr(obj, key, value)

    txn: Optional[ITransaction]
    if hasattr(parent, "_get_transaction"):
        txn = parent._get_transaction()
    else:
        txn = cast(Optional[ITransaction], getattr(parent, "__txn__", None) or get_transaction())
    if txn is None or not txn.storage.supports_unique_constraints:
        # need to manually check unique constraints
        if await parent.async_contains(obj.id):
            raise ConflictIdOnContainer(f"Duplicate ID: {parent} -> {obj.id}")

    obj.__new_marker__ = True

    await notify(BeforeObjectAddedEvent(obj, parent, id_))

    await parent.async_set(obj.id, obj)
    return obj
Beispiel #15
0
async def can_i_do(context, request):
    if "permission" not in request.query and "permissions" not in request.query:
        raise PreconditionFailed(context, "No permission param")
    policy = get_security_policy()
    if "permissions" in request.query:
        results = {}
        for perm in request.query["permissions"].split(","):
            results[perm] = policy.check_permission(perm, context)
        return results
    else:
        return policy.check_permission(request.query["permission"], context)
Beispiel #16
0
async def can_i_do(context, request):
    if 'permission' not in request.query and 'permissions' not in request.query:
        raise PreconditionFailed(context, 'No permission param')
    policy = get_security_policy()
    if 'permissions' in request.query:
        results = {}
        for perm in request.query['permissions'].split(','):
            results[perm] = policy.check_permission(perm, context)
        return results
    else:
        return policy.check_permission(request.query['permission'], context)
Beispiel #17
0
async def resolve_uid(context, request):
    uid = request.matchdict["uid"]
    try:
        ob = await get_object_by_uid(uid)
    except KeyError:
        return HTTPNotFound(content={"reason": f"Could not find uid: {uid}"})
    policy = get_security_policy()
    if policy.check_permission("guillotina.AccessContent", ob):
        return HTTPMovedPermanently(get_object_url(ob, request))
    else:
        # if a user doesn't have access to it, they shouldn't know anything about it
        return HTTPNotFound(content={"reason": f"Could not find uid: {uid}"})
Beispiel #18
0
        async def available_actions(self, request):
            policy = get_security_policy()
            for action_name, action in self.actions.items():
                add = False
                if "check_permission" in action and policy.check_permission(
                        action["check_permission"], self.context):
                    add = True
                elif "check_permission" not in action:
                    add = True

                if add:
                    yield action_name, action
Beispiel #19
0
    def check_permission(self, permission_name):
        if permission_name is None:
            return True

        if permission_name not in self.permission_cache:
            permission = query_utility(IPermission, name=permission_name)
            if permission is None:
                self.permission_cache[permission_name] = True
            else:
                security = get_security_policy()
                self.permission_cache[permission_name] = bool(
                    security.check_permission(permission.id, self.context))
        return self.permission_cache[permission_name]
Beispiel #20
0
    async def __call__(self):
        result = {
            'databases': [],
            'static_file': [],
            'static_directory': [],
            '@type': 'Application'
        }
        allowed = get_security_policy().check_permission(
            'guillotina.GetDatabases', self.application)

        for x in self.application._items.keys():
            if IDatabase.providedBy(self.application._items[x]) and allowed:
                result['databases'].append(x)
            if IStaticFile.providedBy(self.application._items[x]):
                result['static_file'].append(x)
            if IStaticDirectory.providedBy(self.application._items[x]):
                result['static_directory'].append(x)
        return result
Beispiel #21
0
    async def __call__(self):
        result = {
            "databases": [],
            "static_file": [],
            "static_directory": [],
            "@type": "Application"
        }
        allowed = get_security_policy().check_permission(
            "guillotina.GetDatabases", self.application)

        for x in self.application._items.keys():
            if IDatabase.providedBy(self.application._items[x]) and allowed:
                result["databases"].append(x)
            if IStaticFile.providedBy(self.application._items[x]):
                result["static_file"].append(x)
            if IStaticDirectory.providedBy(self.application._items[x]):
                result["static_directory"].append(x)
        return result
Beispiel #22
0
        async def do_action(self, action, comments):
            available_actions = self.actions
            if action not in available_actions:
                raise HTTPPreconditionFailed(
                    content={"reason": "Unavailable action"})

            action_def = available_actions[action]
            policy = get_security_policy()
            if "check_permission" in action_def and not policy.check_permission(
                    action_def["check_permission"], self.context):
                raise HTTPUnauthorized()

            # Change permission
            new_state = action_def["to"]

            if "set_permission" in self.states[new_state]:
                await apply_sharing(self.context,
                                    self.states[new_state]["set_permission"])

            # Write history
            user = get_authenticated_user_id()
            history = {
                "actor": user,
                "comments": comments,
                "time": datetime.datetime.now(),
                "title": action_def["title"],
                "type": "workflow",
                "data": {
                    "action": action,
                    "review_state": new_state
                },
            }

            workflow_behavior = IWorkflowBehavior(self.context)
            workflow_behavior.review_state = new_state

            workflow_behavior.history.append(history)
            workflow_behavior.register()

            await notify(
                WorkflowChangedEvent(self.context, self, action, comments))
            return history
Beispiel #23
0
        async def do_action(self, request, action, comments):
            available_actions = self.actions
            if action not in available_actions:
                raise KeyError('Unavailable action')

            action_def = available_actions[action]
            policy = get_security_policy()
            if 'check_permission' in action_def and not policy.check_permission(
                    action_def['check_permission'], self.context):
                raise HTTPUnauthorized()

            # Change permission
            new_state = action_def['to']

            if 'set_permission' in self.states[new_state]:
                await apply_sharing(self.context,
                                    self.states[new_state]['set_permission'])

            # Write history
            user = get_authenticated_user_id()
            history = {
                'actor': user,
                'comments': comments,
                'time': datetime.datetime.now(),
                'title': action_def['title'],
                'type': 'workflow',
                'data': {
                    'action': action,
                    'review_state': new_state,
                }
            }

            cms_behavior = ICMSBehavior(self.context)
            await cms_behavior.load()
            cms_behavior.review_state = new_state

            cms_behavior.history.append(history)
            cms_behavior.register()

            await notify(
                WorkflowChangedEvent(self.context, self, action, comments))
            return history
Beispiel #24
0
async def _iter_copyable_content(context, request):
    policy = get_security_policy()
    data = await request.json()
    if 'source' not in data:
        raise HTTPPreconditionFailed(content={'reason': 'No source'})

    source = data['source']
    if not isinstance(source, list):
        source = [source]

    container = find_container(context)
    container_url = get_object_url(container)
    for item in source:
        if item.startswith(container_url):
            path = item[len(container_url):]
            ob = await navigate_to(container, path.strip('/'))
            if ob is None:
                raise HTTPPreconditionFailed(content={
                    'reason': 'Could not find content',
                    'source': item
                })
        elif '/' in item:
            ob = await navigate_to(container, item.strip('/'))
            if ob is None:
                raise HTTPPreconditionFailed(content={
                    'reason': 'Could not find content',
                    'source': item
                })
        else:
            try:
                ob = await get_object_by_uid(item)
            except KeyError:
                raise HTTPPreconditionFailed(content={
                    'reason': 'Could not find content',
                    'source': item
                })
        if not policy.check_permission('guillotina.DuplicateContent', ob):
            raise HTTPPreconditionFailed(content={
                'reason': 'Invalid permission',
                'source': item
            })
        yield ob
Beispiel #25
0
    async def __call__(self):
        user = get_authenticated_user()
        self.policy = get_security_policy(user)
        definition = copy.deepcopy(
            app_settings["swagger"]["base_configuration"])
        vhm = self.request.headers.get("X-VirtualHost-Monster")

        if not app_settings["swagger"].get("base_url"):
            if vhm:
                parsed_url = urlparse(vhm)
                host = parsed_url.netloc
                scheme = parsed_url.scheme
                base_path = parsed_url.path
            else:
                host = self.request.host
                scheme = get_request_scheme(self.request)
                base_path = ""
            url = os.path.join(f"{scheme}://{host}", base_path)
        else:
            url = app_settings["swagger"]["base_url"]

        definition["servers"][0]["url"] = url

        if "version" not in definition["info"]:
            definition["info"]["version"] = pkg_resources.get_distribution(
                "guillotina").version

        api_defs = app_settings["api_definition"]

        path = get_full_content_path(self.context)

        for dotted_iface in api_defs.keys():
            iface = resolve_dotted_name(dotted_iface)
            if iface.providedBy(self.context):
                iface_conf = api_defs[dotted_iface]
                self.get_endpoints(iface_conf, path, definition["paths"])

        definition["components"]["schemas"] = app_settings[
            "json_schema_definitions"]
        return definition
Beispiel #26
0
async def test_allowsingle2(container_requester):
    async with container_requester as requester:
        response, status = await requester("POST",
                                           "/db/guillotina/",
                                           data=json.dumps({
                                               "@type": "Folder",
                                               "id": "testing"
                                           }))
        assert status == 201

        response, status = await requester("POST",
                                           "/db/guillotina/testing/",
                                           data=json.dumps({
                                               "@type": "Item",
                                               "id": "test1"
                                           }))
        assert status == 201

        response, status = await requester("POST",
                                           "/db/guillotina/testing/",
                                           data=json.dumps({
                                               "@type": "Item",
                                               "id": "test2"
                                           }))
        assert status == 201

        response, status = await requester(
            "POST",
            "/db/guillotina/@sharing",
            data=json.dumps({
                "prinperm": [{
                    "principal": "group1",
                    "permission": "guillotina.AccessContent",
                    "setting": "AllowSingle",
                }]
            }),
        )

        assert status == 200

        response, status = await requester(
            "POST",
            "/db/guillotina/testing/@sharing",
            data=json.dumps({
                "prinperm": [
                    {
                        "principal": "group2",
                        "permission": "guillotina.AccessContent",
                        "setting": "Allow"
                    },
                    {
                        "principal": "group1",
                        "permission": "guillotina.ViewContent",
                        "setting": "AllowSingle",
                    },
                ]
            }),
        )

        assert status == 200

        response, status = await requester(
            "POST",
            "/db/guillotina/testing/test1/@sharing",
            data=json.dumps({
                "prinperm": [{
                    "principal": "group3",
                    "permission": "guillotina.ViewContent",
                    "setting": "Allow"
                }]
            }),
        )

        assert status == 200

        response, status = await requester(
            "POST",
            "/db/guillotina/testing/test2/@sharing",
            data=json.dumps({
                "prinrole": [{
                    "principal": "group2",
                    "role": "guillotina.Reader",
                    "setting": "Allow"
                }],
                "roleperm": [{
                    "role": "guillotina.Reader",
                    "permission": "guillotina.ViewContent",
                    "setting": "Allow",
                }],
            }),
        )

        assert status == 200

        container = await utils.get_container(requester=requester)
        content = await container.async_get("testing")

        user = GuillotinaUser("user1")
        user._groups = ["group2", "group1"]

        utils.login(user=user)

        policy = get_security_policy()
        assert policy.check_permission("guillotina.AccessContent", container)
        assert policy.check_permission("guillotina.AccessContent", content)

        user = GuillotinaUser("user2")
        user._groups = ["group1"]

        utils.login(user=user)

        policy = get_security_policy(user)
        assert policy.check_permission("guillotina.AccessContent", container)
        assert not policy.check_permission("guillotina.AccessContent", content)

        user = GuillotinaUser("user3")
        user._groups = ["group1", "group2", "group3"]
        user._roles = {"testing.Role1": Allow}

        utils.login(user=user)
        test1 = await content.async_get("test1")
        test2 = await content.async_get("test2")

        policy = get_security_policy(user)
        assert policy.check_permission("guillotina.ViewContent", test1)
        assert policy.check_permission("guillotina.ViewContent", test2)

        roles = get_roles_principal(test2)
        assert "guillotina.Reader" in roles
        assert "guillotina.Anonymous" in roles
        assert "guillotina.Authenticated" in roles
        assert "testing.Role1" in roles
Beispiel #27
0
def can_debug_amqp(context: IContainer) -> bool:
    security = get_security_policy()
    return security.check_permission("guillotina.DebugAMQP", context)
Beispiel #28
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_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()
Beispiel #29
0
async def move(
    context: IResource,
    destination: Optional[Union[IResource, str]] = None,
    new_id: Optional[str] = None,
    check_permission: bool = True,
) -> None:
    if destination is None:
        destination_ob = context.__parent__
    else:
        if isinstance(destination, str):
            destination_ob = None
            if destination.startswith("/"):
                container = task_vars.container.get()
                if container is not None:
                    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")
    if destination_ob.__uuid__ == context.__uuid__:
        raise PreconditionFailed(context, "You can not move object to itself")
    if destination_ob.__uuid__ == context.__parent__.__uuid__ and new_id == context.id:
        raise PreconditionFailed(context, "Object already belongs to this parent with same id")

    txn = get_transaction()
    if txn is not None:
        cache_keys = txn._cache.get_cache_keys(context, "deleted")

    old_id = context.id
    if new_id is None:
        new_id = context.id
    else:
        id_checker = get_adapter(context, IIDChecker)
        if not isinstance(new_id, str) or not await id_checker(new_id, context.type_name):
            raise PreconditionFailed(new_id, "Invalid id")

    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 await destination_ob.async_contains(new_id):
        raise HTTPConflict(content={"reason": f'Destination already has object with the id "{new_id}"'})

    original_parent = context.__parent__

    await notify(
        BeforeObjectMovedEvent(
            context,
            original_parent,
            old_id,
            destination_ob,
            new_id,
            payload={"id": new_id, "destination": destination},
        )
    )

    if new_id != old_id:
        context.id = context.__name__ = new_id
    context.__parent__ = destination_ob
    context.register()

    await notify(
        ObjectMovedEvent(
            context,
            original_parent,
            old_id,
            destination_ob,
            new_id,
            payload={"id": new_id, "destination": destination},
        )
    )

    if txn is not None:
        cache_keys += txn._cache.get_cache_keys(context, "added")
        await txn._cache.delete_all(cache_keys)
Beispiel #30
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)