Skip to content

[Core] Add voter to check for sylius impersonation#16650

Merged
GSadee merged 2 commits intoSylius:2.1from
lusimeon:sylius-impersonator-voter
Jun 3, 2025
Merged

[Core] Add voter to check for sylius impersonation#16650
GSadee merged 2 commits intoSylius:2.1from
lusimeon:sylius-impersonator-voter

Conversation

@lusimeon
Copy link
Contributor

@lusimeon lusimeon commented Jul 29, 2024

Q A
Branch? 2.1
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Related tickets fixes #14845
License MIT

Description

At this time, it's impossible to check if logged-in customer is impersonated or not. This feature can be useful to be able to allow or deny some actions to admin users when impersonate customer.

This PR add an Authorization voter to be able to check if customer is impersonated. The firewall can be pass as voter attribute subject, it defaults to request's firewall instead.

Usage

In controller:

private \Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface $authorizationChecker;
…
$this->authorizationChecker->isGranted('IS_IMPERSONATOR_SYLIUS')
$this->authorizationChecker->isGranted('IS_IMPERSONATOR_SYLIUS', 'my_firewall_name')

In view:

{% if is_granted('IS_IMPERSONATOR_SYLIUS') %}
'You are currently impersonate %s'|format(app.user.username)
{% endif %}

{% if is_granted('IS_IMPERSONATOR_SYLIUS', 'my_firewall_name') %}…{% endif %}

Summary by CodeRabbit

  • New Features

    • Enhanced user impersonation management by ensuring impersonation data is automatically cleared at logout.
    • Improved security with added checks to verify and manage impersonation state through a new security voter.
  • Tests

    • Introduced comprehensive tests validating impersonation handling and ensuring secure, reliable functionality across different scenarios.

@github-actions
Copy link

github-actions bot commented Jul 29, 2024

❌ Preview Environment deleted from Bunnyshell

Available commands:

  • 🚀 /bns:deploy to redeploy the environment

@lusimeon lusimeon force-pushed the sylius-impersonator-voter branch 3 times, most recently from 284e3e0 to 6fbdd8a Compare July 31, 2024 23:18
@lusimeon lusimeon marked this pull request as ready for review July 31, 2024 23:20
@lusimeon lusimeon requested review from a team as code owners July 31, 2024 23:20
@lusimeon lusimeon changed the title [User] Add voter to check for impersonated customer [Core] Add voter to check for sylius impersonation Aug 1, 2024
@coderabbitai
Copy link

coderabbitai bot commented Mar 12, 2025

Walkthrough

This pull request introduces user impersonation functionality. A new event subscriber cleans up impersonation-related session data upon logout, and the session management in the impersonation service is updated to store a unique parameter. In addition, a new security voter is implemented to determine if a user is impersonated, with corresponding tests added to validate the behavior. The changes also include new service definitions to register these components.

Changes

File(s) Change Summary
src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php
src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php
Introduces an event subscriber that listens for logout events and removes impersonation session variables. Accompanied by PhpSpec tests to verify event subscription, session removal, and exception handling.
src/Sylius/Bundle/CoreBundle/Resources/config/services.xml
src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml
Adds new service definitions: one for an authenticated voter (sylius.security.voter.authenticated) and another to register the user impersonator subscriber (sylius.listener.user_impersonator), including proper arguments and tags.
src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php Updates the impersonation logic by introducing a private property to store a formatted session parameter and setting this parameter during impersonation.
src/Sylius/Bundle/CoreBundle/Security/ImpersonationVoter.php
src/Sylius/Bundle/CoreBundle/spec/Security/ImpersonationVoterSpec.php
Implements a voter to check impersonation status based on session values. The voter returns ACCESS_GRANTED, ACCESS_DENIED, or ACCESS_ABSTAIN after verifying the impersonation attribute, with comprehensive tests covering all cases.

Sequence Diagram(s)

sequenceDiagram
  participant User as User
  participant Kernel as Kernel
  participant Subscriber as UserImpersonatorSubscriber
  participant FM as FirewallMap
  participant Session as Session

  User->>Kernel: Triggers Logout
  Kernel->>Subscriber: Dispatch LogoutEvent
  Subscriber->>Subscriber: Retrieve Request from event
  Subscriber->>FM: Get firewall configuration
  FM-->>Subscriber: Return firewall config / null
  Subscriber->>Session: Remove impersonation session variable
  Session-->>Subscriber: Acknowledge removal
Loading
sequenceDiagram
  participant Security as Security System
  participant Voter as ImpersonationVoter
  participant RequestStack as RequestStack
  participant FM as FirewallMap
  participant Session as Session

  Security->>Voter: vote(token, subject, attributes)
  Voter->>RequestStack: Get current request
  RequestStack-->>Voter: Return request
  Voter->>FM: Get firewall config for request
  FM-->>Voter: Return firewall name or null
  Voter->>Session: Check impersonation session variable
  Session-->>Voter: Return impersonation status or error
  Voter-->>Security: Return ACCESS_GRANTED/ACCESS_DENIED/ACCESS_ABSTAIN
Loading

Assessment against linked issues

Objective Addressed Explanation
Allow to know if a connected shop user is impersonated (#14845)

Poem

I'm a rabbit with a skip and a hop,
Coding changes make my heart go pop!
Impersonation cleared with a gentle nudge,
Tests and voters ensure no grudge.
Happy hops in code, with carrots on top!


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 30a944e and 1e49608.

📒 Files selected for processing (7)
  • src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services.xml (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Security/ImpersonationVoter.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php (3 hunks)
  • src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/spec/Security/ImpersonationVoterSpec.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml
  • src/Sylius/Bundle/CoreBundle/Resources/config/services.xml
  • src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php
  • src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php
  • src/Sylius/Bundle/CoreBundle/spec/Security/ImpersonationVoterSpec.php
  • src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php
  • src/Sylius/Bundle/CoreBundle/Security/ImpersonationVoter.php

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@lusimeon lusimeon changed the base branch from 1.14 to 2.1 March 12, 2025 15:30
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php (1)

34-46: Check session existence before removal.

Symfony usually ensures a session is available, but in rare or custom setups the session might not be started or could be null. A brief defensive check would prevent possible edge-case exceptions:

 public function unimpersonate(LogoutEvent $event): void
 {
     $request = $event->getRequest();
     $config = $this->firewallMap->getFirewallConfig($request);

     if (!$config) {
         return;
     }

+    if (!$request->hasSession()) {
+        return;
+    }

     $request->getSession()->remove(
         sprintf('_security_impersonate_sylius_%s', $config->getName()),
     );
 }
src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php (1)

32-46: Add spec for missing firewall config scenario.

Currently, you only test the normal path where getFirewallConfig() returns a config. Consider verifying the behavior when null is returned, ensuring the method exits gracefully. This covers an edge case and improves test robustness.
Would you like me to generate a complementary spec snippet that tests the scenario when getFirewallConfig returns null?

src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (1)

69-82: Slight caution with session-based checks.

In isImpersonated, the SessionProvider::getSession(...) call is convenient. However, edge cases might arise if the session is not started or if $firewall resolution is null. If that’s acceptable, no changes needed; otherwise, consider a safety check to avoid potential null returns.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f6ee17 and 1eb7044.

📒 Files selected for processing (7)
  • src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services.xml (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php (3 hunks)
  • src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Static checks / PHP 8.3, Symfony ^7.1
  • GitHub Check: Static checks / PHP 8.2, Symfony ^6.4
🔇 Additional comments (11)
src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml (1)

134-138: LGTM: New event subscriber service for impersonation cleanup is well-structured

The new sylius.listener.user_impersonator service is properly configured as a kernel event subscriber with the necessary security.firewall.map dependency. This implementation aligns perfectly with the PR objectives to detect user impersonation.

src/Sylius/Bundle/CoreBundle/Resources/config/services.xml (1)

284-289: LGTM: Security voter decorator properly integrated

The AuthenticatedVoter service is correctly configured as a decorator for Symfony's security.access.authenticated_voter, with appropriate dependencies injected. This implementation allows the system to check if a user is being impersonated through the standard security authorization system.

src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php (3)

29-29: LGTM: Added property for tracking impersonation state

The new private property $sessionImpersonatorParameter is well-named and properly typed.


39-39: LGTM: Consistent session parameter naming convention

The initialization of $sessionImpersonatorParameter follows the same pattern as the existing $sessionTokenParameter with a clear naming convention that indicates its purpose.


53-53: LGTM: Session now tracks impersonation state

Setting the impersonation flag in the session enables the voter to later determine if a user is being impersonated, which is the core functionality needed for this feature.

src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php (1)

1-60: LGTM: Comprehensive test coverage for impersonation voter

The spec file provides excellent test coverage for the new AuthenticatedVoter functionality:

  1. It verifies that the voter supports the custom IS_IMPERSONATOR_SYLIUS attribute
  2. It tests the positive case (user is impersonated)
  3. It tests the negative case (user is not impersonated)

The tests are well-structured and cover the essential functionality of the voter.

src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php (2)

22-25: Constructor usage looks good.

This constructor neatly injects the FirewallMap without cluttering or additional logic.


27-32: Event subscription is straightforward and follows best practices.

Subscribing to the LogoutEvent with unimpersonate is clear and aligns with Symfony’s canonical event-subscriber model.

src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php (1)

27-30: Constructor (let method) is concise.

The let method cleanly instantiates the subscriber with the mocked FirewallMap. This helps ensure each spec runs in isolation.

src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (2)

25-31: Constructor usage looks fine.

Injecting the original voter, the RequestStack, and FirewallMap keeps this class small and aligned with your design, without duplicating logic.


34-55: Clarify how the subject relates to the firewall.

The code calls $this->isImpersonated($subject) to check impersonation, but $subject may be a domain object, not a string (firewall name). Consider ensuring $subject is indeed the firewall name or refactor to retrieve the firewall name from the active request to avoid confusion:

 if (self::IS_IMPERSONATOR_SYLIUS === $attribute && $this->isImpersonated($subject)) {
     return VoterInterface::ACCESS_GRANTED;
 }

For instance:

$this->isImpersonated(); // rely solely on the main request or a passed firewall name

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (1)

68-82: Handle missing session more gracefully.

$this->requestStack->getSession() may be null if no session is available. Consider a safeguard to avoid potential \LogicException. For instance:

-if (!$firewall) {
+if (!$firewall || !$this->requestStack->getSession()) {
    return false;
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1eb7044 and 30db055.

📒 Files selected for processing (1)
  • src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (12)
  • GitHub Check: End-to-end tests (MariaDB) / Non-JS, PHP 8.3, Symfony ^7.1, MariaDB 11.4.3, State Machine Adapter symfony_workflow
  • GitHub Check: End-to-end tests (MariaDB) / Non-JS, PHP 8.2, Symfony ^6.4, MariaDB 10.11.9, State Machine Adapter symfony_workflow
  • GitHub Check: End-to-end tests (PostgreSQL) / Non-JS, PHP 8.3, Symfony ^7.1, PostgreSQL 16.4
  • GitHub Check: End-to-end tests (PostgreSQL) / Non-JS, PHP 8.2, Symfony ^6.4, PostgreSQL 15.8
  • GitHub Check: Packages / PHP 8.3, Symfony ^7.1
  • GitHub Check: Packages / PHP 8.2, Symfony ^6.4
  • GitHub Check: End-to-end tests (MySQL) / Non-JS, PHP 8.3, Symfony ^7.1 (test_cached), MySQL 8.4, Twig ^3.3
  • GitHub Check: End-to-end tests (MySQL) / Non-JS, PHP 8.2, Symfony ^6.4 (test_cached), MySQL 8.0, Twig ^3.3
  • GitHub Check: End-to-end tests (MySQL) / JS with Chromedriver, PHP 8.3, Symfony ^7.1 (test_cached), MySQL 8.4, Twig ^3.3
  • GitHub Check: End-to-end tests (MySQL) / JS with Panther, PHP 8.3, Symfony ^7.1 (test_cached), MySQL 8.4, Twig ^3.3
  • GitHub Check: End-to-end tests (MySQL) / JS with Panther, PHP 8.2, Symfony ^6.4 (test_cached), MySQL 8.0, Twig ^3.3
  • GitHub Check: End-to-end tests (MySQL) / JS with Chromedriver, PHP 8.2, Symfony ^6.4 (test_cached), MySQL 8.0, Twig ^3.3
🔇 Additional comments (6)
src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (6)

22-25: Well-structured class purpose and naming.

The class name AuthenticatedVoter and the constant IS_IMPERSONATOR_SYLIUS are clearly named and aligned with the intended functionality for handling Sylius-specific impersonation checks.


26-31: Constructor injection is concise and maintainable.

All dependencies are injected via the constructor, keeping the class loosely coupled and testable.


33-54: Potential misuse of $subject when checking impersonation.

When the attribute is IS_IMPERSONATOR_SYLIUS, the method calls isImpersonated($subject). However, $subject might not be a string or even relevant to the firewall name. Consider ensuring $subject is either null or a string representing the firewall name before passing it to isImpersonated.

Do you want to validate $subject type or rename that parameter to clarify it’s meant to be the firewall name if provided?


56-61: Consistent support for custom and inherited attributes.

By deferring to $authenticatedVoter->supportsAttribute($attribute), the code seamlessly handles attributes beyond impersonation, following Symfony best practices.


63-66: Proper delegation for subject type checks.

Forwarding supportsType calls to the underlying voter nicely adheres to the Liskov Substitution Principle (LSP) and ensures consistent behavior.


84-87: Clear key naming.

Using _security_impersonate_sylius_%s for the session key is both distinctive and unlikely to collide, making it straightforward to identify impersonation status in session data.

@lusimeon lusimeon force-pushed the sylius-impersonator-voter branch from 30db055 to 858e558 Compare March 19, 2025 17:09
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php (1)

25-32: Consider adding a test for automatic firewall detection.

The tests cover explicit firewall specification, but there's no test for when the firewall name is automatically detected from the request (when null is passed to isImpersonated).

function it_votes_with_automatically_detected_firewall(
    TokenInterface $token,
    RequestStack $requestStack,
    SessionInterface $session,
    Request $request,
    FirewallConfig $firewallConfig,
    FirewallMap $firewallMap
): void {
    $requestStack->getMainRequest()->willReturn($request);
    $firewallMap->getFirewallConfig($request)->willReturn($firewallConfig);
    $firewallConfig->getName()->willReturn(self::FIREWALL_NAME);
    
    $requestStack->getSession()->willReturn($session);
    $session->get(sprintf('_security_impersonate_sylius_%s', self::FIREWALL_NAME), false)->willReturn(true);

    $this->vote($token, null, [AuthenticatedVoter::IS_IMPERSONATOR_SYLIUS])->shouldReturn(VoterInterface::ACCESS_GRANTED);
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 30db055 and 858e558.

📒 Files selected for processing (7)
  • src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services.xml (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php (3 hunks)
  • src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php
  • src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml
  • src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php
  • src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php
  • src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php
🧰 Additional context used
🧬 Code Definitions (1)
src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php (1)
src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (3) (3)
  • AuthenticatedVoter (22-88)
  • supportsAttribute (56-61)
  • vote (33-54)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Packages / Get matrix
  • GitHub Check: End-to-end tests (PostgreSQL) / Get matrix
  • GitHub Check: End-to-end tests (MariaDB) / Get matrix
  • GitHub Check: End-to-end tests (MySQL) / Get matrix
🔇 Additional comments (4)
src/Sylius/Bundle/CoreBundle/Resources/config/services.xml (1)

286-290: Great service integration!

The service definition correctly decorates the standard Symfony security.access.authenticated_voter service, extending it with impersonation detection capability. The approach leverages Symfony's decorator pattern effectively to add functionality without modifying the core implementation.

src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php (3)

34-37: LGTM! Support for the custom attribute is properly tested.

The test correctly verifies that the voter supports the new IS_IMPERSONATOR_SYLIUS attribute.


39-48: LGTM! The positive impersonation case is well tested.

This test properly verifies that when a user is being impersonated (session returns true for the impersonation key), the voter grants access as expected.


50-59: LGTM! The negative impersonation case is well tested.

This test correctly verifies that when a user is not being impersonated (session returns false for the impersonation key), the voter denies access as expected.

@lusimeon lusimeon force-pushed the sylius-impersonator-voter branch from 858e558 to 5445fe9 Compare March 19, 2025 17:58
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml (1)

139-142: New Service Declaration for User Impersonator Subscriber

The addition of the sylius.listener.user_impersonator service is well-configured. It properly injects the security.firewall.map dependency and is registered as an event subscriber. Please ensure that the associated UserImpersonatorSubscriber correctly implements EventSubscriberInterface and that its event handling (e.g., for logout events) aligns with your intended impersonation cleanup logic. Also, verify that the dependency injected is the correct service needed to determine the current firewall context.

src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (1)

38-48: Consider breaking once the impersonator attribute is found for efficiency.

Currently, the loop continues checking new attributes even after encountering IS_IMPERSONATOR_SYLIUS. If only one impersonator attribute is expected per vote, you could break early for a minor performance improvement:

 foreach ($attributes as $attribute) {
     if (null === $attribute || (self::IS_IMPERSONATOR_SYLIUS !== $attribute)) {
         continue;
     }

     $result = VoterInterface::ACCESS_DENIED;

     if ($this->isImpersonated($subject)) {
         return VoterInterface::ACCESS_GRANTED;
     }

-    // continue checking further attributes
+    break;
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 858e558 and 5445fe9.

📒 Files selected for processing (7)
  • src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services.xml (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php (3 hunks)
  • src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services.xml
  • src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php
  • src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php
  • src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php
🧰 Additional context used
🧬 Code Definitions (1)
src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (2)
src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php (1) (1)
  • __construct (22-25)
src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php (1) (1)
  • __construct (33-41)
⏰ Context from checks skipped due to timeout of 90000ms (9)
  • GitHub Check: End-to-end tests (PostgreSQL) / Non-JS, PHP 8.2, Symfony ^6.4, PostgreSQL 15.8
  • GitHub Check: Packages / PHP 8.3, Symfony ^7.1
  • GitHub Check: Packages / PHP 8.2, Symfony ^6.4
  • GitHub Check: End-to-end tests (MySQL) / JS with Chromedriver, PHP 8.3, Symfony ^7.1 (test_cached), MySQL 8.4, Twig ^3.3
  • GitHub Check: End-to-end tests (MySQL) / JS with Panther, PHP 8.3, Symfony ^7.1 (test_cached), MySQL 8.4, Twig ^3.3
  • GitHub Check: End-to-end tests (MySQL) / JS with Chromedriver, PHP 8.2, Symfony ^6.4 (test_cached), MySQL 8.0, Twig ^3.3
  • GitHub Check: End-to-end tests (MySQL) / Non-JS, PHP 8.3, Symfony ^7.1 (test_cached), MySQL 8.4, Twig ^3.3
  • GitHub Check: End-to-end tests (MySQL) / JS with Panther, PHP 8.2, Symfony ^6.4 (test_cached), MySQL 8.0, Twig ^3.3
  • GitHub Check: End-to-end tests (MySQL) / Non-JS, PHP 8.2, Symfony ^6.4 (test_cached), MySQL 8.0, Twig ^3.3
🔇 Additional comments (4)
src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php (3)

35-38: Test coverage for attribute support is comprehensive.

This test neatly proves that IS_IMPERSONATOR_SYLIUS is recognized as a supported attribute, preventing regressions in attribute handling.


40-49: Well-structured test for impersonation check.

Verifies the session-based impersonation flag effectively grants the correct access. This ensures that the voter logic aligns with the feature's promises.


61-69: Commendable coverage of the no-session edge case.

Testing the outcome when a session does not exist ensures graceful handling and prevents runtime errors in non-session contexts, such as API requests.

src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (1)

69-87:

Details

❓ Verification inconclusive

Verify the subject assumption when passing the firewall name.

The isImpersonated(?string $firewall = null) method expects $subject to be the firewall name if provided. If $subject might sometimes be a different type or if other code paths set $subject to a non-string, it could lead to unexpected results in sprintf.

Run this script to confirm all usage sites pass valid string firewall names:


🏁 Script executed:

#!/bin/bash
# Description: Ensure that AuthenticatedVoter is only called with string or null subject values.

# Look for calls to AuthenticatedVoter::vote(...) across the codebase.
rg -A 3 'AuthenticatedVoter->vote\s*\('

Length of output: 41


Action Required: Manual Verification of Firewall Name Passing

The automated search for call sites of AuthenticatedVoter::vote(...) did not produce any outputs, leaving us without conclusive evidence that the firewall name (subject) is consistently passed as a string (or null). This means there’s no automated confirmation that all usages enforce the correct type. To be safe, please manually verify that any calls to or uses of the firewall name in the AuthenticatedVoter (especially as used in methods like getImpersonateKeyName) indeed pass a string or null, ensuring that no non-string value is inadvertently used in a context (such as sprintf) that expects a string.

@lusimeon lusimeon force-pushed the sylius-impersonator-voter branch from 5445fe9 to 10df5e9 Compare March 19, 2025 23:16
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php (2)

17-17: Remove unused import

The Psr\Http\Message\RequestInterface import is not used anywhere in this specification class.

-use Psr\Http\Message\RequestInterface;

63-63: Fix method name grammar

The method name has a grammatical error.

-function it_votes_abstain_when_session_do_not_exists(
+function it_votes_abstain_when_session_does_not_exist(
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5445fe9 and 10df5e9.

📒 Files selected for processing (7)
  • src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services.xml (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php (3 hunks)
  • src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml
  • src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php
  • src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php
  • src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php
  • src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php
🧰 Additional context used
🧬 Code Definitions (1)
src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php (1)
src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (3) (3)
  • AuthenticatedVoter (23-102)
  • supportsAttribute (47-52)
  • vote (34-45)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Packages / Get matrix
  • GitHub Check: End-to-end tests (PostgreSQL) / Get matrix
🔇 Additional comments (6)
src/Sylius/Bundle/CoreBundle/Resources/config/services.xml (1)

286-290: Properly defined voter service with appropriate dependencies

The AuthenticatedVoter service is correctly defined as a decorator for the Symfony authenticated voter, with all necessary dependencies injected. This implementation follows the decorator pattern best practices by passing the inner service as the first argument and adding the required request stack and firewall map.

src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php (5)

37-40: LGTM: Correctly tests attribute support

This test properly verifies that the voter supports the IS_IMPERSONATOR_SYLIUS attribute.


42-51: LGTM: Proper test for the impersonated user scenario

This test correctly verifies that the voter grants access when the session contains impersonation data.


53-62: LGTM: Proper test for the non-impersonated user scenario

This test correctly verifies that the voter denies access when the session does not contain impersonation data.


63-70: LGTM: Addresses the previous review comment about session absence

This test properly handles the edge case when a session doesn't exist by verifying the voter abstains from voting.


72-82: LGTM: Proper test for handling null firewall

This test correctly verifies that the voter abstains when the firewall configuration is not available.

@lusimeon lusimeon force-pushed the sylius-impersonator-voter branch 2 times, most recently from d781634 to 990bdd8 Compare March 19, 2025 23:32
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (3)

23-25: Suggest adding a docblock for the class.

Adding a short PHPDoc explaining the purpose of this voter would enhance clarity for future maintainers.


33-56: Handle silent catch for SessionNotFoundException.

Breaking out of the loop when the session isn't found might obscure potential debugging. Consider logging or explicitly handling the case if needed for troubleshooting.


90-93: Optional: Extract the key prefix as a constant.

For consistency, consider extracting '_security_impersonate_sylius_' into a class-level constant, as it’s repeated in similar classes like UserImpersonator.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 10df5e9 and 990bdd8.

📒 Files selected for processing (7)
  • src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services.xml (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php (3 hunks)
  • src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php
  • src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml
  • src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php
  • src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php
  • src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php
🧰 Additional context used
🧬 Code Definitions (1)
src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (2)
src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php (1) (1)
  • __construct (33-41)
src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php (1) (1)
  • __construct (22-25)
🔇 Additional comments (6)
src/Sylius/Bundle/CoreBundle/Resources/config/services.xml (1)

286-290: Nicely configured service decoration.

The constructor arguments align well with your custom AuthenticatedVoter class. This setup should seamlessly replace the default Symfony security.access.authenticated_voter.

src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (5)

1-13: File header and strict typing.

The file header and the declare(strict_types=1); usage adhere to best practices.


25-31: Well-structured constructor.

Declaring constructor properties as private is a neat approach and aligns with modern PHP standards.


58-66: Simple and focused support checks.

The supportsAttribute and supportsType methods are concise and correct for a voter that targets one specific attribute.


68-77: Straightforward impersonation check.

Fetching the session value under a specific key is clear. The method is well-isolated, improving testability.


79-88: Graceful null handling for firewall.

Returning null if the main request or its firewall configuration is absent avoids potential errors.

@lusimeon lusimeon force-pushed the sylius-impersonator-voter branch from 990bdd8 to 2329dbf Compare March 19, 2025 23:55
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (3)

23-26: Add a short docblock explaining the purpose of this custom voter.
Even though the class name is self-explanatory, a brief docblock describing its high-level role (e.g., checking if a user is impersonated) is helpful for documentation purposes.


33-56: Consider logging the SessionNotFoundException.
Silently catching the SessionNotFoundException (lines 49-50) may hide real issues in production. Logging a warning would help troubleshoot misconfigurations.

Below is a possible approach if you decide to add a logger:

 use Psr\Log\LoggerInterface;

 class AuthenticatedVoter implements CacheableVoterInterface
 {
     private ?LoggerInterface $logger = null;

     public function __construct(
         private RequestStack $requestStack,
         private FirewallMap $firewallMap,
+        ?LoggerInterface $logger = null,
     ) {
         $this->logger = $logger;
     }

     public function vote(TokenInterface $token, mixed $subject, array $attributes): int
     {
         foreach ($attributes as $attribute) {
             if (self::IS_IMPERSONATOR_SYLIUS !== $attribute) {
                 continue;
             }

             $firewall = $subject ?? $this->getMainRequestFirewallName();
             if ($firewall) {
                 try {
                     return $this->isImpersonated($firewall)
                         ? VoterInterface::ACCESS_GRANTED
                         : VoterInterface::ACCESS_DENIED;
                 } catch (SessionNotFoundException) {
+                    if (null !== $this->logger) {
+                        $this->logger->warning('Session not found while checking impersonation.');
+                    }
                 }
             }

             break;
         }

         return VoterInterface::ACCESS_ABSTAIN;
     }

79-93: Firewall name resolution & key computation.
Using the main request’s firewall via firewallMap is consistent with typical Symfony security voter patterns. Be mindful that in edge cases (e.g., sub-requests or multiple firewalls), you may need additional logic.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 990bdd8 and 2329dbf.

📒 Files selected for processing (7)
  • src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services.xml (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php (3 hunks)
  • src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services.xml
  • src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php
  • src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml
  • src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php
  • src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php
  • src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php
🧰 Additional context used
🧬 Code Definitions (1)
src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (2)
src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php (1) (1)
  • __construct (22-25)
src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php (1) (1)
  • __construct (33-41)
🔇 Additional comments (3)
src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (3)

27-31: Constructor usage.
Injecting the RequestStack and FirewallMap is appropriate for retrieving firewall configurations and session data. No issues here.


58-66: All attributes & subject types.
Returning true from supportsType() ensures this voter can process any subject type. Given that impersonation checks don't depend on any specific object, this approach is valid.


68-77:

Details

✅ Verification successful

Session key-based check.
This straightforward approach correctly retrieves the boolean flag from the session. Ensure it remains in sync with how keys are set (e.g., in UserImpersonator) so that naming never diverges.

Would you like to verify that all code paths setting this _security_impersonate_sylius_{firewall} key align with usage here?


🏁 Script executed:

#!/bin/bash
rg '_security_impersonate_sylius_' -A 3

Length of output: 2708


Session Key Consistency Verified
The impersonation flag in isImpersonated() correctly retrieves the session key formatted as _security_impersonate_sylius_{firewall}. Our verification confirms that all code paths—such as those in UserImpersonator, AuthenticatedVoterSpec.php, and UserImpersonatorSubscriber—use the same naming convention. Please ensure that any future changes preserve this consistency.

@lusimeon lusimeon force-pushed the sylius-impersonator-voter branch from 2329dbf to 99f4ffc Compare March 20, 2025 09:07
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php (1)

40-42: Consider adding a test for when FirewallConfig is null.

The current tests verify behavior when FirewallConfig is available, but it would be beneficial to also test the case where getFirewallConfig() returns null, which could happen in a real application.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2329dbf and 99f4ffc.

📒 Files selected for processing (7)
  • src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services.xml (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php (3 hunks)
  • src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services.xml
  • src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml
  • src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php
  • src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php
  • src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php
  • src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php
🔇 Additional comments (2)
src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php (2)

1-62: Well-structured spec file with comprehensive test coverage.

The spec file properly tests the subscriber's behavior for removing impersonation session variables during logout events. The test coverage includes both the happy path and error handling for when the session is not available.


44-44:

Details

✅ Verification successful

Verify the session variable name format.

Make sure the session variable format _security_impersonate_sylius_%s matches what's used in the actual implementation. This is critical for the impersonation feature to work correctly.


🏁 Script executed:

#!/bin/bash
# Search for the session variable name pattern in the implementation
rg "_security_impersonate_sylius_" --type php --glob "src/Sylius/Bundle/CoreBundle/**/*.php" --no-line-number

Length of output: 1142


Session variable naming verified and consistent

The session variable format _security_impersonate_sylius_%s is used consistently across the codebase (as seen in UserImpersonator, AuthenticatedVoter, and related specs). No changes are required for this naming format.

@lusimeon lusimeon force-pushed the sylius-impersonator-voter branch from 99f4ffc to d28539b Compare March 20, 2025 09:17
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/Sylius/Bundle/CoreBundle/Resources/config/services.xml (1)

286-291: Consider clarifying the voter name to avoid confusion with Symfony’s built-in AuthenticatedVoter.
While this voter is scoped under Sylius namespaces, the identical name “AuthenticatedVoter” can create ambiguity, especially in discussions or debugging. You might consider a unique naming convention (e.g., SyliusImpersonationVoter) for clarity.

src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php (1)

24-85: Well-designed test coverage for the UserImpersonatorSubscriber

This spec file provides excellent test coverage for the UserImpersonatorSubscriber, including all edge cases (session not found, missing firewall config) and successfully addresses the previous review comment about testing the getSubscribedEvents method. The tests are well-structured and follow PhpSpec best practices.

Consider adding a descriptive PHPDoc comment to the class to explain its purpose and relationship to the implementation class it's testing.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 99f4ffc and d28539b.

📒 Files selected for processing (7)
  • src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services.xml (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php (3 hunks)
  • src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php (1 hunks)
  • src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php
  • src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php
  • src/Sylius/Bundle/CoreBundle/spec/Security/AuthenticatedVoterSpec.php
🧰 Additional context used
🧬 Code Definitions (1)
src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (2)
src/Sylius/Bundle/CoreBundle/EventListener/UserImpersonatorSubscriber.php (1) (1)
  • __construct (23-26)
src/Sylius/Bundle/CoreBundle/Security/UserImpersonator.php (1) (1)
  • __construct (33-41)
🔇 Additional comments (6)
src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml (1)

139-143: Looks good!
Registering the UserImpersonatorSubscriber as a kernel event subscriber with the firewall map argument is consistent with Symfony’s recommended approach. This enables proper cleanup or management of impersonation data during logout events.

src/Sylius/Bundle/CoreBundle/Security/AuthenticatedVoter.php (4)

23-31: Excellent approach to using CacheableVoterInterface for performance.
Implementing CacheableVoterInterface can improve performance by caching outcomes for given attributes and subjects. The constructor injection of RequestStack and FirewallMap is clear and aligns with your impersonation logic.


33-56: Validate the default abstention logic when the session is unavailable.
In the vote() method, if a session is missing or throws a SessionNotFoundException, this voter abstains. This design is typically correct in Symfony to avoid incorrectly denying access. However, confirm that your application does not require a stricter denial under these conditions.

Do you want to verify the intended behavior by testing a scenario where no session is available (e.g., a stateless firewall)? I can generate a quick test script if needed.


58-77: Straightforward support checks and impersonation retrieval.
Your supportsAttribute() method ensures the voter only processes the IS_IMPERSONATOR_SYLIUS attribute, and isImpersonated() neatly reads the session flag. This is well-encapsulated and avoids confusion with other attributes.


79-93: Firewall-based session key retrieval is well-structured.
Using getMainRequestFirewallName() and constructing the _security_impersonate_sylius_%s session key is clear and ensures impersonation state is properly sandboxed by firewall name. This approach should correctly handle multiple firewalls.

src/Sylius/Bundle/CoreBundle/spec/EventListener/UserImpersonatorSubscriberSpec.php (1)

33-37: Good job addressing the previous review comment

This test for getSubscribedEvents() directly addresses the previous review comment requesting verification of the event subscription implementation.

@lusimeon lusimeon force-pushed the sylius-impersonator-voter branch 2 times, most recently from 30a944e to 1e49608 Compare March 20, 2025 10:08
Decorate Symfony AuthenticatedVoter to be able to check if customer is impersonated
@GSadee GSadee force-pushed the sylius-impersonator-voter branch from 1e49608 to 6e28f97 Compare June 3, 2025 12:53
@GSadee GSadee added Feature New feature proposals. DX Issues and PRs aimed at improving Developer eXperience. labels Jun 3, 2025
@GSadee GSadee merged commit 1803fa5 into Sylius:2.1 Jun 3, 2025
30 of 31 checks passed
@GSadee
Copy link
Member

GSadee commented Jun 3, 2025

Thank you @lusimeon! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DX Issues and PRs aimed at improving Developer eXperience. Feature New feature proposals.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow to know if a connected shop user is impersonated

3 participants