lexik / LexikJWTAuthenticationBundle

JWT authentication for your Symfony API
MIT License
2.51k stars 613 forks source link

User switch / impersonation? #652

Closed yivi closed 5 years ago

yivi commented 5 years ago

The documentation mentions that for user impersonation we should refer to the Symfony docs, but it's not immediately clear how it applies, at least to me.

I've changed my security configuration according to the docs:

login:
            pattern: ^/api/login
            stateless: true
            anonymous:
                secret: null
            switch_user:
                role: ROLE_CAN_IMPERSONATE
                parameter: impersonate
                stateless: false
            json_login:
                check_path: /api/login_check
                success_handler: lexik_jwt_authentication.handler.authentication_success
                failure_handler: lexik_jwt_authentication.handler.authentication_failure
                remember_me: true
                use_forward: false
                require_previous_session: false
                username_path: username
                password_path: password
            methods: {  }
            security: true
            user_checker: security.user_checker
            logout_on_user_change: true

But where and how is this new impoersonation parameter sent?

I tried including it in the payload:

curl -X POST \
      -H "Content-Type: application/json" http://localhost/api/login_check \ 
      -d '{"username":"user_a@example.com","password":"1234", "impersonate": "user_b@example.com"}'

And the query string:

curl -X POST \
       -H "Content-Type: application/json" "http://localhost/api/login_check?impersonate=user_b@example.com" \
       -d '{"username":"user_a@example.com","password":"1234"}'

But the auth token I receive back is always for user_a (which has the role ROLE_CAN_IMPERSONATE and it's included in the token). I verified that the authenticated user ($token->getUser()) matches the user for the auth credentials, not the one we want to impersonate.

Is there another way to send this extra parameter and impersonate a user statelessly using Lexik JWT Authentication?

yivi commented 5 years ago

I see that the documentation for Symfony 3.4 included this bit:

For using the switch_user listener in a stateless firewall, set the switch_user.stateless option to true.

But I believe this option doesn't exist in Sf >=4.

chalasr commented 5 years ago

It does exist in Symfony 4.x. The option has been introduced in 3.4 and will be removed in 5.0 (if the firewall is stateless, the switch_user listener will automatically be stateless).

priyanksaini2010 commented 3 years ago

Was there any solution for this

ahoulgrave commented 2 years ago

Bumped into a problem that i think it's worth mentioning.

I'm using Symfony 3.4, LexikJWTAuthenticationBundle and have this config in my security.yaml file:

security:
    (...)
    firewalls:
    (...)
            api:
            pattern:   ^/
            stateless: true
            switch_user:
                stateless: true
            guard:
                entry_point: My\Custom\Authenticator
                authenticators:
                    - lexik_jwt_authentication.jwt_token_authenticator
                    - My\Custom\Authenticator

I kept getting this exception while impersonating:

No Authentication Provider found for token of class Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken

Did some debugging and noticed that i was passing around a UsernamePasswordToken instead of a JWTUserToken.

The problem was that i had the always_authenticate_before_granting option set to true, not sure why, but as i was calling the isGranted helper method in my controller, the second time that the token was authenticated, the user switch feature would pass a UsernamePasswordToken instead. The AuthenticationProviderManager would not find an authentication provider for that class and would fail with a 401.

So one could say that the impersonation feature won't work with the LexikJWTAuthenticationBundle if you have the always_authenticate_before_granting option set to true.

Hope this helps in the future to someone running into the same issue.