Skip to content
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

Improve logging of the user when he logged in programmatically #720

Merged
merged 12 commits into from
Jul 31, 2023

Conversation

ste93cry
Copy link
Collaborator

@ste93cry ste93cry commented May 11, 2023

Fixes #706. I had no time to test it on a real project, so please do it if you can before merging 🙏

Jean85
Jean85 previously requested changes Jun 17, 2023
Copy link
Collaborator

@Jean85 Jean85 left a comment

Choose a reason for hiding this comment

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

Overall a good PR, with a great set of complete and well described tests. Just a few nitpick.

@@ -37,7 +37,8 @@
"symfony/http-kernel": "^4.4.20||^5.0.11||^6.0",
"symfony/polyfill-php80": "^1.22",
"symfony/psr-http-message-bridge": "^1.2||^2.0",
"symfony/security-core": "^4.4.20||^5.0.11||^6.0"
"symfony/security-core": "^4.4.20||^5.0.11||^6.0",
"symfony/security-http": "^4.4.20||^5.0.11||^6.0"
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure about this requirement. And to be frank, even the previous one could be invasive in some edge cases...

Maybe it's out of scope for this PR, but I think we should move these two requirements to require-dev, and make the code that uses them optional.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I agree, definitely. However, making the code optional is a completely different topic that I don't want to tackle here. We need the security-http package mostly because of the event classes that are part of it IIRC.

src/EventListener/LoginListener.php Outdated Show resolved Hide resolved
@ste93cry ste93cry requested a review from Jean85 June 17, 2023 15:34
@ste93cry
Copy link
Collaborator Author

ste93cry commented Jul 6, 2023

@cleptric can I ask for your review on this?

@cleptric
Copy link
Member

cleptric commented Jul 6, 2023

Yep, can take a look tomorrow/next week.

Copy link
Member

@cleptric cleptric left a comment

Choose a reason for hiding this comment

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

Do we need to listen to an additional event?

The user ID is only set on the scope during a request that contains credentials, all subsequent requests to a route guarded with access_control will only set the user's IP on the scope.

@ste93cry
Copy link
Collaborator Author

I found out that the RequestListener listener was overwriting the entire user context set on the scope. Since the LoginListener probably ran earlier than that, it may have been the cause of seeing only the user IP address for all subsequent requests. I still have some doubts about the fact that we need to listen on the kernel.request event to gather the user data from the token storage though because I'm not sure that the LoginSuccessEvent event is dispatched on every request...

@cleptric
Copy link
Member

Both LoginListener::handleLoginSuccessEvent and LoginListener::handleAuthenticationSuccessEvent seem not to be called on each request. In my controller, $this->security->getUser() does return the logged-in user. The event sent to Sentry only contains the IP.

Screenshot 2023-07-25 at 22 12 35

@ste93cry
Copy link
Collaborator Author

ste93cry commented Jul 26, 2023

Do you mind sharing the version of the framework you're using and the security.yaml file you're using in your test project? In mine, I configured it like this and it seems to work fine:

security:
    password_hashers:
        Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'plaintext'

    providers:
        users_in_memory:
            memory:
                users:
                    john: { password: 'doe', roles: ['ROLE_USER'] }

    firewalls:
        main:
            provider: users_in_memory
            http_basic:
                realm: Secured Area

    access_control:
        - { path: ^/, roles: ROLE_USER }

Note that with this config, even though I'm using HTTP basic authentication, a session is created so that the browser does not ask me the credentials at every page refresh

@cleptric
Copy link
Member

security:
    # https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
    password_hashers:
        Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
    # https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
    providers:
        # used to reload user from session & other features (e.g. switch_user)
        app_user_provider:
            entity:
                class: App\Entity\User
                property: email
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            lazy: true
            provider: app_user_provider

            form_login:
                # "app_login" is the name of the route created previously
                login_path: login
                check_path: login

            logout:
                path: logout
                # where to redirect after logout
                target: /

            # activate different ways to authenticate
            # https://symfony.com/doc/current/security.html#the-firewall

            # https://symfony.com/doc/current/security/impersonating_user.html
            # switch_user: true

    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
        - { path: ^/sentry, roles: ROLE_USER }

when@test:
    security:
        password_hashers:
            # By default, password hashers are resource intensive and take time. This is
            # important to generate secure password hashes. In tests however, secure hashes
            # are not important, waste resources and increase test times. The following
            # reduces the work factor to the lowest possible values.
            Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
                algorithm: auto
                cost: 4 # Lowest possible value for bcrypt
                time_cost: 3 # Lowest possible value for argon
                memory_cost: 10 # Lowest possible value for argon

@ste93cry
Copy link
Collaborator Author

ste93cry commented Jul 26, 2023

I can't replicate the problem with your setup either. There are still some minor differences between my setup and yours, e.g. the user provider and password hasher, but it shouldn't matter at all. I'm using Symfony 6.3, maybe you are using a different version and some behaviour changed? Otherwise, can you please share a repo reproducing the issue?

@cleptric
Copy link
Member

https://github.com/cleptric/symfony - Most logic is in the SentryController.

@ste93cry
Copy link
Collaborator Author

I have no clue on why it was working in my test project, but indeed the framework does not dispatch the two login-related events for each request. I readded back a listener for the request.kernel event and it now works as expected.

@cleptric
Copy link
Member

Screenshot 2023-07-27 at 13 14 16

Looking good!

@Jean85 can you take another look, please?

@ste93cry ste93cry changed the title Improve filling the User context Improve logging of the user when he logged in programmatically Jul 27, 2023
@cleptric cleptric merged commit d1e5128 into getsentry:master Jul 31, 2023
26 of 28 checks passed
@ste93cry ste93cry deleted the fix-user-context-filling branch July 31, 2023 14:43
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.

User is not set when logged in programatically
4 participants