Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get private item info as anonymous user #13

Open
pnicolli opened this issue Jun 6, 2019 · 3 comments
Open

Get private item info as anonymous user #13

pnicolli opened this issue Jun 6, 2019 · 3 comments

Comments

@pnicolli
Copy link

pnicolli commented Jun 6, 2019

I have a custom content type which has a RelationChoice field (z3c.relationfield.schema.RelationChoice) called relation.

In this content type view we need to proxy some info of the related item. Let's call this content type Proxy. I have an item of type Proxy, let's call it ProxyItem, and I chose a News Item for the relation field.

If ProxyItem is public and the related News Item is private, I can still access to the News Item fields as the anonymous user. I can see its title, description, etc, in the ProxyItem view.

@eikichi18 and I went through some debugging and found out that the code ProxyItem.relation.to_object returns the related News Item even if it's public.

This is what we tried in a pdb: (_object is the underlying function called by the to_object property)

> /Users/pieronicolli/.buildout/eggs/z3c.relationfield-0.7-py2.7.egg/z3c/relationfield/relation.py(112)_object()
-> try:
(Pdb) l
107     def _object(id):
108         if id is None:
109             return None
110         intids = component.getUtility(IIntIds)
111         import pdb;pdb.set_trace()
112  ->     try:
113             return intids.getObject(id)
114         except KeyError:
115             # XXX catching this error is not the right thing to do.
116             # instead, breaking a relation by removing an object should
117             # be caught and the relation should be adjusted that way.
(Pdb) n
> /Users/pieronicolli/.buildout/eggs/z3c.relationfield-0.7-py2.7.egg/z3c/relationfield/relation.py(113)_object()
-> return intids.getObject(id)
(Pdb) s
--Call--
> /Users/pieronicolli/.buildout/eggs/zope.intid-3.7.2-py2.7.egg/zope/intid/__init__.py(71)getObject()
-> def getObject(self, id):
(Pdb) l
 66             return list(self.refs.items())
 67     
 68         def __iter__(self):
 69             return self.refs.iterkeys()
 70     
 71  ->     def getObject(self, id):
 72             return self.refs[id]()
 73     
 74         def queryObject(self, id, default=None):
 75             r = self.refs.get(id)
 76             if r is not None:
(Pdb) n
> /Users/pieronicolli/.buildout/eggs/zope.intid-3.7.2-py2.7.egg/zope/intid/__init__.py(72)getObject()
-> return self.refs[id]()
(Pdb) s
--Call--
> /Users/pieronicolli/.buildout/eggs/five.intid-1.1.2-py2.7.egg/five/intid/keyreference.py(122)__call__()
-> def __call__(self):
(Pdb) l
117                     for item in reversed(chain):
118                         new_obj = aq_base(item).__of__(new_obj)
119                     obj = new_obj
120             return obj
121     
122  ->     def __call__(self):
123             return self.wrapped_object
124     
125         def __hash__(self):
126             return hash((self.dbname,
127                          self.object._p_oid,
(Pdb) n
> /Users/pieronicolli/.buildout/eggs/five.intid-1.1.2-py2.7.egg/five/intid/keyreference.py(123)__call__()
-> return self.wrapped_object
(Pdb) s
--Call--
> /Users/pieronicolli/.buildout/eggs/five.intid-1.1.2-py2.7.egg/five/intid/keyreference.py(98)wrapped_object()
-> @property
(Pdb) l
 93             # object. Asking the root object on the wrong db can trigger
 94             # an POSKeyError.
 95             connection = IConnection(self.object).get_connection(self.root_dbname)
 96             return connection[self.root_oid]
 97     
 98  ->     @property
 99         def wrapped_object(self):
100             if self.path is None:
101                 return self.object
102             try:
103                 obj = self.root.unrestrictedTraverse(self.path)
(Pdb) n
> /Users/pieronicolli/.buildout/eggs/five.intid-1.1.2-py2.7.egg/five/intid/keyreference.py(100)wrapped_object()
-> if self.path is None:
(Pdb) l
 95             connection = IConnection(self.object).get_connection(self.root_dbname)
 96             return connection[self.root_oid]
 97     
 98         @property
 99         def wrapped_object(self):
100  ->         if self.path is None:
101                 return self.object
102             try:
103                 obj = self.root.unrestrictedTraverse(self.path)
104             except (NotFound, AttributeError,):
105                 return self.object
(Pdb) self.path
'/Plone/news/my-news-item'
(Pdb) self.object
<NewsItem at my-news-item>

We stopped after noticing the unrestrictedTraverse call, and came here to ask if it's a wanted behavior or if it's not. In case it's not, should we propose a pull request changing that to a restrictedTraverse call? It feels like a possible breaking change.

@jensens
Copy link
Sponsor Member

jensens commented Jun 13, 2019

Good catch!

The problem is, if you do an restrictedTraverse and have a path like /root/public/private/public it would stumble about the private in the middle and would prevent access to the public one at the end, which would be wrong as well.

@pnicolli
Copy link
Author

I see. What do you think about adding a check, before returning the object, to see if the user has View permission on it?

@jensens
Copy link
Sponsor Member

jensens commented Jun 13, 2019

I have no good idea how to solve it here. The whole concept feels broken permission wise. OTHO this is so low level here, in five.initid, it feels wrong to do permission checks in here.

Probably it is the wrong place, but z3c.relationfield RelationValue should do security checking?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants