- <?php
- /*
-  * This file is part of the Symfony package.
-  *
-  * (c) Fabien Potencier <fabien@symfony.com>
-  *
-  * For the full copyright and license information, please view the LICENSE
-  * file that was distributed with this source code.
-  */
- namespace Symfony\Bundle\SecurityBundle\DataCollector;
- use Symfony\Bundle\SecurityBundle\Debug\TraceableFirewallListener;
- use Symfony\Bundle\SecurityBundle\Security\FirewallMap;
- use Symfony\Component\HttpFoundation\Request;
- use Symfony\Component\HttpFoundation\Response;
- use Symfony\Component\HttpKernel\DataCollector\DataCollector;
- use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface;
- use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
- use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
- use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
- use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
- use Symfony\Component\Security\Core\Authorization\TraceableAccessDecisionManager;
- use Symfony\Component\Security\Core\Authorization\Voter\TraceableVoter;
- use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
- use Symfony\Component\Security\Http\Firewall\SwitchUserListener;
- use Symfony\Component\Security\Http\FirewallMapInterface;
- use Symfony\Component\Security\Http\Logout\LogoutUrlGenerator;
- use Symfony\Component\VarDumper\Caster\ClassStub;
- use Symfony\Component\VarDumper\Cloner\Data;
- /**
-  * @author Fabien Potencier <fabien@symfony.com>
-  *
-  * @final
-  */
- class SecurityDataCollector extends DataCollector implements LateDataCollectorInterface
- {
-     private $tokenStorage;
-     private $roleHierarchy;
-     private $logoutUrlGenerator;
-     private $accessDecisionManager;
-     private $firewallMap;
-     private $firewall;
-     private $hasVarDumper;
-     private $authenticatorManagerEnabled;
-     public function __construct(?TokenStorageInterface $tokenStorage = null, ?RoleHierarchyInterface $roleHierarchy = null, ?LogoutUrlGenerator $logoutUrlGenerator = null, ?AccessDecisionManagerInterface $accessDecisionManager = null, ?FirewallMapInterface $firewallMap = null, ?TraceableFirewallListener $firewall = null, bool $authenticatorManagerEnabled = false)
-     {
-         if (!$authenticatorManagerEnabled) {
-             trigger_deprecation('symfony/security-bundle', '5.4', 'Setting the $authenticatorManagerEnabled argument of "%s" to "false" is deprecated, use the new authenticator system instead.', __METHOD__);
-         }
-         $this->tokenStorage = $tokenStorage;
-         $this->roleHierarchy = $roleHierarchy;
-         $this->logoutUrlGenerator = $logoutUrlGenerator;
-         $this->accessDecisionManager = $accessDecisionManager;
-         $this->firewallMap = $firewallMap;
-         $this->firewall = $firewall;
-         $this->hasVarDumper = class_exists(ClassStub::class);
-         $this->authenticatorManagerEnabled = $authenticatorManagerEnabled;
-     }
-     /**
-      * {@inheritdoc}
-      */
-     public function collect(Request $request, Response $response, ?\Throwable $exception = null)
-     {
-         if (null === $this->tokenStorage) {
-             $this->data = [
-                 'enabled' => false,
-                 'authenticated' => false,
-                 'impersonated' => false,
-                 'impersonator_user' => null,
-                 'impersonation_exit_path' => null,
-                 'token' => null,
-                 'token_class' => null,
-                 'logout_url' => null,
-                 'user' => '',
-                 'roles' => [],
-                 'inherited_roles' => [],
-                 'supports_role_hierarchy' => null !== $this->roleHierarchy,
-             ];
-         } elseif (null === $token = $this->tokenStorage->getToken()) {
-             $this->data = [
-                 'enabled' => true,
-                 'authenticated' => false,
-                 'impersonated' => false,
-                 'impersonator_user' => null,
-                 'impersonation_exit_path' => null,
-                 'token' => null,
-                 'token_class' => null,
-                 'logout_url' => null,
-                 'user' => '',
-                 'roles' => [],
-                 'inherited_roles' => [],
-                 'supports_role_hierarchy' => null !== $this->roleHierarchy,
-             ];
-         } else {
-             $inheritedRoles = [];
-             $assignedRoles = $token->getRoleNames();
-             $impersonatorUser = null;
-             if ($token instanceof SwitchUserToken) {
-                 $originalToken = $token->getOriginalToken();
-                 // @deprecated since Symfony 5.3, change to $originalToken->getUserIdentifier() in 6.0
-                 $impersonatorUser = method_exists($originalToken, 'getUserIdentifier') ? $originalToken->getUserIdentifier() : $originalToken->getUsername();
-             }
-             if (null !== $this->roleHierarchy) {
-                 foreach ($this->roleHierarchy->getReachableRoleNames($assignedRoles) as $role) {
-                     if (!\in_array($role, $assignedRoles, true)) {
-                         $inheritedRoles[] = $role;
-                     }
-                 }
-             }
-             $logoutUrl = null;
-             try {
-                 if (null !== $this->logoutUrlGenerator && !$token instanceof AnonymousToken) {
-                     $logoutUrl = $this->logoutUrlGenerator->getLogoutPath();
-                 }
-             } catch (\Exception $e) {
-                 // fail silently when the logout URL cannot be generated
-             }
-             $this->data = [
-                 'enabled' => true,
-                 'authenticated' => method_exists($token, 'isAuthenticated') ? $token->isAuthenticated(false) : (bool) $token->getUser(),
-                 'impersonated' => null !== $impersonatorUser,
-                 'impersonator_user' => $impersonatorUser,
-                 'impersonation_exit_path' => null,
-                 'token' => $token,
-                 'token_class' => $this->hasVarDumper ? new ClassStub(\get_class($token)) : \get_class($token),
-                 'logout_url' => $logoutUrl,
-                 // @deprecated since Symfony 5.3, change to $token->getUserIdentifier() in 6.0
-                 'user' => method_exists($token, 'getUserIdentifier') ? $token->getUserIdentifier() : $token->getUsername(),
-                 'roles' => $assignedRoles,
-                 'inherited_roles' => array_unique($inheritedRoles),
-                 'supports_role_hierarchy' => null !== $this->roleHierarchy,
-             ];
-         }
-         // collect voters and access decision manager information
-         if ($this->accessDecisionManager instanceof TraceableAccessDecisionManager) {
-             $this->data['voter_strategy'] = $this->accessDecisionManager->getStrategy();
-             $this->data['voters'] = [];
-             foreach ($this->accessDecisionManager->getVoters() as $voter) {
-                 if ($voter instanceof TraceableVoter) {
-                     $voter = $voter->getDecoratedVoter();
-                 }
-                 $this->data['voters'][] = $this->hasVarDumper ? new ClassStub(\get_class($voter)) : \get_class($voter);
-             }
-             // collect voter details
-             $decisionLog = $this->accessDecisionManager->getDecisionLog();
-             foreach ($decisionLog as $key => $log) {
-                 $decisionLog[$key]['voter_details'] = [];
-                 foreach ($log['voterDetails'] as $voterDetail) {
-                     $voterClass = \get_class($voterDetail['voter']);
-                     $classData = $this->hasVarDumper ? new ClassStub($voterClass) : $voterClass;
-                     $decisionLog[$key]['voter_details'][] = [
-                         'class' => $classData,
-                         'attributes' => $voterDetail['attributes'], // Only displayed for unanimous strategy
-                         'vote' => $voterDetail['vote'],
-                     ];
-                 }
-                 unset($decisionLog[$key]['voterDetails']);
-             }
-             $this->data['access_decision_log'] = $decisionLog;
-         } else {
-             $this->data['access_decision_log'] = [];
-             $this->data['voter_strategy'] = 'unknown';
-             $this->data['voters'] = [];
-         }
-         // collect firewall context information
-         $this->data['firewall'] = null;
-         if ($this->firewallMap instanceof FirewallMap) {
-             $firewallConfig = $this->firewallMap->getFirewallConfig($request);
-             if (null !== $firewallConfig) {
-                 $this->data['firewall'] = [
-                     'name' => $firewallConfig->getName(),
-                     'allows_anonymous' => $this->authenticatorManagerEnabled ? false : $firewallConfig->allowsAnonymous(),
-                     'request_matcher' => $firewallConfig->getRequestMatcher(),
-                     'security_enabled' => $firewallConfig->isSecurityEnabled(),
-                     'stateless' => $firewallConfig->isStateless(),
-                     'provider' => $firewallConfig->getProvider(),
-                     'context' => $firewallConfig->getContext(),
-                     'entry_point' => $firewallConfig->getEntryPoint(),
-                     'access_denied_handler' => $firewallConfig->getAccessDeniedHandler(),
-                     'access_denied_url' => $firewallConfig->getAccessDeniedUrl(),
-                     'user_checker' => $firewallConfig->getUserChecker(),
-                 ];
-                 // in 6.0, always fill `$this->data['authenticators'] only
-                 if ($this->authenticatorManagerEnabled) {
-                     $this->data['firewall']['authenticators'] = $firewallConfig->getAuthenticators();
-                 } else {
-                     $this->data['firewall']['listeners'] = $firewallConfig->getAuthenticators();
-                 }
-                 // generate exit impersonation path from current request
-                 if ($this->data['impersonated'] && null !== $switchUserConfig = $firewallConfig->getSwitchUser()) {
-                     $exitPath = $request->getRequestUri();
-                     $exitPath .= null === $request->getQueryString() ? '?' : '&';
-                     $exitPath .= sprintf('%s=%s', urlencode($switchUserConfig['parameter']), SwitchUserListener::EXIT_VALUE);
-                     $this->data['impersonation_exit_path'] = $exitPath;
-                 }
-             }
-         }
-         // collect firewall listeners information
-         $this->data['listeners'] = [];
-         if ($this->firewall) {
-             $this->data['listeners'] = $this->firewall->getWrappedListeners();
-         }
-         $this->data['authenticator_manager_enabled'] = $this->authenticatorManagerEnabled;
-         $this->data['authenticators'] = $this->firewall ? $this->firewall->getAuthenticatorsInfo() : [];
-     }
-     /**
-      * {@inheritdoc}
-      */
-     public function reset()
-     {
-         $this->data = [];
-     }
-     public function lateCollect()
-     {
-         $this->data = $this->cloneVar($this->data);
-     }
-     /**
-      * Checks if security is enabled.
-      */
-     public function isEnabled(): bool
-     {
-         return $this->data['enabled'];
-     }
-     /**
-      * Gets the user.
-      */
-     public function getUser(): string
-     {
-         return $this->data['user'];
-     }
-     /**
-      * Gets the roles of the user.
-      *
-      * @return array|Data
-      */
-     public function getRoles()
-     {
-         return $this->data['roles'];
-     }
-     /**
-      * Gets the inherited roles of the user.
-      *
-      * @return array|Data
-      */
-     public function getInheritedRoles()
-     {
-         return $this->data['inherited_roles'];
-     }
-     /**
-      * Checks if the data contains information about inherited roles. Still the inherited
-      * roles can be an empty array.
-      */
-     public function supportsRoleHierarchy(): bool
-     {
-         return $this->data['supports_role_hierarchy'];
-     }
-     /**
-      * Checks if the user is authenticated or not.
-      */
-     public function isAuthenticated(): bool
-     {
-         return $this->data['authenticated'];
-     }
-     public function isImpersonated(): bool
-     {
-         return $this->data['impersonated'];
-     }
-     public function getImpersonatorUser(): ?string
-     {
-         return $this->data['impersonator_user'];
-     }
-     public function getImpersonationExitPath(): ?string
-     {
-         return $this->data['impersonation_exit_path'];
-     }
-     /**
-      * Get the class name of the security token.
-      *
-      * @return string|Data|null
-      */
-     public function getTokenClass()
-     {
-         return $this->data['token_class'];
-     }
-     /**
-      * Get the full security token class as Data object.
-      */
-     public function getToken(): ?Data
-     {
-         return $this->data['token'];
-     }
-     /**
-      * Get the logout URL.
-      */
-     public function getLogoutUrl(): ?string
-     {
-         return $this->data['logout_url'];
-     }
-     /**
-      * Returns the FQCN of the security voters enabled in the application.
-      *
-      * @return string[]|Data
-      */
-     public function getVoters()
-     {
-         return $this->data['voters'];
-     }
-     /**
-      * Returns the strategy configured for the security voters.
-      */
-     public function getVoterStrategy(): string
-     {
-         return $this->data['voter_strategy'];
-     }
-     /**
-      * Returns the log of the security decisions made by the access decision manager.
-      *
-      * @return array|Data
-      */
-     public function getAccessDecisionLog()
-     {
-         return $this->data['access_decision_log'];
-     }
-     /**
-      * Returns the configuration of the current firewall context.
-      *
-      * @return array|Data|null
-      */
-     public function getFirewall()
-     {
-         return $this->data['firewall'];
-     }
-     /**
-      * @return array|Data
-      */
-     public function getListeners()
-     {
-         return $this->data['listeners'];
-     }
-     /**
-      * @return array|Data
-      */
-     public function getAuthenticators()
-     {
-         return $this->data['authenticators'];
-     }
-     /**
-      * {@inheritdoc}
-      */
-     public function getName(): string
-     {
-         return 'security';
-     }
-     public function isAuthenticatorManagerEnabled(): bool
-     {
-         return $this->data['authenticator_manager_enabled'];
-     }
- }
-