-
-
Notifications
You must be signed in to change notification settings - Fork 661
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
fix(auth): UI logged-in detection for other auths #2535
Conversation
See also a related |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome to see you moving on to the Volto part, and quite fast! It's like... did you just learn Volto in a week?
Now, for the code part: I think userSession should be moved to the reducers
folder, I don't think we need the extra selectors folder. I saw that you're using them in the connect calls, that's a pattern that I didn't see in the existing Volto code. If those functions are reusable but not reducers, then you should move them to the helpers
folder.
It's quite a big PR, I'll need several looks probably to fully grasp it. Maybe we can have a call (with @sneridagh) to go through the new introduced API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but I have questions :)
Main one is regarding the workflow in mixed environments, having authenticated in Plone Classic, then going to Volto, how does Volto gets the token? It should be related with the PR in p.restapi, but I don't see it now. I will revisit it.
Introducing the selectors (and folder) is fine with me, although it will be needed to add some introductory documentation in the main docs.
Would you say it's breaking? I don't see it now, but due to the nature of the change maybe it would be worth to state it as breaking.
Tomorrow we have the Volto Team Meeting, could you attend and explain the changes? If not, maybe we can find a moment to meet and talk about it.
@@ -77,7 +82,8 @@ docs-build: | |||
.PHONY: start | |||
# Run both the back-end and the front end | |||
start: | |||
$(MAKE) -j 2 start-backend start-frontend |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I won't generalise this for training/educational purposes. So the simple approach remains the default, then have the "advanced" deployment testbed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not quite following you here. Can you clarify and LMK if there's I should do here?
@@ -0,0 +1,50 @@ | |||
# Proxy the back-end and front-end running on the local host |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough, but yet another file/folder in the root...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you suggesting a better location?
Well, I have some previous React+Redux experience coming in. Not much, primarily one green-field project, but it was just 2-3 developers, we all did everything (Flask API, UI, CI, CD, orchestration) and I was the one whose hours were fully dedicated, so it kinda ended up being a React+Redux bootcamp. But thanks! :-)
I don't think that works here. As I understand it, in Redux selectors are about abstracting what the UI needs to know from state without depending on the technical specifics of how state is interpreted to derive that knowledge. This makes it much easier to change how state is interpreted without having to touch every freaking component in the app to do so as I had to in the commit to move to selectors. IOW, they make Redux code bases more agile, maintainable, and less fragile. In this case, the I could see an argument that calling this selector
As I understand Redux, this is the pattern for using selectors with class components. If these were function components, then I'd use the Components shouldn't care about how state is interpreted, they should only care about what their inputs are as the component itself would interpret them. So in this case, the components should only take an input of the abstracted fact of whether a user is authenticated. The right place to interpret the Redux state to provide inputs to the React component is when the component is connected to the state. LMK if I've got any of that wrong or if there's a better way to achieve what I'm arguing for here.
In my experience selectors are a core Redux concept, are specifically about interpreting state, and the convention is to keep them in a
Sorry, I wasn't sure how to break this apart (aside from the minor build, local development stuff). For example, the commits that change how user session state is interpreted demonstrate the value of introducing selectors. But LMK if you have a suggestion for how to break this up more. Thanks for the feedback, @tiberiuichim! |
Volto doesn't necessarily get a token in all cases. Since a token is only necessary to authenticate to the API, it's not needed if the user's browser is already authenticated to the API buy some other means such as ZMI
Got a pointer for me as to where to add that? I'm happy to put something brief in there as a part of this PR.
It shouldn't be, but I wouldn't argue against calling it a breaking change. Probably the most "breaking" thing about it is that is't my first significant contribution and I've touched so many parts of the code base. ;-)
Alright, I'll try to stay up till 3 AM my time tonight to attend. But please forgive me if I don't make it, I've actually been less of a night owl recently. If I don't make it, I'll happily schedule something with you. Thanks, @sneridagh! |
0204d1e
to
8649248
Compare
@rpatterson oh please, you don't have to stay awake until that late! We can schedule a meeting when all can have a more sane time frame. Maybe not with all the team but with who is interested. In which TZ are you? |
Sorry, I didn't mean to "martyr" myself there. ;-) I'd actually like to try to make it tonight/tomorrow-morning. Lets see how it goes and schedule something else if I don't. FYI, I'm in San Francisco, so my time zone is |
|
From framework meeting, move to feature. |
A testbed that reproduces accessing all of the ZMI, the classic HTML plone UI, and the Volto UI under the same hostname. Originally needed to workout issues with different kinds of authentication working for all UIs. refs #131171
Use `collective.recipe.omelette` to reproduce a single directory tree of the Python packages installed in the `./api/` buildout's `instance` part. Useful for searching, browsing, or otherwise exploring all the source code involved in the application in a way that's more readable and avoids duplicates from older versions of eggs.
This repository has no `master` branch. At least according to GitHub, `main` is the default branch and it also has the most recent activity in `$ git log`.
More sensible ordering of the folder structure documentation so that the library, React, is first, the state framework, Redux, is next, followed by more project specific structure.
Refactor the logic around user session state out of the multiple components into Redux selectors. This is a step on the way to refactoring the UI user session logic to be agnostic of *how* the user is authenticated. Currently this includes 2 selectors: - detecting whether a user is currently authenticated and logged in - retrieving the authenticated users login or ID I note this project isn't using selectors prior to this. From [the Redux docs](https://redux.js.org/tutorials/fundamentals/part-2-concepts-data-flow#selectors): > Selectors are functions that know how to extract specific pieces of information from a > store state value. As an application grows bigger, this can help avoid repeating logic > as different parts of the app need to read the same data That's *exactly* what's needed here. This is particularly true for getting user data state, such as the `userId`. As such, I went ahead and introduced the usage of selectors here. Refs #134784
Seeking an action by id, for example to check for the presence of an action or to lookup the `url` property of a specific action, is a very common task. As such, transform the arrays of actions into objects of actions by action id and include that in Redux state as well. Next, I plan to use this to replace the JWT implementation-dependent check if a user is logged in. Refs #134784
Defer to the API, specifically the presence of the `login` action, to determine if a user is logged in instead of depending on the implementation detail of the UI JWT login process. Refs #134784
8649248
to
faec2ae
Compare
I believe I've previously addressed all feedback from the comments here and I just pushed some further refinement that should address all remaining feedback from the framework meeting. I have an approval and a green merge button, so I'll wait a day for anyone to tell me if I have anything more to do, otherwise I'll go ahead and merge. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've just noticed that it changes a few prop names, so this will be a breaking change. @sneridagh what's the procedure for this? Wait for the merge until an appropriate window is found?
Can you clarify the sense of breaking change that is meant here and how changing prop names is a breaking change, @tiberiuichim? |
I may be wrong, so take this with a grain of salt, but: One of the extension methods that Volto provides is customization. I think of it as a "transition API" while Volto develops a real extensibility story and I've advocated avoiding this practice. But the gist of it is that when components change their props it could potentially break things for somebody who customized either that component file or their parent that passes down props. Though that may not be the case for the files touched in this PR, you're mostly passing down props from the connect, making those modules black boxes. |
@tiberiuichim yeah the props changes, but since they are "connected" (you don't really pass them down) do they matter? @rpatterson I would wait for the corresponding release in p.restapi before merging. |
I fully agree. The holiday season is on. Both @sneridagh and I will be on holiday for three weeks soon and it is too risky to push a major release right before that. |
Ok, I'll assume someone else will merge this when it's time. I'll also do my best to pay attention to this and merge when someone tells me to if that's preferred. |
* master: (79 commits) Back to development Release 14.0.0-alpha.0 Prepare for release Remove compatibility with older configuration way based on imports (#2516) Locking support (#2594) Back to development Release 13.15.0 Prepare for release feat: add placeholder to wysiwyg widget (#2653) chore(i18n): update ita translations (#2652) Show loading indicator in listing view when content is loading (#2644) Validate touched-only `required` fields in Forms (#2642) Get SchemaWidget field factories from backend (#2651) Change the batch size of folder content (#2654) Show item title and item type when hovering over item title and item type icon in folder content view (#2649) Back to development Release 13.14.0 Prepare for release cypress: user/groups controlpanel tests (#2650) Reimplement the architecture of user/groups controlpanel (#2064) ...
@rpatterson I've just merged this and tested it in: There is a moment when the toolbar appears, then disappears. Could you take a look into it asap? The logout from the frontend is going to be necessary too, eg. if you are logged in in Zope, there is no way to remove the credentials, then the logout (from Volto) does not take place. |
This reverts commit 44a05c7.
Let's revert then, so we can look at it more closely. @avoinea also reported strange behaviours:
|
We should add a call to the @logout endpoint on logout action. |
Given Ross changes in p.restapi I think it should do more than invalidate the token but do the normal Zope and Plone logout. |
@sneridagh True. We need to also amend the |
Ooh, I like this idea, @avoinea! I've been contemplating the best way to handle Zope I'll take advantage of this comment to capture some of my thinking to date. My API JWT
The problem with this is its statelessness and thus there is no login event. From the For plain Zope, such as at the Zope root, one way to do this is with the cookie I've done some testing in the Zope instance created by the
So that seems like a bug somewhere. At any rate, if I move aside and disable the
When I disable So having walked through all that, and given that the set up bugs in the Zope root I'm mostly just babbling here and capturing my findings and thoughts, but if anyone has |
See my |
Defer to the API, specifically the presence of the
login
action, to determine if auser is logged in instead of depending on the implementation detail of the UI JWT login
process.
This change results in the Volto UI showing the user as logged in even when they've
previously logged in via the ZMI
Basic
authentication or via the classic HTML Plonelogin form. The
userId
still can't be retrieved if the user has logged in some otherway than the JWT Volto login component, but this is still a step forward.
Refs #134784
Involves some refactoring of actions and user session state handling. I also captured
some development build/setup improvements I either needed for this work or ran across
while working on this. I work hard to keep my commits atomic so it's probably best to
review commit-by-commit rather than review the whole diff. Otherwise, if this community
prefers very atomic PRs (as in approaching 1 PR per-commit), LMK and I'll break this up.