Why are users Anonymous on error pages?

This is normally a minor annoyance, but it's a problem if they are in the context of a folder that requires authentication to view. The error page is broken, with no proper structure or resources. It's probably easiest to explain with an example: go to https://classic.demo.plone.org, pull up the example Folder, and make it private. Now try to go to a nonexistant sub page within that folder: https://classic.demo.plone.org/en/demo/a-folder/1

I don't know the reasons behind why users at this stage are treated as anonymous users. Is that a bug or is there a security reason behind it? Is it possible to render the 404 page within the context of the site root instead of within the folder?

Eric via Plone Community wrote at 2024-2-20 20:03 +0000:

...
It's probably easiest to explain with an example: go to https://classic.demo.plone.org, pull up the example Folder, and make it private. Now try to go to a nonexistant sub page within that folder: https://classic.demo.plone.org/en/demo/a-folder/1

I don't know the reasons behind why users at this stage are treated as anonymous users.

Non-existency is detected during "traversal", authentication only
happens after a successful traversal.

Is that a bug or is there a security reason behind it?

Likely, the error page should get redesigned to be usable even
for Anonymous.
As a workaround, you can install your own error page.

Is it possible to render the 404 page within the context of the site root instead of within the folder?

If you are only interested to get a working error page for
"NotFound", you can register an "exception view" for zExceptions.NotFound.

Look at ZPublisher.WSGIPublisher._exc_view_created_response
to learn how error page and exception views are looked up
(and consequently can be changed/registered by you).

2 Likes

I thought the problem might be with viewlets. A lot of the viewlets, including the one that has all of the css links, were not getting loaded because of this condition: plone.app.viewletmanager/plone/app/viewletmanager/manager.py at 4.0.3 · plone/plone.app.viewletmanager · GitHub This makes sense, the configure.zcml for plone.app.layout.viewlets shows these all as requiring zope2.View, which we do not have in this context.

But even if I change it to zope.Public it still fails the guarded_hasattr check. I think this is because the user still doesn't have access to the context itself, even though the permission on it is 'public'.

Eric via Plone Community wrote at 2024-2-21 21:58 +0000:

...
But even if I change it to zope.Public it still fails the guarded_hasattr check. I think this is because the user still doesn't have access to the context itself, even though the permission on it is 'public'.

Do you know about "verbose-security".
This is the (Zope configuration) setting which greatly helps
with the analysis of authentication problems.

It will not help much when the Unauthorized exception is locally
handled (e.g. as for viewlet of viewlet-manager authorization
problems), but it is in general a great help for situations where
the Unauthorized arrives at the framework.
However, I am not sure whether this applies to authorization problems
encountered during rendering of exceptions views (such as
standard_error_message.

I just remember another potential work around for your problem:
the use of so called "proxy role"s.
Proxy roles specify roles which should be used instead of
the roles of the current user to execute restricted code.
Letting the error page generation use appropriate proxy roles
may solve your problem (however, I am not sure about the security
implications).

If your error page is generated by a ZMI customizable
object, you may there see a "Proxy..." tab allowing you to
specify the proxy roles.
If your error page is generated by a "view", you
can set up proxy roles in code. One way is the use
of proxy from "dm.zopepatches.security · PyPI";
but Plone comes with a similar functionality.

I have turned on verbose-security, but as you say I don't think it's that useful in this case, because it doesn't actually try to authorize during the rendering of the exception views.

The error page is the standard Plone one. I did try to wrap the __call__ here Products.CMFPlone/Products/CMFPlone/browser/exceptions.py at master · plone/Products.CMFPlone · GitHub with plone.api.env.adopt_roles(['Member']) as a proof of concept. To my surprise it still says my only role in that context is Anonymous

(Pdb) plone.api.user.get_roles(obj=self.context)
['Anonymous']

This may be a bad approach anyway, I don't know.