Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork9.7k
[Security] Load the user before pre/post auth checks when needed#26788
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
chalasr commentedApr 4, 2018
| Q | A |
|---|---|
| Branch? | 2.8 |
| Bug fix? | yes |
| New feature? | n/a |
| BC breaks? | no |
| Deprecations? | no |
| Tests pass? | yes |
| Fixed tickets | #26775 |
| License | MIT |
| Doc PR | n/a |
| $user =$authToken->getUser(); | ||
| if (!$userinstanceof UserInterface) { |
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.
What if the user isAnon.? It will fail
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.
No it will not.instanceof handles strings.
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.
it will call this:$user = $this->userProvider->loadUserByUsername('Anon.');, which will fail to retrieve the user and result inNULL
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.
Yea, butloadUserByUsername() will throw a UsernameNotFoundException. Should we throw a specific exception before?
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.
It will also handlenull:https://3v4l.org/Xrt8u
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.
* @return UserInterface does enforce it to me, it doesn't allow null
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.
Except that people can just doreturn null; and it won't fail.
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.
well, if they don't respect the contract of the interface, they enter unknown land. Things might break badly at any time (and the typehint error on the next call is such a failure), and the failure can even change in any Symfony patch release. We don't guarantee any backward compatibility for code not respecting the interface contract (and yes, any new API added in Symfony 4.1+ will use return types to enforce it better)
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.
While I fully agree, sadly (especially older implementations) are often based of "reverse engineered" authenticators, due to lack of better (SF2.0~2.6). Thus, I can't fully blame developers for making this "mistake".
symfony/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php
Lines 74 to 78 in9f1c017
| $user =$this->userProvider->loadUserByUsername($username); | |
| if (!$userinstanceof UserInterface) { | |
| thrownewAuthenticationServiceException('The user provider must return a UserInterface object.'); | |
| } |
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.
same check added for consistency
nicolas-grekas commentedApr 4, 2018 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
|
f40ce0f to21f6216Compare21f6216 toc318306Compare| $user =$this->userProvider->loadUserByUsername($user); | ||
| if (!$userinstanceof UserInterface) { | ||
| thrownewAuthenticationServiceException('The user provider must return a UserInterface object.'); |
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.
should we also call forget this comment 😉setToken for this one?
nicolas-grekas commentedApr 4, 2018
Thank you@chalasr. |
…needed (chalasr)This PR was merged into the 2.8 branch.Discussion----------[Security] Load the user before pre/post auth checks when needed| Q | A| ------------- | ---| Branch? | 2.8| Bug fix? | yes| New feature? | n/a| BC breaks? | no| Deprecations? | no| Tests pass? | yes| Fixed tickets |#26775| License | MIT| Doc PR | n/aCommits-------c318306 [Security] Load the user before pre/post auth checks when needed
aschempp commentedApr 11, 2018
Unfortunately, this implementation is broken as well.
The only viable solution is to only run the UserChecker if |
chalasr commentedApr 11, 2018
Right, casting to string beforehand should be enough to fix that.
No, it mustreturn an instance of UserInterface. I'll submit a patch tomorrow, thanks for reporting. |
aschempp commentedApr 12, 2018
That will not solve the problem, at least not for us (Contao CMS). For BC reasons, our current LTS version (Contao 4.4) is usinga custom Authenticator registeredin the firewall config. Our legacy user classes do not implement the It's all rather complex, but worked perfectly fine until now. Our legacy user class is stored in the token, and thanks to the Now, casting the user object to a string would not work, because the object's username would not be suitable for our user provider. I also think the whole approach is flawed. The code is essentially calling the user provideragain to get a user. It did not get one in the first place, why would it get one if you call it again? Even worse, we're cancelling the authentication if the user provider does not return a |
linaori commentedApr 12, 2018
And this is one of the reasons why the User object should be restricted as data object and be limited to the security internal behavior, never be exposed to the outside. While I agree that the current approach is not really ideal, I think that the I'm curious though, why a custom authenticator to eventually return an anonymous user? I personally think that you should not be altering the |
aschempp commentedApr 12, 2018
I totally agree Still, I think there are valid use cases for not having a Regardless of examples, I think my last paragraph was still valid. It does not make sense to try to load a useragain from the user provider. The authenticator is responsible for that, and if there is no |
linaori commentedApr 12, 2018
I agree, and I'm 100% sure that we can make Symfonynever expose the |
chalasr commentedApr 12, 2018
Point is the contract says
That means we would have a different behavior when passing a username (or object with At this stage I suggest to open a new issue to discuss about what can/should be done. |
aschempp commentedApr 13, 2018
I guess we could. It would be wonky as we're implementing |
linaori commentedApr 13, 2018
aschempp commentedApr 13, 2018
Unfortunately, there are more issues with the implementation. Our |