vendor/symfony/security-core/Authentication/Token/AbstractToken.php line 335

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Security\Core\Authentication\Token;
  11. use Symfony\Component\Security\Core\Role\Role;
  12. use Symfony\Component\Security\Core\User\AdvancedUserInterface;
  13. use Symfony\Component\Security\Core\User\EquatableInterface;
  14. use Symfony\Component\Security\Core\User\UserInterface;
  15. /**
  16.  * Base class for Token instances.
  17.  *
  18.  * @author Fabien Potencier <fabien@symfony.com>
  19.  * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  20.  */
  21. abstract class AbstractToken implements TokenInterface
  22. {
  23.     private $user;
  24.     private $roles = [];
  25.     private $roleNames = [];
  26.     private $authenticated false;
  27.     private $attributes = [];
  28.     /**
  29.      * @param string[] $roles An array of roles
  30.      *
  31.      * @throws \InvalidArgumentException
  32.      */
  33.     public function __construct(array $roles = [])
  34.     {
  35.         foreach ($roles as $role) {
  36.             if (\is_string($role)) {
  37.                 $role = new Role($rolefalse);
  38.             } elseif (!$role instanceof Role) {
  39.                 throw new \InvalidArgumentException(sprintf('$roles must be an array of strings, but got "%s".', \gettype($role)));
  40.             }
  41.             $this->roles[] = $role;
  42.             $this->roleNames[] = (string) $role;
  43.         }
  44.     }
  45.     public function getRoleNames(): array
  46.     {
  47.         return $this->roleNames;
  48.     }
  49.     /**
  50.      * {@inheritdoc}
  51.      */
  52.     public function getRoles()
  53.     {
  54.         if (=== \func_num_args() || func_get_arg(0)) {
  55.             @trigger_error(sprintf('The %s() method is deprecated since Symfony 4.3. Use the getRoleNames() method instead.'__METHOD__), E_USER_DEPRECATED);
  56.         }
  57.         return $this->roles;
  58.     }
  59.     /**
  60.      * {@inheritdoc}
  61.      */
  62.     public function getUsername()
  63.     {
  64.         if ($this->user instanceof UserInterface) {
  65.             return $this->user->getUsername();
  66.         }
  67.         return (string) $this->user;
  68.     }
  69.     /**
  70.      * {@inheritdoc}
  71.      */
  72.     public function getUser()
  73.     {
  74.         return $this->user;
  75.     }
  76.     /**
  77.      * {@inheritdoc}
  78.      */
  79.     public function setUser($user)
  80.     {
  81.         if (!($user instanceof UserInterface || (\is_object($user) && method_exists($user'__toString')) || \is_string($user))) {
  82.             throw new \InvalidArgumentException('$user must be an instanceof UserInterface, an object implementing a __toString method, or a primitive string.');
  83.         }
  84.         if (null === $this->user) {
  85.             $changed false;
  86.         } elseif ($this->user instanceof UserInterface) {
  87.             if (!$user instanceof UserInterface) {
  88.                 $changed true;
  89.             } else {
  90.                 $changed $this->hasUserChanged($user);
  91.             }
  92.         } elseif ($user instanceof UserInterface) {
  93.             $changed true;
  94.         } else {
  95.             $changed = (string) $this->user !== (string) $user;
  96.         }
  97.         if ($changed) {
  98.             $this->setAuthenticated(false);
  99.         }
  100.         $this->user $user;
  101.     }
  102.     /**
  103.      * {@inheritdoc}
  104.      */
  105.     public function isAuthenticated()
  106.     {
  107.         return $this->authenticated;
  108.     }
  109.     /**
  110.      * {@inheritdoc}
  111.      */
  112.     public function setAuthenticated($authenticated)
  113.     {
  114.         $this->authenticated = (bool) $authenticated;
  115.     }
  116.     /**
  117.      * {@inheritdoc}
  118.      */
  119.     public function eraseCredentials()
  120.     {
  121.         if ($this->getUser() instanceof UserInterface) {
  122.             $this->getUser()->eraseCredentials();
  123.         }
  124.     }
  125.     /**
  126.      * Returns all the necessary state of the object for serialization purposes.
  127.      *
  128.      * There is no need to serialize any entry, they should be returned as-is.
  129.      * If you extend this method, keep in mind you MUST guarantee parent data is present in the state.
  130.      * Here is an example of how to extend this method:
  131.      * <code>
  132.      *     public function __serialize(): array
  133.      *     {
  134.      *         return [$this->childAttribute, parent::__serialize()];
  135.      *     }
  136.      * </code>
  137.      *
  138.      * @see __unserialize()
  139.      */
  140.     public function __serialize(): array
  141.     {
  142.         return [$this->user$this->authenticated$this->roles$this->attributes$this->roleNames];
  143.     }
  144.     /**
  145.      * @return string
  146.      *
  147.      * @final since Symfony 4.3, use __serialize() instead
  148.      *
  149.      * @internal since Symfony 4.3, use __serialize() instead
  150.      */
  151.     public function serialize()
  152.     {
  153.         $serialized $this->__serialize();
  154.         if (null === $isCalledFromOverridingMethod = \func_num_args() ? func_get_arg(0) : null) {
  155.             $trace debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT2);
  156.             $isCalledFromOverridingMethod = isset($trace[1]['function'], $trace[1]['object']) && 'serialize' === $trace[1]['function'] && $this === $trace[1]['object'];
  157.         }
  158.         return $isCalledFromOverridingMethod $serialized serialize($serialized);
  159.     }
  160.     /**
  161.      * Restores the object state from an array given by __serialize().
  162.      *
  163.      * There is no need to unserialize any entry in $data, they are already ready-to-use.
  164.      * If you extend this method, keep in mind you MUST pass the parent data to its respective class.
  165.      * Here is an example of how to extend this method:
  166.      * <code>
  167.      *     public function __unserialize(array $data): void
  168.      *     {
  169.      *         [$this->childAttribute, $parentData] = $data;
  170.      *         parent::__unserialize($parentData);
  171.      *     }
  172.      * </code>
  173.      *
  174.      * @see __serialize()
  175.      */
  176.     public function __unserialize(array $data): void
  177.     {
  178.         [$this->user$this->authenticated$this->roles$this->attributes] = $data;
  179.         // migration path to 4.3+
  180.         if (null === $this->roleNames $data[4] ?? null) {
  181.             $this->roleNames = [];
  182.             foreach ($this->roles as $role) {
  183.                 $this->roleNames[] = (string) $role;
  184.             }
  185.         }
  186.     }
  187.     /**
  188.      * {@inheritdoc}
  189.      *
  190.      * @final since Symfony 4.3, use __unserialize() instead
  191.      *
  192.      * @internal since Symfony 4.3, use __unserialize() instead
  193.      */
  194.     public function unserialize($serialized)
  195.     {
  196.         $this->__unserialize(\is_array($serialized) ? $serialized unserialize($serialized));
  197.     }
  198.     /**
  199.      * Returns the token attributes.
  200.      *
  201.      * @return array The token attributes
  202.      */
  203.     public function getAttributes()
  204.     {
  205.         return $this->attributes;
  206.     }
  207.     /**
  208.      * Sets the token attributes.
  209.      *
  210.      * @param array $attributes The token attributes
  211.      */
  212.     public function setAttributes(array $attributes)
  213.     {
  214.         $this->attributes $attributes;
  215.     }
  216.     /**
  217.      * Returns true if the attribute exists.
  218.      *
  219.      * @param string $name The attribute name
  220.      *
  221.      * @return bool true if the attribute exists, false otherwise
  222.      */
  223.     public function hasAttribute($name)
  224.     {
  225.         return \array_key_exists($name$this->attributes);
  226.     }
  227.     /**
  228.      * Returns an attribute value.
  229.      *
  230.      * @param string $name The attribute name
  231.      *
  232.      * @return mixed The attribute value
  233.      *
  234.      * @throws \InvalidArgumentException When attribute doesn't exist for this token
  235.      */
  236.     public function getAttribute($name)
  237.     {
  238.         if (!\array_key_exists($name$this->attributes)) {
  239.             throw new \InvalidArgumentException(sprintf('This token has no "%s" attribute.'$name));
  240.         }
  241.         return $this->attributes[$name];
  242.     }
  243.     /**
  244.      * Sets an attribute.
  245.      *
  246.      * @param string $name  The attribute name
  247.      * @param mixed  $value The attribute value
  248.      */
  249.     public function setAttribute($name$value)
  250.     {
  251.         $this->attributes[$name] = $value;
  252.     }
  253.     /**
  254.      * {@inheritdoc}
  255.      */
  256.     public function __toString()
  257.     {
  258.         $class = static::class;
  259.         $class substr($classstrrpos($class'\\') + 1);
  260.         $roles = [];
  261.         foreach ($this->roles as $role) {
  262.             $roles[] = $role->getRole();
  263.         }
  264.         return sprintf('%s(user="%s", authenticated=%s, roles="%s")'$class$this->getUsername(), json_encode($this->authenticated), implode(', '$roles));
  265.     }
  266.     private function hasUserChanged(UserInterface $user): bool
  267.     {
  268.         if (!($this->user instanceof UserInterface)) {
  269.             throw new \BadMethodCallException('Method "hasUserChanged" should be called when current user class is instance of "UserInterface".');
  270.         }
  271.         if ($this->user instanceof EquatableInterface) {
  272.             return !(bool) $this->user->isEqualTo($user);
  273.         }
  274.         if ($this->user->getPassword() !== $user->getPassword()) {
  275.             return true;
  276.         }
  277.         if ($this->user->getSalt() !== $user->getSalt()) {
  278.             return true;
  279.         }
  280.         $userRoles array_map('strval', (array) $user->getRoles());
  281.         if ($this instanceof SwitchUserToken) {
  282.             $userRoles[] = 'ROLE_PREVIOUS_ADMIN';
  283.         }
  284.         if (\count($userRoles) !== \count($this->getRoleNames()) || \count($userRoles) !== \count(array_intersect($userRoles$this->getRoleNames()))) {
  285.             return true;
  286.         }
  287.         if ($this->user->getUsername() !== $user->getUsername()) {
  288.             return true;
  289.         }
  290.         if ($this->user instanceof AdvancedUserInterface && $user instanceof AdvancedUserInterface) {
  291.             @trigger_error(sprintf('Checking for the AdvancedUserInterface in "%s()" is deprecated since Symfony 4.1 and support for it will be removed in 5.0. Implement the %s to check if the user has been changed,'__METHOD__EquatableInterface::class), E_USER_DEPRECATED);
  292.             if ($this->user->isAccountNonExpired() !== $user->isAccountNonExpired()) {
  293.                 return true;
  294.             }
  295.             if ($this->user->isAccountNonLocked() !== $user->isAccountNonLocked()) {
  296.                 return true;
  297.             }
  298.             if ($this->user->isCredentialsNonExpired() !== $user->isCredentialsNonExpired()) {
  299.                 return true;
  300.             }
  301.             if ($this->user->isEnabled() !== $user->isEnabled()) {
  302.                 return true;
  303.             }
  304.         } elseif ($this->user instanceof AdvancedUserInterface xor $user instanceof AdvancedUserInterface) {
  305.             @trigger_error(sprintf('Checking for the AdvancedUserInterface in "%s()" is deprecated since Symfony 4.1 and support for it will be removed in 5.0. Implement the %s to check if the user has been changed,'__METHOD__EquatableInterface::class), E_USER_DEPRECATED);
  306.             return true;
  307.         }
  308.         return false;
  309.     }
  310. }