The start of something beautiful
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
<?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\Component\Security\Core\Authentication;
|
||||
|
||||
use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
|
||||
/**
|
||||
* The default implementation of the authentication trust resolver.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class AuthenticationTrustResolver implements AuthenticationTrustResolverInterface
|
||||
{
|
||||
public function isAuthenticated(?TokenInterface $token = null): bool
|
||||
{
|
||||
return $token && $token->getUser();
|
||||
}
|
||||
|
||||
public function isRememberMe(?TokenInterface $token = null): bool
|
||||
{
|
||||
return $token && $token instanceof RememberMeToken;
|
||||
}
|
||||
|
||||
public function isFullFledged(?TokenInterface $token = null): bool
|
||||
{
|
||||
return $this->isAuthenticated($token) && !$this->isRememberMe($token);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
<?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\Component\Security\Core\Authentication;
|
||||
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
|
||||
/**
|
||||
* Interface for resolving the authentication status of a given token.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
interface AuthenticationTrustResolverInterface
|
||||
{
|
||||
/**
|
||||
* Resolves whether the passed token implementation is authenticated.
|
||||
*/
|
||||
public function isAuthenticated(?TokenInterface $token = null): bool;
|
||||
|
||||
/**
|
||||
* Resolves whether the passed token implementation is authenticated
|
||||
* using remember-me capabilities.
|
||||
*/
|
||||
public function isRememberMe(?TokenInterface $token = null): bool;
|
||||
|
||||
/**
|
||||
* Resolves whether the passed token implementation is fully authenticated.
|
||||
*/
|
||||
public function isFullFledged(?TokenInterface $token = null): bool;
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
<?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\Component\Security\Core\Authentication\RememberMe;
|
||||
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class CacheTokenVerifier implements TokenVerifierInterface
|
||||
{
|
||||
private CacheItemPoolInterface $cache;
|
||||
private int $outdatedTokenTtl;
|
||||
private string $cacheKeyPrefix;
|
||||
|
||||
/**
|
||||
* @param int $outdatedTokenTtl How long the outdated token should still be considered valid. Defaults
|
||||
* to 60, which matches how often the PersistentRememberMeHandler will at
|
||||
* most refresh tokens. Increasing to more than that is not recommended,
|
||||
* but you may use a lower value.
|
||||
*/
|
||||
public function __construct(CacheItemPoolInterface $cache, int $outdatedTokenTtl = 60, string $cacheKeyPrefix = 'rememberme-stale-')
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->outdatedTokenTtl = $outdatedTokenTtl;
|
||||
$this->cacheKeyPrefix = $cacheKeyPrefix;
|
||||
}
|
||||
|
||||
public function verifyToken(PersistentTokenInterface $token, #[\SensitiveParameter] string $tokenValue): bool
|
||||
{
|
||||
if (hash_equals($token->getTokenValue(), $tokenValue)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$cacheKey = $this->getCacheKey($token);
|
||||
$item = $this->cache->getItem($cacheKey);
|
||||
if (!$item->isHit()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$outdatedToken = $item->get();
|
||||
|
||||
return hash_equals($outdatedToken, $tokenValue);
|
||||
}
|
||||
|
||||
public function updateExistingToken(PersistentTokenInterface $token, #[\SensitiveParameter] string $tokenValue, \DateTimeInterface $lastUsed): void
|
||||
{
|
||||
// When a token gets updated, persist the outdated token for $outdatedTokenTtl seconds so we can
|
||||
// still accept it as valid in verifyToken
|
||||
$item = $this->cache->getItem($this->getCacheKey($token));
|
||||
$item->set($token->getTokenValue());
|
||||
$item->expiresAfter($this->outdatedTokenTtl);
|
||||
$this->cache->save($item);
|
||||
}
|
||||
|
||||
private function getCacheKey(PersistentTokenInterface $token): string
|
||||
{
|
||||
return $this->cacheKeyPrefix.rawurlencode($token->getSeries());
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
<?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\Component\Security\Core\Authentication\RememberMe;
|
||||
|
||||
use Symfony\Component\Security\Core\Exception\TokenNotFoundException;
|
||||
|
||||
/**
|
||||
* This class is used for testing purposes, and is not really suited for production.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
final class InMemoryTokenProvider implements TokenProviderInterface
|
||||
{
|
||||
private array $tokens = [];
|
||||
|
||||
public function loadTokenBySeries(string $series): PersistentTokenInterface
|
||||
{
|
||||
if (!isset($this->tokens[$series])) {
|
||||
throw new TokenNotFoundException('No token found.');
|
||||
}
|
||||
|
||||
return $this->tokens[$series];
|
||||
}
|
||||
|
||||
public function updateToken(string $series, #[\SensitiveParameter] string $tokenValue, \DateTimeInterface $lastUsed): void
|
||||
{
|
||||
if (!isset($this->tokens[$series])) {
|
||||
throw new TokenNotFoundException('No token found.');
|
||||
}
|
||||
|
||||
$token = new PersistentToken(
|
||||
$this->tokens[$series]->getClass(),
|
||||
$this->tokens[$series]->getUserIdentifier(),
|
||||
$series,
|
||||
$tokenValue,
|
||||
$lastUsed
|
||||
);
|
||||
$this->tokens[$series] = $token;
|
||||
}
|
||||
|
||||
public function deleteTokenBySeries(string $series): void
|
||||
{
|
||||
unset($this->tokens[$series]);
|
||||
}
|
||||
|
||||
public function createNewToken(PersistentTokenInterface $token): void
|
||||
{
|
||||
$this->tokens[$token->getSeries()] = $token;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?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\Component\Security\Core\Authentication\RememberMe;
|
||||
|
||||
/**
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class PersistentToken implements PersistentTokenInterface
|
||||
{
|
||||
private string $class;
|
||||
private string $userIdentifier;
|
||||
private string $series;
|
||||
private string $tokenValue;
|
||||
private \DateTimeImmutable $lastUsed;
|
||||
|
||||
public function __construct(string $class, string $userIdentifier, string $series, #[\SensitiveParameter] string $tokenValue, \DateTimeInterface $lastUsed)
|
||||
{
|
||||
if (!$class) {
|
||||
throw new \InvalidArgumentException('$class must not be empty.');
|
||||
}
|
||||
if ('' === $userIdentifier) {
|
||||
throw new \InvalidArgumentException('$userIdentifier must not be empty.');
|
||||
}
|
||||
if (!$series) {
|
||||
throw new \InvalidArgumentException('$series must not be empty.');
|
||||
}
|
||||
if (!$tokenValue) {
|
||||
throw new \InvalidArgumentException('$tokenValue must not be empty.');
|
||||
}
|
||||
|
||||
$this->class = $class;
|
||||
$this->userIdentifier = $userIdentifier;
|
||||
$this->series = $series;
|
||||
$this->tokenValue = $tokenValue;
|
||||
$this->lastUsed = \DateTimeImmutable::createFromInterface($lastUsed);
|
||||
}
|
||||
|
||||
public function getClass(): string
|
||||
{
|
||||
return $this->class;
|
||||
}
|
||||
|
||||
public function getUserIdentifier(): string
|
||||
{
|
||||
return $this->userIdentifier;
|
||||
}
|
||||
|
||||
public function getSeries(): string
|
||||
{
|
||||
return $this->series;
|
||||
}
|
||||
|
||||
public function getTokenValue(): string
|
||||
{
|
||||
return $this->tokenValue;
|
||||
}
|
||||
|
||||
public function getLastUsed(): \DateTime
|
||||
{
|
||||
return \DateTime::createFromImmutable($this->lastUsed);
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
<?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\Component\Security\Core\Authentication\RememberMe;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by persistent token classes (such as
|
||||
* Doctrine entities representing a remember-me token).
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
interface PersistentTokenInterface
|
||||
{
|
||||
/**
|
||||
* Returns the class of the user.
|
||||
*/
|
||||
public function getClass(): string;
|
||||
|
||||
/**
|
||||
* Returns the series.
|
||||
*/
|
||||
public function getSeries(): string;
|
||||
|
||||
/**
|
||||
* Returns the token value.
|
||||
*/
|
||||
public function getTokenValue(): string;
|
||||
|
||||
/**
|
||||
* Returns the time the token was last used.
|
||||
*
|
||||
* Each call SHOULD return a new distinct DateTime instance.
|
||||
*/
|
||||
public function getLastUsed(): \DateTime;
|
||||
|
||||
/**
|
||||
* Returns the identifier used to authenticate (e.g. their email address or username).
|
||||
*/
|
||||
public function getUserIdentifier(): string;
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
<?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\Component\Security\Core\Authentication\RememberMe;
|
||||
|
||||
use Symfony\Component\Security\Core\Exception\TokenNotFoundException;
|
||||
|
||||
/**
|
||||
* Interface for TokenProviders.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
interface TokenProviderInterface
|
||||
{
|
||||
/**
|
||||
* Loads the active token for the given series.
|
||||
*
|
||||
* @return PersistentTokenInterface
|
||||
*
|
||||
* @throws TokenNotFoundException if the token is not found
|
||||
*/
|
||||
public function loadTokenBySeries(string $series);
|
||||
|
||||
/**
|
||||
* Deletes all tokens belonging to series.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deleteTokenBySeries(string $series);
|
||||
|
||||
/**
|
||||
* Updates the token according to this data.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws TokenNotFoundException if the token is not found
|
||||
*/
|
||||
public function updateToken(string $series, #[\SensitiveParameter] string $tokenValue, \DateTimeInterface $lastUsed);
|
||||
|
||||
/**
|
||||
* Creates a new token.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function createNewToken(PersistentTokenInterface $token);
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
<?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\Component\Security\Core\Authentication\RememberMe;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
interface TokenVerifierInterface
|
||||
{
|
||||
/**
|
||||
* Verifies that the given $token is valid.
|
||||
*
|
||||
* This lets you override the token check logic to for example accept slightly outdated tokens.
|
||||
*
|
||||
* Do not forget to implement token comparisons using hash_equals for a secure implementation.
|
||||
*/
|
||||
public function verifyToken(PersistentTokenInterface $token, #[\SensitiveParameter] string $tokenValue): bool;
|
||||
|
||||
/**
|
||||
* Updates an existing token with a new token value and lastUsed time.
|
||||
*/
|
||||
public function updateExistingToken(PersistentTokenInterface $token, #[\SensitiveParameter] string $tokenValue, \DateTimeInterface $lastUsed): void;
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
<?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\Component\Security\Core\Authentication\Token;
|
||||
|
||||
use Symfony\Component\Security\Core\User\InMemoryUser;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
/**
|
||||
* Base class for Token instances.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
abstract class AbstractToken implements TokenInterface, \Serializable
|
||||
{
|
||||
private ?UserInterface $user = null;
|
||||
private array $roleNames = [];
|
||||
private array $attributes = [];
|
||||
|
||||
/**
|
||||
* @param string[] $roles An array of roles
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function __construct(array $roles = [])
|
||||
{
|
||||
foreach ($roles as $role) {
|
||||
$this->roleNames[] = $role;
|
||||
}
|
||||
}
|
||||
|
||||
public function getRoleNames(): array
|
||||
{
|
||||
return $this->roleNames;
|
||||
}
|
||||
|
||||
public function getUserIdentifier(): string
|
||||
{
|
||||
return $this->user ? $this->user->getUserIdentifier() : '';
|
||||
}
|
||||
|
||||
public function getUser(): ?UserInterface
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
public function setUser(UserInterface $user): void
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
public function eraseCredentials(): void
|
||||
{
|
||||
if ($this->getUser() instanceof UserInterface) {
|
||||
$this->getUser()->eraseCredentials();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the necessary state of the object for serialization purposes.
|
||||
*
|
||||
* There is no need to serialize any entry, they should be returned as-is.
|
||||
* If you extend this method, keep in mind you MUST guarantee parent data is present in the state.
|
||||
* Here is an example of how to extend this method:
|
||||
* <code>
|
||||
* public function __serialize(): array
|
||||
* {
|
||||
* return [$this->childAttribute, parent::__serialize()];
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @see __unserialize()
|
||||
*/
|
||||
public function __serialize(): array
|
||||
{
|
||||
return [$this->user, true, null, $this->attributes, $this->roleNames];
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the object state from an array given by __serialize().
|
||||
*
|
||||
* There is no need to unserialize any entry in $data, they are already ready-to-use.
|
||||
* If you extend this method, keep in mind you MUST pass the parent data to its respective class.
|
||||
* Here is an example of how to extend this method:
|
||||
* <code>
|
||||
* public function __unserialize(array $data): void
|
||||
* {
|
||||
* [$this->childAttribute, $parentData] = $data;
|
||||
* parent::__unserialize($parentData);
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @see __serialize()
|
||||
*/
|
||||
public function __unserialize(array $data): void
|
||||
{
|
||||
[$user, , , $this->attributes, $this->roleNames] = $data;
|
||||
$this->user = \is_string($user) ? new InMemoryUser($user, '', $this->roleNames, false) : $user;
|
||||
}
|
||||
|
||||
public function getAttributes(): array
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
public function setAttributes(array $attributes): void
|
||||
{
|
||||
$this->attributes = $attributes;
|
||||
}
|
||||
|
||||
public function hasAttribute(string $name): bool
|
||||
{
|
||||
return \array_key_exists($name, $this->attributes);
|
||||
}
|
||||
|
||||
public function getAttribute(string $name): mixed
|
||||
{
|
||||
if (!\array_key_exists($name, $this->attributes)) {
|
||||
throw new \InvalidArgumentException(sprintf('This token has no "%s" attribute.', $name));
|
||||
}
|
||||
|
||||
return $this->attributes[$name];
|
||||
}
|
||||
|
||||
public function setAttribute(string $name, mixed $value): void
|
||||
{
|
||||
$this->attributes[$name] = $value;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
$class = static::class;
|
||||
$class = substr($class, strrpos($class, '\\') + 1);
|
||||
|
||||
$roles = [];
|
||||
foreach ($this->roleNames as $role) {
|
||||
$roles[] = $role;
|
||||
}
|
||||
|
||||
return sprintf('%s(user="%s", roles="%s")', $class, $this->getUserIdentifier(), implode(', ', $roles));
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final public function serialize(): string
|
||||
{
|
||||
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final public function unserialize(string $serialized): void
|
||||
{
|
||||
$this->__unserialize(unserialize($serialized));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?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\Component\Security\Core\Authentication\Token;
|
||||
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
/**
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*/
|
||||
class NullToken implements TokenInterface
|
||||
{
|
||||
public function __toString(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getRoleNames(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getUser(): ?UserInterface
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function setUser(UserInterface $user): never
|
||||
{
|
||||
throw new \BadMethodCallException('Cannot set user on a NullToken.');
|
||||
}
|
||||
|
||||
public function getUserIdentifier(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function eraseCredentials(): void
|
||||
{
|
||||
}
|
||||
|
||||
public function getAttributes(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function setAttributes(array $attributes): never
|
||||
{
|
||||
throw new \BadMethodCallException('Cannot set attributes of NullToken.');
|
||||
}
|
||||
|
||||
public function hasAttribute(string $name): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getAttribute(string $name): mixed
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function setAttribute(string $name, mixed $value): never
|
||||
{
|
||||
throw new \BadMethodCallException('Cannot add attribute to NullToken.');
|
||||
}
|
||||
|
||||
public function __serialize(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function __unserialize(array $data): void
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?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\Component\Security\Core\Authentication\Token;
|
||||
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
/**
|
||||
* PreAuthenticatedToken implements a pre-authenticated token.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class PreAuthenticatedToken extends AbstractToken
|
||||
{
|
||||
private string $firewallName;
|
||||
|
||||
/**
|
||||
* @param string[] $roles
|
||||
*/
|
||||
public function __construct(UserInterface $user, string $firewallName, array $roles = [])
|
||||
{
|
||||
parent::__construct($roles);
|
||||
|
||||
if ('' === $firewallName) {
|
||||
throw new \InvalidArgumentException('$firewallName must not be empty.');
|
||||
}
|
||||
|
||||
$this->setUser($user);
|
||||
$this->firewallName = $firewallName;
|
||||
}
|
||||
|
||||
public function getFirewallName(): string
|
||||
{
|
||||
return $this->firewallName;
|
||||
}
|
||||
|
||||
public function __serialize(): array
|
||||
{
|
||||
return [null, $this->firewallName, parent::__serialize()];
|
||||
}
|
||||
|
||||
public function __unserialize(array $data): void
|
||||
{
|
||||
[, $this->firewallName, $parentData] = $data;
|
||||
$parentData = \is_array($parentData) ? $parentData : unserialize($parentData);
|
||||
parent::__unserialize($parentData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?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\Component\Security\Core\Authentication\Token;
|
||||
|
||||
use Symfony\Component\Security\Core\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
/**
|
||||
* Authentication Token for "Remember-Me".
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class RememberMeToken extends AbstractToken
|
||||
{
|
||||
private string $secret;
|
||||
private string $firewallName;
|
||||
|
||||
/**
|
||||
* @param string $secret A secret used to make sure the token is created by the app and not by a malicious client
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function __construct(UserInterface $user, string $firewallName, #[\SensitiveParameter] string $secret)
|
||||
{
|
||||
parent::__construct($user->getRoles());
|
||||
|
||||
if (!$secret) {
|
||||
throw new InvalidArgumentException('A non-empty secret is required.');
|
||||
}
|
||||
|
||||
if (!$firewallName) {
|
||||
throw new InvalidArgumentException('$firewallName must not be empty.');
|
||||
}
|
||||
|
||||
$this->firewallName = $firewallName;
|
||||
$this->secret = $secret;
|
||||
|
||||
$this->setUser($user);
|
||||
}
|
||||
|
||||
public function getFirewallName(): string
|
||||
{
|
||||
return $this->firewallName;
|
||||
}
|
||||
|
||||
public function getSecret(): string
|
||||
{
|
||||
return $this->secret;
|
||||
}
|
||||
|
||||
public function __serialize(): array
|
||||
{
|
||||
return [$this->secret, $this->firewallName, parent::__serialize()];
|
||||
}
|
||||
|
||||
public function __unserialize(array $data): void
|
||||
{
|
||||
[$this->secret, $this->firewallName, $parentData] = $data;
|
||||
$parentData = \is_array($parentData) ? $parentData : unserialize($parentData);
|
||||
parent::__unserialize($parentData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?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\Component\Security\Core\Authentication\Token\Storage;
|
||||
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Contracts\Service\ResetInterface;
|
||||
|
||||
/**
|
||||
* TokenStorage contains a TokenInterface.
|
||||
*
|
||||
* It gives access to the token representing the current user authentication.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class TokenStorage implements TokenStorageInterface, ResetInterface
|
||||
{
|
||||
private ?TokenInterface $token = null;
|
||||
private ?\Closure $initializer = null;
|
||||
|
||||
public function getToken(): ?TokenInterface
|
||||
{
|
||||
if ($initializer = $this->initializer) {
|
||||
$this->initializer = null;
|
||||
$initializer();
|
||||
}
|
||||
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
public function setToken(?TokenInterface $token): void
|
||||
{
|
||||
if ($token) {
|
||||
// ensure any initializer is called
|
||||
$this->getToken();
|
||||
}
|
||||
|
||||
$this->initializer = null;
|
||||
$this->token = $token;
|
||||
}
|
||||
|
||||
public function setInitializer(?callable $initializer): void
|
||||
{
|
||||
$this->initializer = null === $initializer ? null : $initializer(...);
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
$this->setToken(null);
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<?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\Component\Security\Core\Authentication\Token\Storage;
|
||||
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
|
||||
/**
|
||||
* The TokenStorageInterface.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
interface TokenStorageInterface
|
||||
{
|
||||
/**
|
||||
* Returns the current security token.
|
||||
*/
|
||||
public function getToken(): ?TokenInterface;
|
||||
|
||||
/**
|
||||
* Sets the authentication token.
|
||||
*
|
||||
* @param TokenInterface|null $token A TokenInterface token, or null if no further authentication information should be stored
|
||||
*/
|
||||
public function setToken(?TokenInterface $token): void;
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
<?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\Component\Security\Core\Authentication\Token\Storage;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Contracts\Service\ServiceSubscriberInterface;
|
||||
|
||||
/**
|
||||
* A token storage that increments the session usage index when the token is accessed.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
final class UsageTrackingTokenStorage implements TokenStorageInterface, ServiceSubscriberInterface
|
||||
{
|
||||
private TokenStorageInterface $storage;
|
||||
private ContainerInterface $container;
|
||||
private bool $enableUsageTracking = false;
|
||||
|
||||
public function __construct(TokenStorageInterface $storage, ContainerInterface $container)
|
||||
{
|
||||
$this->storage = $storage;
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function getToken(): ?TokenInterface
|
||||
{
|
||||
if ($this->shouldTrackUsage()) {
|
||||
// increments the internal session usage index
|
||||
$this->getSession()->getMetadataBag();
|
||||
}
|
||||
|
||||
return $this->storage->getToken();
|
||||
}
|
||||
|
||||
public function setToken(?TokenInterface $token = null): void
|
||||
{
|
||||
$this->storage->setToken($token);
|
||||
|
||||
if ($token && $this->shouldTrackUsage()) {
|
||||
// increments the internal session usage index
|
||||
$this->getSession()->getMetadataBag();
|
||||
}
|
||||
}
|
||||
|
||||
public function enableUsageTracking(): void
|
||||
{
|
||||
$this->enableUsageTracking = true;
|
||||
}
|
||||
|
||||
public function disableUsageTracking(): void
|
||||
{
|
||||
$this->enableUsageTracking = false;
|
||||
}
|
||||
|
||||
public static function getSubscribedServices(): array
|
||||
{
|
||||
return [
|
||||
'request_stack' => RequestStack::class,
|
||||
];
|
||||
}
|
||||
|
||||
private function getSession(): SessionInterface
|
||||
{
|
||||
return $this->container->get('request_stack')->getSession();
|
||||
}
|
||||
|
||||
private function shouldTrackUsage(): bool
|
||||
{
|
||||
return $this->enableUsageTracking && $this->container->get('request_stack')->getMainRequest();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?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\Component\Security\Core\Authentication\Token;
|
||||
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
/**
|
||||
* Token representing a user who temporarily impersonates another one.
|
||||
*
|
||||
* @author Christian Flothmann <christian.flothmann@sensiolabs.de>
|
||||
*/
|
||||
class SwitchUserToken extends UsernamePasswordToken
|
||||
{
|
||||
private TokenInterface $originalToken;
|
||||
private ?string $originatedFromUri = null;
|
||||
|
||||
/**
|
||||
* @param $user The username (like a nickname, email address, etc.), or a UserInterface instance or an object implementing a __toString method
|
||||
* @param $originatedFromUri The URI where was the user at the switch
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function __construct(UserInterface $user, string $firewallName, array $roles, TokenInterface $originalToken, ?string $originatedFromUri = null)
|
||||
{
|
||||
parent::__construct($user, $firewallName, $roles);
|
||||
|
||||
$this->originalToken = $originalToken;
|
||||
$this->originatedFromUri = $originatedFromUri;
|
||||
}
|
||||
|
||||
public function getOriginalToken(): TokenInterface
|
||||
{
|
||||
return $this->originalToken;
|
||||
}
|
||||
|
||||
public function getOriginatedFromUri(): ?string
|
||||
{
|
||||
return $this->originatedFromUri;
|
||||
}
|
||||
|
||||
public function __serialize(): array
|
||||
{
|
||||
return [$this->originalToken, $this->originatedFromUri, parent::__serialize()];
|
||||
}
|
||||
|
||||
public function __unserialize(array $data): void
|
||||
{
|
||||
if (3 > \count($data)) {
|
||||
// Support for tokens serialized with version 5.1 or lower of symfony/security-core.
|
||||
[$this->originalToken, $parentData] = $data;
|
||||
} else {
|
||||
[$this->originalToken, $this->originatedFromUri, $parentData] = $data;
|
||||
}
|
||||
$parentData = \is_array($parentData) ? $parentData : unserialize($parentData);
|
||||
parent::__unserialize($parentData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?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\Component\Security\Core\Authentication\Token;
|
||||
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
/**
|
||||
* TokenInterface is the interface for the user authentication information.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
interface TokenInterface extends \Stringable
|
||||
{
|
||||
/**
|
||||
* Returns a string representation of the Token.
|
||||
*
|
||||
* This is only to be used for debugging purposes.
|
||||
*/
|
||||
public function __toString(): string;
|
||||
|
||||
/**
|
||||
* Returns the user identifier used during authentication (e.g. a user's email address or username).
|
||||
*/
|
||||
public function getUserIdentifier(): string;
|
||||
|
||||
/**
|
||||
* Returns the user roles.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getRoleNames(): array;
|
||||
|
||||
/**
|
||||
* Returns a user representation.
|
||||
*
|
||||
* @see AbstractToken::setUser()
|
||||
*/
|
||||
public function getUser(): ?UserInterface;
|
||||
|
||||
/**
|
||||
* Sets the authenticated user in the token.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setUser(UserInterface $user): void;
|
||||
|
||||
/**
|
||||
* Removes sensitive information from the token.
|
||||
*/
|
||||
public function eraseCredentials(): void;
|
||||
|
||||
public function getAttributes(): array;
|
||||
|
||||
/**
|
||||
* @param array $attributes The token attributes
|
||||
*/
|
||||
public function setAttributes(array $attributes): void;
|
||||
|
||||
public function hasAttribute(string $name): bool;
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException When attribute doesn't exist for this token
|
||||
*/
|
||||
public function getAttribute(string $name): mixed;
|
||||
|
||||
public function setAttribute(string $name, mixed $value): void;
|
||||
|
||||
/**
|
||||
* Returns all the necessary state of the object for serialization purposes.
|
||||
*/
|
||||
public function __serialize(): array;
|
||||
|
||||
/**
|
||||
* Restores the object state from an array given by __serialize().
|
||||
*/
|
||||
public function __unserialize(array $data): void;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?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\Component\Security\Core\Authentication\Token;
|
||||
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
/**
|
||||
* UsernamePasswordToken implements a username and password token.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class UsernamePasswordToken extends AbstractToken
|
||||
{
|
||||
private string $firewallName;
|
||||
|
||||
public function __construct(UserInterface $user, string $firewallName, array $roles = [])
|
||||
{
|
||||
parent::__construct($roles);
|
||||
|
||||
if ('' === $firewallName) {
|
||||
throw new \InvalidArgumentException('$firewallName must not be empty.');
|
||||
}
|
||||
|
||||
$this->setUser($user);
|
||||
$this->firewallName = $firewallName;
|
||||
}
|
||||
|
||||
public function getFirewallName(): string
|
||||
{
|
||||
return $this->firewallName;
|
||||
}
|
||||
|
||||
public function __serialize(): array
|
||||
{
|
||||
return [null, $this->firewallName, parent::__serialize()];
|
||||
}
|
||||
|
||||
public function __unserialize(array $data): void
|
||||
{
|
||||
[, $this->firewallName, $parentData] = $data;
|
||||
$parentData = \is_array($parentData) ? $parentData : unserialize($parentData);
|
||||
parent::__unserialize($parentData);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user