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)
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)
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 } }] } } }
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
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
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
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)
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
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
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)
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)
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)
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
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)
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)
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}"})
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
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]
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
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
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
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
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
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
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
def can_debug_amqp(context: IContainer) -> bool: security = get_security_policy() return security.check_permission("guillotina.DebugAMQP", context)
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()
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)
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)