Skip to content

Throw access denied if CurrentUser cannot be resolved instead of a 500 #45761

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
merged 0 commits into from
Mar 17, 2022

Conversation

Seldaek
Copy link
Member

@Seldaek Seldaek commented Mar 16, 2022

Q A
Branch? 6.1
Bug fix? no
New feature? yes
Deprecations? no
Tickets Fix #45257
License MIT
Doc PR symfony/symfony-docs#...

When using #[CurrentUser] User $user in my controller I do expect to get that, and if the user is not logged in clearly I am expecting a logged in user here so throwing an AccessDeniedException for me would be super convenient.

Right now it simply stops resolving that param, and we end up with a 500 for example:

[2022-03-16T06:33:37.867185+00:00] request.CRITICAL: Uncaught PHP Exception Symfony\Component\DependencyInjection\Exception\RuntimeException: "Cannot autowire argument $loggedUser of "App\Controller\UserController::fooAction()": it references class "App\Entity\User" but no such service exists."

Yes it's a failure of my firewall config if you will, but on the other hand I don't see the point in having to list every URL that needs a user in the firewall, which is a very un-DRY and error prone process, if it can be done for me in this way.

I would personally consider this a bugfix and submit the PR against 5.4, but I thought I'd start the discussion with a PR for 6.1 :)

@jvasseur
Copy link
Contributor

Well if think removing a 500 could easily be considered an non-breaking change.

We could even go further and throw an access denied exception if the current user class doesn't extends the argument type. This would allow to do thing like limiting access to admin by sub-classing the user class for example.

This is actually one of the solution I proposed to fix https://github.com/sensiolabs/SensioFrameworkExtraBundle/issues/574 so I'm in favor of doing this change.

@chalasr
Copy link
Member

chalasr commented Mar 16, 2022

This would fix #45257.

While I agree that the current error is bad from a DX pov, I'm wondering if we want the argument resolver to know about authorization. I mean, as you said, it's mostly a developer error.

Assuming we go this way, wouldn't the access denied error be cryptic as well in case you just forgot to make that parameter nullable? Maybe that could be fixed by a meaningful exception message?

@Seldaek
Copy link
Member Author

Seldaek commented Mar 16, 2022

Yeah I was not sure about adding a message to the exception, I guess by default it is hidden from users so it is only for devs right? If so I'll add a message to try and clarify why the AccessDenied occurred. But IMO while it may confuse some, it is still clearer than this autowiring exception which requires you to know quite a bit about symfony internals to make sense of it.

@Seldaek
Copy link
Member Author

Seldaek commented Mar 16, 2022

@chalasr so do you see this as bugfix too? Should I rebase to 4.4 and try to add some tests?

@chalasr
Copy link
Member

chalasr commented Mar 16, 2022

I guess by default it is hidden from users so it is only for devs right?

Yes, all good.

Honestly I tend to think this is more a feature as it was not intended to work like this originally, but I agree the current error is really problematic and we should fix it.
Please go ahead with the rebase and the tests, switching back to 6.1 should not be hard for us if others disagree with merging this as a bugfix.

@fabpot
Copy link
Member

fabpot commented Mar 16, 2022

I understand the discussion, but per our merging strategy, this is new behavior and as such, it should be merged on 6.1.

@Seldaek
Copy link
Member Author

Seldaek commented Mar 16, 2022

OK updated to add tests, and also include the idea by @jvasseur above:

We could even go further and throw an access denied exception if the current user class doesn't extends the argument type. This would allow to do thing like limiting access to admin by sub-classing the user class for example.

So now it yields $user or null depending if the $user is instanceof param type (or null for nullable params), and otherwise it throws AccessDenied always.

@chalasr
Copy link
Member

chalasr commented Mar 16, 2022

Looks good. Should we handle the User $user = new User() case somehow?

@Seldaek
Copy link
Member Author

Seldaek commented Mar 16, 2022

@chalasr yes that sounds sensible, although a bit of a weird case it's better if this doesn't end up throwing AccessDenied so I added a test & fix for that case 👍🏻

@fabpot
Copy link
Member

fabpot commented Mar 17, 2022

Thank you @Seldaek.

@Cryde
Copy link

Cryde commented Mar 21, 2022

Some routes are accesible by both anonymous and logged user.
I sometimes use this in my controllers

    #[Route('/', name: 'route_name')]
    public function index(
        Request        $request,
        #[CurrentUser] ?User $user = null
    ): Response { ... }

Will this still work?

@jvasseur
Copy link
Contributor

@Cryde yes because this PR doesn't change anything when the argument is nullable or has a default value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants