Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Security] Use supportsClass in addition to UnsupportedUserException #35065

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

Merged

Conversation

linaori
Copy link
Contributor

@linaori linaori commented Dec 20, 2019

Q A
Branch? 3.4+
Bug fix? yes
New feature? no
Deprecations? no
Tickets Fix #35045
License MIT
Doc PR ~

This PR fixes the issue where user providers rely on just the UnsupportedUserException from refreshUser(), causing a flow where users are wrongfully re-authenticated.

There's one issue where refreshUser() can do far more sophisticated checks on the user class, which it will never reach if the class is not supported. As far as I know it was never intended to support instances that are rejected by supportsClass(), though people could've implemented this (by accident). So the question is more if we should add a BC layer for this; for example:

try {
    $refreshedUser = $provider->refreshUser($user);
    $newToken = clone $token;
    $newToken->setUser($refreshedUser);

    if (!$provider->supportsClass($userClass)) {
        if ($this->shouldCheckSupportsClass) {
            continue;
        }
        // have to think of a proper deprecation here for 6.0
        @trigger_error('Provider %s does not support user class %s via supportsClass() while it does support it via refreshUser .. please set option X and fix %s::supportsUser() ', E_USER_DEPRECATED);
    }

This would prevent behavior from breaking but also means we can't fix this on anything less than 5.1.

@linaori
Copy link
Contributor Author

linaori commented Dec 20, 2019

One additional solution for 3.4 and higher in case we want to add the BC version, would be to log it as error regardless so that people can fix it without introducing a new feature:

try {
    $refreshedUser = $provider->refreshUser($user);
    $newToken = clone $token;
    $newToken->setUser($refreshedUser);

    if (!$provider->supportsClass($userClass)) {
        $this->logger->error('...');
    }

Both failures are unrelated to this PR as far as I can see.

1) Symfony\Component\Config\Tests\Resource\DirectoryResourceTest::testIsFreshDeleteFile

->isFresh() returns false if an existing file is removed

Failed asserting that true is false.

/home/travis/build/symfony/symfony/src/Symfony/Component/Config/Tests/Resource/DirectoryResourceTest.php:115

@chalasr
Copy link
Member

chalasr commented Dec 20, 2019

I would consider the new error log a feature :) I think we can just fix the non called supportsClass() "silently" here, and discuss about triggering on master

@chalasr chalasr added this to the 3.4 milestone Dec 20, 2019
@linaori
Copy link
Contributor Author

linaori commented Dec 20, 2019

So if I understand it correctly, the PR as-is is okay? I'm not sure what the best approach would be for 5.1 and 6.0. Ideally I'd see either supportsClass() or UnsupportedUserException disappear to reduce it to a single way of determining support, with my preference being the exception.

What about a supportsUser(UserInterface $user) instead?

Copy link
Member

@chalasr chalasr left a comment

Choose a reason for hiding this comment

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

with minor comment

@@ -168,12 +168,17 @@ protected function refreshUser(TokenInterface $token)

$userNotFoundByProvider = false;
$userDeauthenticated = false;
$userClass = \get_class($user);
Copy link
Member

Choose a reason for hiding this comment

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

not needed, opcache does a better job without it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You have some resources on that?

Copy link
Member

Choose a reason for hiding this comment

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

Sure: @nicolas-grekas 😁

Copy link
Member

Choose a reason for hiding this comment

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

you mean inlining the call instead of using a variable? I won't make a claim here, I'm fine this way :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I know that importing certain functions from the root namespace gives an optimization for these functions, never heard of it being the other way around, hence I'm curious 😄

@chalasr
Copy link
Member

chalasr commented Jan 20, 2020

What about a supportsUser(UserInterface $user) instead?

supportsClass is needed to avoid extra loadUserByUsername() calls, see e.g. RememberMeServices

@nicolas-grekas
Copy link
Member

Thank you @linaori.

nicolas-grekas added a commit that referenced this pull request Jan 21, 2020
…rException (linaori)

This PR was merged into the 3.4 branch.

Discussion
----------

[Security] Use supportsClass in addition to UnsupportedUserException

| Q             | A
| ------------- | ---
| Branch?       | 3.4+
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #35045
| License       | MIT
| Doc PR        | ~

This PR fixes the issue where user providers rely on just the UnsupportedUserException from `refreshUser()`, causing a flow where users are wrongfully re-authenticated.

There's one issue where `refreshUser()` can do far more sophisticated checks on the user class, which it will never reach if the class is not supported. As far as I know it was never intended to support instances that are rejected by `supportsClass()`, though people could've implemented this (by accident). So the question is more if we should add a BC layer for this; for example:

```php
try {
    $refreshedUser = $provider->refreshUser($user);
    $newToken = clone $token;
    $newToken->setUser($refreshedUser);

    if (!$provider->supportsClass($userClass)) {
        if ($this->shouldCheckSupportsClass) {
            continue;
        }
        // have to think of a proper deprecation here for 6.0
        @trigger_error('Provider %s does not support user class %s via supportsClass() while it does support it via refreshUser .. please set option X and fix %s::supportsUser() ', E_USER_DEPRECATED);
    }
```
This would prevent behavior from breaking but also means we can't fix this on anything less than 5.1.

Commits
-------

d3942cb Use supportsClass where possible
@nicolas-grekas nicolas-grekas merged commit d3942cb into symfony:3.4 Jan 21, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants