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

Move plone protect to plone layout #125

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

cihanandac
Copy link

@cihanandac cihanandac commented Feb 11, 2025

This PR moves the plone.protect.confirm.pt template to plone.app.layout.viewlets

@mister-roboto
Copy link

@cihanandac thanks for creating this Pull Request and helping to improve Plone!

TL;DR: Finish pushing changes, pass all other checks, then paste a comment:

@jenkins-plone-org please run jobs

To ensure that these changes do not break other parts of Plone, the Plone test suite matrix needs to pass, but it takes 30-60 min. Other CI checks are usually much faster and the Plone Jenkins resources are limited, so when done pushing changes and all other checks pass either start all Jenkins PR jobs yourself, or simply add the comment above in this PR to start all the jobs automatically.

Happy hacking!

@petschki
Copy link
Member

petschki commented Feb 11, 2025

Suggestion: this template is not a viewlet. Its the confirmation browser view. So I would not move it to plone.app.layout.viewlets but to a new module plone.app.layout.views

@cihanandac cihanandac force-pushed the 3953-move-plone-protect-to-plone-layout branch from 97efa16 to 822bb17 Compare February 11, 2025 13:44
@cihanandac
Copy link
Author

Suggestion: this template is not a viewlet. Its the confirmation browser view. So I would not move it to plone.app.layout.viewlets but to a new module plone.app.layout.views

Thanks @petschki for the suggestion. I have made changes to fix this.

@cihanandac cihanandac force-pushed the 3953-move-plone-protect-to-plone-layout branch 6 times, most recently from ac641df to c25a99e Compare February 14, 2025 12:46
@cihanandac cihanandac requested a review from ale-rt February 19, 2025 12:48
template="confirm.pt"
permission="zope2.View"
/>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am pretty sure the confirm view should stay in this package because we have code that mentions it:

resp.redirect(
"{}/@@confirm-action?{}".format(
self.site.absolute_url(), urlencode(data)
)
)

Let me think about that.

CC @plone/classicui-team

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a test, I have overwritten the _check method in auto.py to always redirect to @@confirm-action:

    def _check(self):
        if "confirm_action" not in self.request.URL:
            print("Overriding _check to always redirect to confirm-action.")
            print(f"original_url = {self.request.URL}")
            resp = self.request.response
            data = self.request.form.copy()
            data["original_url"] = self.request.URL
            resp.redirect(
                "{}/@@confirm-action?{}".format(
                    self.site.absolute_url(), urlencode(data)
                )
            )
            return False

This is basically the same code as further on in this method, we just execute this always, to see what happens.

Now start Volto, go to localhost:3000, and you get redirected to http://localhost:3000/@@confirm-action. This page gives a 403 Forbidden exception. This is raised by this line. The reason is that the original_url is http://localhost:3000/@site or similar. So you get a traceback in the logs because the url is not in the portal:

Forbidden: http://localhost:3000/@@confirm-action
Traceback (innermost last):
  Module ZPublisher.WSGIPublisher, line 181, in transaction_pubevents
  Module ZPublisher.WSGIPublisher, line 390, in publish_module
  Module ZPublisher.WSGIPublisher, line 284, in publish
  Module ZPublisher.mapply, line 98, in mapply
  Module ZPublisher.WSGIPublisher, line 68, in call_object
  Module plone.protect.views, line 14, in __call__
zExceptions.Forbidden: url not in portal:

This might work better on production, as the url may be fine there. But even if I comment out the line that raises Forbidden, I get a 500 server error, though nothing is visible in the logs.

In other words: redirecting to the confirm-action view seems useless in Volto, as the page simply does not work.

@davisagli Can you confirm this conclusion?

Would it make sense to somehow disable plone.protect completely for REST API calls? More or less this already seems the intention, as a lot of plone.restapi services have this line:

alsoProvides(self.request, plone.protect.interfaces.IDisableCSRFProtection)

So maybe plone.protect can be treated as Classic UI only, although it probably needs to remain a dependency of Products.CMFPlone. Note that it also helps protect the ZMI.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An interesting thing would be raising a CSRFExceptionOrNameItLikeYouPrefer exception instead of redirecting to a view.
Then the confirm-action page would rather be the index.html view for that custom exception:

See: https://github.com/plone/Products.CMFPlone/blob/6e2b2f55fc251a0e68b5ba65c09de6be867a9d39/Products/CMFPlone/browser/configure.zcml#L250-L257

I have no idea if that could even work, but sounds really sane to me.
Products.CMFPlone will raise a normal error page,
Classic UI -> will show the "index.html" with the form to confirm the action.
Volto -> Whatever

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mauritsvanrees You're right, it doesn't make sense to redirect to the confirmation in plone.restapi. But I also don't want to remove the check entirely; it's useful for finding unexpected write-on-reads. I would suggest not doing the redirect if the request only has application/json in the Accept header.

@ale-rt Using exception views is a nice idea, but the check happens in the transform chain and runs on both PubBeforeCommit and PubBeforeAbort events in the publisher. We can raise an exception during PubBeforeCommit and the publisher will look up the exception view, but if we raise an exception during PubBeforeAbort it is too late. https://github.com/zopefoundation/Zope/blob/master/src/ZPublisher/WSGIPublisher.py#L233

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ale-rt Using exception views is a nice idea, but the check happens in the transform chain and runs on both PubBeforeCommit and PubBeforeAbort events in the publisher. We can raise an exception during PubBeforeCommit and the publisher will look up the exception view, but if we raise an exception during PubBeforeAbort it is too late. https://github.com/zopefoundation/Zope/blob/master/src/ZPublisher/WSGIPublisher.py#L233

Ouch! Bummer :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mauritsvanrees So maybe plone.protect can be treated as Classic UI only, although it probably needs to remain a dependency of Products.CMFPlone. Note that it also helps protect the ZMI.

Devils advocate question: If this is the case, why then move the templates to plone.app.layout?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devils advocate question: If this is the case, why then move the templates to plone.app.layout?

Reading David's answer, it seems plone.protect is still useful for Volto/RestApi as it prevents write-on-read. The problem is then only that the error message you get (the confirmation page) does not get through to the Volto frontend. So for application/json requests, we could return a json error response. And then Volto should somehow handle this.

Since on the ClassicUI side only one page template is involved, it could be fine to keep that here. It is not a template that anyone is likely to want to customize.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, the best solution is to keep a simple template for covering whoever uses this package without classic UI, and then have a template targeted for ClassicUI in the frontend.
I am waiting for the pt to land in plone.app.layout to port there some markup improvements from a customer project:
image
(hoping that a good designer will make it less fleshy 🤣 )

@cihanandac cihanandac self-assigned this Mar 9, 2025
@cihanandac cihanandac force-pushed the 3953-move-plone-protect-to-plone-layout branch from c25a99e to 6854e3e Compare March 9, 2025 21:40
@cihanandac cihanandac requested a review from gforcada March 10, 2025 00:06
Comment on lines +7 to +17
import warnings


warnings.warn(
"You are using the base ConfirmView view in plone.protect,"
" for classic UI, override the ConfirmView from plone.app.layout"
" by subclassing your BrowserLayer of"
" plone.app.layout.interfaces.IPloneAppLayoutLayer.",
DeprecationWarning,
)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO these tests should stay

</metal:content-core>
</metal:content-core>

</form>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the dependency from the main template is super good.

If I check of the view renders, I see something like this:

image

It would be cool to have something a bit better.
At least I would keep the title and the description that we had before.

Top it would be to match the style of the Zope views

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

Successfully merging this pull request may close these issues.

7 participants