Skip to content

[security] "security.authentication.success" event should be fired on every request? #21571

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

Closed
MacDada opened this issue Feb 8, 2017 · 11 comments

Comments

@MacDada
Copy link
Contributor

MacDada commented Feb 8, 2017

At least that's what the docs say: https://symfony.com/doc/2.8/components/security/authentication.html#authentication-success-and-failure-events

When a provider authenticates the user, a security.authentication.success event is dispatched. But beware - this event will fire, for example, on every request if you have session-based authentication.

The problem is, it doesn't fire for me (?) on Symfony 2.8.12.

Not sure if this is a problem with Symfony, with my code/configuration or just the documentation.

My config (I've cut off what I think are irrelevant parts):

#security.yml
security:

    providers:
        orm:
            entity:
                class: AppBundle:User
                property: username

    firewalls:
        # disables authentication for assets and the profiler, adapt it according to your needs
        dev:
            pattern:  ^/(_(profiler|wdt)|css|images|js)/
            security: false

        default:
            anonymous: ~
            provider: orm

            form_login:
                login_path: user_login
                check_path: user_login_check
                success_handler: security_login_success_handler
                target_path_parameter: relocate

            remember_me:
                lifetime: 604800 # 1 week in seconds
                always_remember_me: true

    access_control:
        #- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
#config.yml
framework:
    session:
        handler_id:  session.handler.memcached
        cookie_domain: '%auth_cookies_domain%'
@chalasr
Copy link
Member

chalasr commented Feb 8, 2017

Actually this event is fired only when submitting credentials, no matter if the firewall is stateless or not.
Still not sure if it's a bug in the code or in the doc but, given InteractiveLoginEvent seems to be dispatched only when the authentication occurs because valid credentials are passed to the request, maybe AuthenticationSuccessEvent should indeed be triggered each time session is used?

Related to #20305.

@linaori
Copy link
Contributor

linaori commented Feb 9, 2017

@MacDada in your config here you don't have any authorization enforcing authentication, not even an anonymous enforcer (commented out). If you add that, does it work?

@MacDada
Copy link
Contributor Author

MacDada commented Feb 17, 2017

in your config here you don't have any authorization enforcing authentication

@iltar So what? Authentication !== Authorization. Why would I need any "authorization" check for "security.authentication.success" event to work?

BTW, I actually do have authorization configured – but on the controller level, not on the firewall level.

not even an anonymous enforcer (commented out)

If I required ROLE_USER, ROLE_ADMIN, etc on every path, then I'd need to uncomment that for login form to work. But I don't.

https://symfony.com/doc/2.8/security/form_login_setup.html#be-sure-the-login-page-isn-t-secure-redirect-loop


Anyway, I did a bit more debugging. It really is "strange". Notice that I use memcached to store sessions and do testing while being authenticated from remember me cookie. I check if the event is fired with a breakpoint here.


Scenario one: no authorization requirements in firewall and controller.

  1. clear Symfony cache
  2. restart nginx+php+memcached
  3. fresh request: event gets fired
  4. next request: event does not get fired
  5. clear Symfony cache
  6. request: event does not get fired
  7. restart nginx+php+memcached
  8. request: event does not get fired

So… I need to dump both Symfony cache and sessions storage for the event to fire. But dumping one of them is not enough…


Scenario two: IS_AUTHENTICATED_ANONYMOUSLY role required in firewall authorization.

#security.yml
security:
    access_control:
        - { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }

Test and result same as above.


Scenario three: IS_AUTHENTICATED_ANONYMOUSLY role required in controller authorization.

<?php

namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;

class HomepageController extends Controller
{
	/**
	 * @Route("/", name="homepage")
	 * @Security("is_granted('IS_AUTHENTICATED_ANONYMOUSLY')")
	 *
	 * @param Request $request
	 * @return \Symfony\Component\HttpFoundation\Response
	 */
	public function homepageAction(Request $request)
	{

Test and result same as above.


Scenario four: IS_AUTHENTICATED_ANONYMOUSLY role required both in firewall and controller authorization.

Test and result same as above.


???

@TerjeBr
Copy link

TerjeBr commented May 26, 2017

I also ran into this issue. Are there any news about this?

Is the documentation wrong, or should the symfony code be changed?

@oleg-andreyev
Copy link
Contributor

oleg-andreyev commented May 1, 2018

Ran into this issue today on 2.7.x

  • InteractiveLoginEvent is dispatched only when submitting a form which is correct.
  • AuthenticationEvent (success) will dispatch on each require ONLY if authenticated=false, but UsernamePasswordToken is serialized with authenticated=true

AuthenticationEvent is dispatched in

$this->eventDispatcher->dispatch(AuthenticationEvents::AUTHENTICATION_SUCCESS, new AuthenticationEvent($result));
, authenticate is called from
$token = $this->authManager->authenticate($token);
, ONLY when authenticated=false

Documentation is saying

When a provider authenticates the user, a security.authentication.success event is dispatched. But beware - this event will fire, for example, on every request if you have session-based authentication.

Which is not quite true.

@spantaleev
Copy link

I've also hit this problem..

The documentation says that security.authentication.success fires on every request (when restoring from session), but that doesn't seem to be the case.

My workaround was to use a kernel.request event listener instead and do my work there. Not quite the same, but works well enough for my use case..

@Simperfit
Copy link
Contributor

what's the status of this ?

oleg-andreyev added a commit to oleg-andreyev/symfony that referenced this issue Jun 11, 2019
oleg-andreyev added a commit to oleg-andreyev/symfony that referenced this issue Jun 11, 2019
- updated AbstractToken to compare Roles
- Updated isEqualTo method to match roles as default User implements EquatableInterface
- added test case
@zacharyzh
Copy link

Same problem on 4.3.3

@TerjeBr
Copy link

TerjeBr commented Aug 12, 2019

This seems to be resloved by changing the documentation in symfony/symfony-docs#11457

@zacharyzh
Copy link

So, if I want to modify user session status then should use the request listener instead ?

@chalasr
Copy link
Member

chalasr commented Aug 21, 2019

Authentication happens when an authentication listener proceeds an incoming request i.e. only when credentials are submitted.
When the security token is read from the session, it is already authenticated (and can be deauthenticated). So the bug is in the docs, not in the code.

If one comes with a common enough use case, we could consider dispatching a new event when the token is read from the session.

@chalasr chalasr closed this as completed Aug 21, 2019
fabpot added a commit that referenced this issue Sep 6, 2019
…ged (oleg-andreyev)

This PR was merged into the 4.4 branch.

Discussion
----------

#21571 Comparing roles to detected that users has changed

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | yes
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| License       | MIT
| Fixed tickets | #21571 (comment)
| Docs | symfony/symfony-docs#11457

**Case 1:**
User A has roles `foo, bar and admin`, User A is signed-in into application and token is persisted, later another User B with role `admin`, decided to restrict role `admin` for User A, so User A won't lose it's privileges until session is expired or logout, because token is persisted with `roles` and `authenticated=true` and roles are not compared.

Ref. to the previous attempt: #27121

Commits
-------

4f4c30d - updated AbstractToken to compare Roles - Updated isEqualTo method to match roles as default User implements EquatableInterface - added test case - bumped symfony/security-core to 4.4
javiereguiluz added a commit to symfony/symfony-docs that referenced this issue Sep 24, 2019
…s" section (oleg-andreyev)

This PR was merged into the 4.4 branch.

Discussion
----------

#21571 updated "Authentication Success and Failure Events" section

Updated "Authentication Success and Failure Events"

`security.authentication.success` can be dispatched in the following cases:
- if `always_authenticate_before_granting` is enabled and `isGranted` is called
- if a token is not authenticated before `AccessListener` is invoked
- if customer submitted credentials (actual authentication)

symfony/symfony#21571

Commits
-------

dc91bfd #21571 updated "Authentication Success and Failure Events" section
This was referenced Nov 12, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants