summaryrefslogtreecommitdiffstats
path: root/Core
diff options
context:
space:
mode:
authorJohannes M. Schmitt <schmittjoh@gmail.com>2011-01-26 21:34:11 +0100
committerFabien Potencier <fabien.potencier@gmail.com>2011-01-26 22:23:20 +0100
commitbebc09870cb0a7720e2c6a8c5c74585e69e8bb24 (patch)
tree0c399647cdbe504be405017e7cc04c70c53482f2 /Core
parentc85f3d708d2c9b00d73ca1234ccfaf50336d94b1 (diff)
downloadsymfony-security-bebc09870cb0a7720e2c6a8c5c74585e69e8bb24.zip
symfony-security-bebc09870cb0a7720e2c6a8c5c74585e69e8bb24.tar.gz
symfony-security-bebc09870cb0a7720e2c6a8c5c74585e69e8bb24.tar.bz2
namespace changes
Symfony\Component\Security -> Symfony\Component\Security\Core Symfony\Component\Security\Acl remains unchanged Symfony\Component\HttpKernel\Security -> Symfony\Component\Security\Http
Diffstat (limited to 'Core')
-rw-r--r--Core/Authentication/AuthenticationManagerInterface.php35
-rw-r--r--Core/Authentication/AuthenticationProviderManager.php120
-rw-r--r--Core/Authentication/AuthenticationTrustResolver.php75
-rw-r--r--Core/Authentication/AuthenticationTrustResolverInterface.php53
-rw-r--r--Core/Authentication/EntryPoint/AuthenticationEntryPointInterface.php32
-rw-r--r--Core/Authentication/Provider/AnonymousAuthenticationProvider.php60
-rw-r--r--Core/Authentication/Provider/AuthenticationProviderInterface.php35
-rw-r--r--Core/Authentication/Provider/DaoAuthenticationProvider.php95
-rw-r--r--Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php81
-rw-r--r--Core/Authentication/Provider/RememberMeAuthenticationProvider.php45
-rw-r--r--Core/Authentication/Provider/UserAuthenticationProvider.php113
-rw-r--r--Core/Authentication/RememberMe/InMemoryTokenProvider.php50
-rw-r--r--Core/Authentication/RememberMe/PersistentToken.php107
-rw-r--r--Core/Authentication/RememberMe/PersistentTokenInterface.php45
-rw-r--r--Core/Authentication/RememberMe/TokenProviderInterface.php51
-rw-r--r--Core/Authentication/Token/AnonymousToken.php58
-rw-r--r--Core/Authentication/Token/PreAuthenticatedToken.php52
-rw-r--r--Core/Authentication/Token/RememberMeToken.php75
-rw-r--r--Core/Authentication/Token/Token.php199
-rw-r--r--Core/Authentication/Token/TokenInterface.php102
-rw-r--r--Core/Authentication/Token/UsernamePasswordToken.php66
-rw-r--r--Core/Authorization/AccessDecisionManager.php240
-rw-r--r--Core/Authorization/AccessDecisionManagerInterface.php51
-rw-r--r--Core/Authorization/Voter/AuthenticatedVoter.php96
-rw-r--r--Core/Authorization/Voter/RoleHierarchyVoter.php41
-rw-r--r--Core/Authorization/Voter/RoleVoter.php79
-rw-r--r--Core/Authorization/Voter/VoterInterface.php58
-rw-r--r--Core/Encoder/BasePasswordEncoder.php91
-rw-r--r--Core/Encoder/EncoderFactory.php77
-rw-r--r--Core/Encoder/EncoderFactoryInterface.php30
-rw-r--r--Core/Encoder/MessageDigestPasswordEncoder.php65
-rw-r--r--Core/Encoder/PasswordEncoderInterface.php41
-rw-r--r--Core/Encoder/PlaintextPasswordEncoder.php49
-rw-r--r--Core/Exception/AccessDeniedException.php25
-rw-r--r--Core/Exception/AccountExpiredException.php21
-rw-r--r--Core/Exception/AccountStatusException.php22
-rw-r--r--Core/Exception/AuthenticationCredentialsNotFoundException.php22
-rw-r--r--Core/Exception/AuthenticationException.php39
-rw-r--r--Core/Exception/AuthenticationServiceException.php21
-rw-r--r--Core/Exception/BadCredentialsException.php25
-rw-r--r--Core/Exception/CookieTheftException.php22
-rw-r--r--Core/Exception/CredentialsExpiredException.php21
-rw-r--r--Core/Exception/DisabledException.php21
-rw-r--r--Core/Exception/InsufficientAuthenticationException.php23
-rw-r--r--Core/Exception/LockedException.php21
-rw-r--r--Core/Exception/NonceExpiredException.php27
-rw-r--r--Core/Exception/ProviderNotFoundException.php22
-rw-r--r--Core/Exception/TokenNotFoundException.php20
-rw-r--r--Core/Exception/UnsupportedAccountException.php22
-rw-r--r--Core/Exception/UsernameNotFoundException.php21
-rw-r--r--Core/Role/Role.php41
-rw-r--r--Core/Role/RoleHierarchy.php77
-rw-r--r--Core/Role/RoleHierarchyInterface.php32
-rw-r--r--Core/Role/RoleInterface.php35
-rw-r--r--Core/Role/SwitchUserRole.php48
-rw-r--r--Core/SecurityContext.php94
-rw-r--r--Core/User/AccountChecker.php61
-rw-r--r--Core/User/AccountCheckerInterface.php36
-rw-r--r--Core/User/AccountInterface.php74
-rw-r--r--Core/User/AdvancedAccountInterface.php48
-rw-r--r--Core/User/InMemoryUserProvider.php98
-rw-r--r--Core/User/User.php163
-rw-r--r--Core/User/UserProviderInterface.php57
63 files changed, 3726 insertions, 0 deletions
diff --git a/Core/Authentication/AuthenticationManagerInterface.php b/Core/Authentication/AuthenticationManagerInterface.php
new file mode 100644
index 0000000..280377a
--- /dev/null
+++ b/Core/Authentication/AuthenticationManagerInterface.php
@@ -0,0 +1,35 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+
+/**
+ * AuthenticationManagerInterface is the interface for authentication managers,
+ * which process Token authentication.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+interface AuthenticationManagerInterface
+{
+ /**
+ * Attempts to authenticates a TokenInterface object.
+ *
+ * @param TokenInterface $token The TokenInterface instance to authenticate
+ *
+ * @return TokenInterface An authenticated TokenInterface instance
+ *
+ * @throws AuthenticationException if the authentication fails
+ */
+ function authenticate(TokenInterface $token);
+}
diff --git a/Core/Authentication/AuthenticationProviderManager.php b/Core/Authentication/AuthenticationProviderManager.php
new file mode 100644
index 0000000..187a81b
--- /dev/null
+++ b/Core/Authentication/AuthenticationProviderManager.php
@@ -0,0 +1,120 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Exception\AccountStatusException;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Core\Exception\ProviderNotFoundException;
+use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+
+/**
+ * AuthenticationProviderManager uses a list of AuthenticationProviderInterface
+ * instances to authenticate a Token.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class AuthenticationProviderManager implements AuthenticationManagerInterface
+{
+ protected $providers;
+ protected $eraseCredentials;
+
+ /**
+ * Constructor.
+ *
+ * @param AuthenticationProviderInterface[] $providers An array of AuthenticationProviderInterface instances
+ * @param Boolean $eraseCredentials Whether to erase credentials after authentication or not
+ */
+ public function __construct(array $providers = array(), $eraseCredentials = true)
+ {
+ $this->setProviders($providers);
+ $this->eraseCredentials = (Boolean) $eraseCredentials;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function authenticate(TokenInterface $token)
+ {
+ if (!count($this->providers)) {
+ throw new \LogicException('You must add at least one provider.');
+ }
+
+ $lastException = null;
+ $result = null;
+
+ foreach ($this->providers as $provider) {
+ if (!$provider->supports($token)) {
+ continue;
+ }
+
+ try {
+ $result = $provider->authenticate($token);
+ } catch (AccountStatusException $e) {
+ $e->setExtraInformation($token);
+
+ throw $e;
+ } catch (AuthenticationException $e) {
+ $lastException = $e;
+ }
+ }
+
+ if (null !== $result) {
+ if (true === $this->eraseCredentials) {
+ $result->eraseCredentials();
+ }
+
+ return $result;
+ }
+
+ if (null === $lastException) {
+ $lastException = new ProviderNotFoundException(sprintf('No Authentication Provider found for token of class "%s".', get_class($token)));
+ }
+
+ $lastException->setExtraInformation($token);
+
+ throw $lastException;
+ }
+
+ /**
+ * Returns the list of current providers.
+ *
+ * @return AuthenticationProviderInterface[] An array of AuthenticationProviderInterface instances
+ */
+ public function all()
+ {
+ return $this->providers;
+ }
+
+ /**
+ * Sets the providers instances.
+ *
+ * @param AuthenticationProviderInterface[] $providers An array of AuthenticationProviderInterface instances
+ */
+ public function setProviders(array $providers)
+ {
+ $this->providers = array();
+ foreach ($providers as $provider) {
+ $this->add($provider);
+ }
+ }
+
+ /**
+ * Adds a provider.
+ *
+ * @param AuthenticationProviderInterface $provider A AuthenticationProviderInterface instance
+ */
+ public function add(AuthenticationProviderInterface $provider)
+ {
+ $this->providers[] = $provider;
+ }
+}
diff --git a/Core/Authentication/AuthenticationTrustResolver.php b/Core/Authentication/AuthenticationTrustResolver.php
new file mode 100644
index 0000000..95b8cb4
--- /dev/null
+++ b/Core/Authentication/AuthenticationTrustResolver.php
@@ -0,0 +1,75 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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;
+
+/**
+ * The default implementation of the authentication trust resolver.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class AuthenticationTrustResolver implements AuthenticationTrustResolverInterface
+{
+ protected $anonymousClass;
+ protected $rememberMeClass;
+
+ /**
+ * Constructor
+ *
+ * @param string $anonymousClass
+ * @param string $rememberMeClass
+ *
+ * @return void
+ */
+ public function __construct($anonymousClass, $rememberMeClass)
+ {
+ $this->anonymousClass = $anonymousClass;
+ $this->rememberMeClass = $rememberMeClass;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function isAnonymous(TokenInterface $token = null)
+ {
+ if (null === $token) {
+ return false;
+ }
+
+ return $token instanceof $this->anonymousClass;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function isRememberMe(TokenInterface $token = null)
+ {
+ if (null === $token) {
+ return false;
+ }
+
+ return $token instanceof $this->rememberMeClass;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function isFullFledged(TokenInterface $token = null)
+ {
+ if (null === $token) {
+ return false;
+ }
+
+ return !$this->isAnonymous($token) && !$this->isRememberMe($token);
+ }
+}
diff --git a/Core/Authentication/AuthenticationTrustResolverInterface.php b/Core/Authentication/AuthenticationTrustResolverInterface.php
new file mode 100644
index 0000000..1f29465
--- /dev/null
+++ b/Core/Authentication/AuthenticationTrustResolverInterface.php
@@ -0,0 +1,53 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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
+ * anonymously.
+ *
+ * If null is passed, the method must return false.
+ *
+ * @param TokenInterface $token
+ *
+ * @return Boolean
+ */
+ function isAnonymous(TokenInterface $token = null);
+
+ /**
+ * Resolves whether the passed token implementation is authenticated
+ * using remember-me capabilities.
+ *
+ * @param TokenInterface $token
+ *
+ * @return Boolean
+ */
+ function isRememberMe(TokenInterface $token = null);
+
+ /**
+ * Resolves whether the passed token implementation is fully authenticated.
+ *
+ * @param TokenInterface $token
+ *
+ * @return Boolean
+ */
+ function isFullFledged(TokenInterface $token = null);
+}
diff --git a/Core/Authentication/EntryPoint/AuthenticationEntryPointInterface.php b/Core/Authentication/EntryPoint/AuthenticationEntryPointInterface.php
new file mode 100644
index 0000000..7fd64bf
--- /dev/null
+++ b/Core/Authentication/EntryPoint/AuthenticationEntryPointInterface.php
@@ -0,0 +1,32 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\EntryPoint;
+
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * AuthenticationEntryPointInterface is the interface used to start the
+ * authentication scheme.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+interface AuthenticationEntryPointInterface
+{
+ /**
+ * Starts the authentication scheme.
+ *
+ * @param object $request The request that resulted in an AuthenticationException
+ * @param AuthenticationException $authException The exception that started the authentication process
+ */
+ function start(Request $request, AuthenticationException $authException = null);
+}
diff --git a/Core/Authentication/Provider/AnonymousAuthenticationProvider.php b/Core/Authentication/Provider/AnonymousAuthenticationProvider.php
new file mode 100644
index 0000000..821e17e
--- /dev/null
+++ b/Core/Authentication/Provider/AnonymousAuthenticationProvider.php
@@ -0,0 +1,60 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Provider;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Exception\BadCredentialsException;
+use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
+
+/**
+ * AnonymousAuthenticationProvider validates AnonymousToken instances.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class AnonymousAuthenticationProvider implements AuthenticationProviderInterface
+{
+ protected $key;
+
+ /**
+ * Constructor.
+ *
+ * @param string $key The key shared with the authentication token
+ */
+ public function __construct($key)
+ {
+ $this->key = $key;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function authenticate(TokenInterface $token)
+ {
+ if (!$this->supports($token)) {
+ return null;
+ }
+
+ if ($this->key != $token->getKey()) {
+ throw new BadCredentialsException('The Token does not contain the expected key.');
+ }
+
+ return $token;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supports(TokenInterface $token)
+ {
+ return $token instanceof AnonymousToken;
+ }
+}
diff --git a/Core/Authentication/Provider/AuthenticationProviderInterface.php b/Core/Authentication/Provider/AuthenticationProviderInterface.php
new file mode 100644
index 0000000..89d5ed5
--- /dev/null
+++ b/Core/Authentication/Provider/AuthenticationProviderInterface.php
@@ -0,0 +1,35 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Provider;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
+
+/**
+ * AuthenticationProviderInterface is the interface for for all authentication
+ * providers.
+ *
+ * Concrete implementations processes specific Token instances.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+interface AuthenticationProviderInterface extends AuthenticationManagerInterface
+{
+ /**
+ * Checks whether this provider supports the given token.
+ *
+ * @param TokenInterface $token A TokenInterface instance
+ *
+ * @return Boolean true if the implementation supports the Token, false otherwise
+ */
+ function supports(TokenInterface $token);
+}
diff --git a/Core/Authentication/Provider/DaoAuthenticationProvider.php b/Core/Authentication/Provider/DaoAuthenticationProvider.php
new file mode 100644
index 0000000..398f586
--- /dev/null
+++ b/Core/Authentication/Provider/DaoAuthenticationProvider.php
@@ -0,0 +1,95 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Provider;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
+use Symfony\Component\Security\Core\User\UserProviderInterface;
+use Symfony\Component\Security\Core\User\AccountCheckerInterface;
+use Symfony\Component\Security\Core\User\AccountInterface;
+use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
+use Symfony\Component\Security\Core\Exception\AuthenticationServiceException;
+use Symfony\Component\Security\Core\Exception\BadCredentialsException;
+use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
+
+/**
+ * DaoAuthenticationProvider uses a UserProviderInterface to retrieve the user
+ * for a UsernamePasswordToken.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class DaoAuthenticationProvider extends UserAuthenticationProvider
+{
+ protected $encoderFactory;
+ protected $userProvider;
+
+ /**
+ * Constructor.
+ *
+ * @param UserProviderInterface $userProvider A UserProviderInterface instance
+ * @param AccountCheckerInterface $accountChecker An AccountCheckerInterface instance
+ * @param EncoderFactoryInterface $encoderFactory A EncoderFactoryInterface instance
+ */
+ public function __construct(UserProviderInterface $userProvider, AccountCheckerInterface $accountChecker, $providerKey, EncoderFactoryInterface $encoderFactory, $hideUserNotFoundExceptions = true)
+ {
+ parent::__construct($accountChecker, $providerKey, $hideUserNotFoundExceptions);
+
+ $this->encoderFactory = $encoderFactory;
+ $this->userProvider = $userProvider;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function checkAuthentication(AccountInterface $account, UsernamePasswordToken $token)
+ {
+ $user = $token->getUser();
+ if ($user instanceof AccountInterface) {
+ if ($account->getPassword() !== $user->getPassword()) {
+ throw new BadCredentialsException('The credentials were changed from another session.');
+ }
+ } else {
+ if (!$presentedPassword = (string) $token->getCredentials()) {
+ throw new BadCredentialsException('Bad credentials');
+ }
+
+ if (!$this->encoderFactory->getEncoder($account)->isPasswordValid($account->getPassword(), $presentedPassword, $account->getSalt())) {
+ throw new BadCredentialsException('Bad credentials');
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function retrieveUser($username, UsernamePasswordToken $token)
+ {
+ $user = $token->getUser();
+ if ($user instanceof AccountInterface) {
+ return $user;
+ }
+
+ try {
+ $user = $this->userProvider->loadUserByUsername($username);
+
+ if (!$user instanceof AccountInterface) {
+ throw new AuthenticationServiceException('The user provider must return an AccountInterface object.');
+ }
+
+ return $user;
+ } catch (UsernameNotFoundException $notFound) {
+ throw $notFound;
+ } catch (\Exception $repositoryProblem) {
+ throw new AuthenticationServiceException($repositoryProblem->getMessage(), $token, 0, $repositoryProblem);
+ }
+ }
+}
diff --git a/Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php b/Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php
new file mode 100644
index 0000000..7fda9d4
--- /dev/null
+++ b/Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php
@@ -0,0 +1,81 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Provider;
+
+use Symfony\Component\Security\Core\User\AccountInterface;
+use Symfony\Component\Security\Core\User\UserProviderInterface;
+use Symfony\Component\Security\Core\User\AccountCheckerInterface;
+use Symfony\Component\Security\Core\Exception\BadCredentialsException;
+use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+
+/**
+ * Processes a pre-authenticated authentication request.
+ *
+ * This authentication provider will not perform any checks on authentication
+ * requests, as they should already be pre-authenticated. However, the
+ * UserProviderInterface implementation may still throw a
+ * UsernameNotFoundException, for example.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class PreAuthenticatedAuthenticationProvider implements AuthenticationProviderInterface
+{
+ protected $userProvider;
+ protected $accountChecker;
+ protected $providerKey;
+
+ /**
+ * Constructor.
+ *
+ * @param UserProviderInterface $userProvider A UserProviderInterface instance
+ * @param AccountCheckerInterface $accountChecker An AccountCheckerInterface instance
+ */
+ public function __construct(UserProviderInterface $userProvider, AccountCheckerInterface $accountChecker, $providerKey)
+ {
+ $this->userProvider = $userProvider;
+ $this->accountChecker = $accountChecker;
+ $this->providerKey = $providerKey;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function authenticate(TokenInterface $token)
+ {
+ if (!$this->supports($token)) {
+ return null;
+ }
+
+ if (!$user = $token->getUser()) {
+ throw new BadCredentialsException('No pre-authenticated principal found in request.');
+ }
+/*
+ if (null === $token->getCredentials()) {
+ throw new BadCredentialsException('No pre-authenticated credentials found in request.');
+ }
+*/
+ $user = $this->userProvider->loadUserByUsername($user);
+
+ $this->accountChecker->checkPostAuth($user);
+
+ return new PreAuthenticatedToken($user, $token->getCredentials(), $user->getRoles());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supports(TokenInterface $token)
+ {
+ return $token instanceof PreAuthenticatedToken && $this->providerKey === $token->getProviderKey();
+ }
+}
diff --git a/Core/Authentication/Provider/RememberMeAuthenticationProvider.php b/Core/Authentication/Provider/RememberMeAuthenticationProvider.php
new file mode 100644
index 0000000..95ee588
--- /dev/null
+++ b/Core/Authentication/Provider/RememberMeAuthenticationProvider.php
@@ -0,0 +1,45 @@
+<?php
+namespace Symfony\Component\Security\Core\Authentication\Provider;
+
+use Symfony\Component\Security\Core\User\AccountCheckerInterface;
+use Symfony\Component\Security\Core\User\AccountInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
+use Symfony\Component\Security\Core\Exception\BadCredentialsException;
+
+class RememberMeAuthenticationProvider implements AuthenticationProviderInterface
+{
+ protected $accountChecker;
+ protected $key;
+ protected $providerKey;
+
+ public function __construct(AccountCheckerInterface $accountChecker, $key, $providerKey)
+ {
+ $this->accountChecker = $accountChecker;
+ $this->key = $key;
+ $this->providerKey = $providerKey;
+ }
+
+ public function authenticate(TokenInterface $token)
+ {
+ if (!$this->supports($token)) {
+ return;
+ }
+
+ if ($this->key !== $token->getKey()) {
+ throw new BadCredentialsException('The presented key does not match.');
+ }
+
+ $user = $token->getUser();
+ $this->accountChecker->checkPreAuth($user);
+ $this->accountChecker->checkPostAuth($user);
+ $token->setAuthenticated(true);
+
+ return $token;
+ }
+
+ public function supports(TokenInterface $token)
+ {
+ return $token instanceof RememberMeToken && $token->getProviderKey() === $this->providerKey;
+ }
+} \ No newline at end of file
diff --git a/Core/Authentication/Provider/UserAuthenticationProvider.php b/Core/Authentication/Provider/UserAuthenticationProvider.php
new file mode 100644
index 0000000..6947de3
--- /dev/null
+++ b/Core/Authentication/Provider/UserAuthenticationProvider.php
@@ -0,0 +1,113 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Provider;
+
+use Symfony\Component\Security\Core\User\AccountInterface;
+use Symfony\Component\Security\Core\User\AccountCheckerInterface;
+use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Core\Exception\BadCredentialsException;
+use Symfony\Component\Security\Core\Exception\AuthenticationServiceException;
+use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+
+/**
+ * UserProviderInterface retrieves users for UsernamePasswordToken tokens.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+abstract class UserAuthenticationProvider implements AuthenticationProviderInterface
+{
+ protected $hideUserNotFoundExceptions;
+ protected $accountChecker;
+ protected $providerKey;
+
+ /**
+ * Constructor.
+ *
+ * @param AccountCheckerInterface $accountChecker An AccountCheckerInterface interface
+ * @param Boolean $hideUserNotFoundExceptions Whether to hide user not found exception or not
+ */
+ public function __construct(AccountCheckerInterface $accountChecker, $providerKey, $hideUserNotFoundExceptions = true)
+ {
+ if (empty($providerKey)) {
+ throw new \InvalidArgumentException('$providerKey must not be empty.');
+ }
+
+ $this->accountChecker = $accountChecker;
+ $this->providerKey = $providerKey;
+ $this->hideUserNotFoundExceptions = $hideUserNotFoundExceptions;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function authenticate(TokenInterface $token)
+ {
+ if (!$this->supports($token)) {
+ return null;
+ }
+
+ $username = null === $token->getUser() ? 'NONE_PROVIDED' : (string) $token;
+
+ try {
+ $user = $this->retrieveUser($username, $token);
+
+ if (!$user instanceof AccountInterface) {
+ throw new AuthenticationServiceException('retrieveUser() must return an AccountInterface.');
+ }
+
+ $this->accountChecker->checkPreAuth($user);
+ $this->checkAuthentication($user, $token);
+ $this->accountChecker->checkPostAuth($user);
+
+ return new UsernamePasswordToken($user, $token->getCredentials(), $this->providerKey, $user->getRoles());
+ } catch (UsernameNotFoundException $notFound) {
+ if ($this->hideUserNotFoundExceptions) {
+ throw new BadCredentialsException('Bad credentials', 0, $notFound);
+ }
+
+ throw $notFound;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supports(TokenInterface $token)
+ {
+ return $token instanceof UsernamePasswordToken && $this->providerKey === $token->getProviderKey();
+ }
+
+ /**
+ * Retrieves the user from an implementation-specific location.
+ *
+ * @param string $username The username to retrieve
+ * @param UsernamePasswordToken $token The Token
+ *
+ * @return array The user
+ *
+ * @throws AuthenticationException if the credentials could not be validated
+ */
+ abstract protected function retrieveUser($username, UsernamePasswordToken $token);
+
+ /**
+ * Does additional checks on the user and token (like validating the
+ * credentials).
+ *
+ * @param AccountInterface $account The retrieved AccountInterface instance
+ * @param UsernamePasswordToken $token The UsernamePasswordToken token to be authenticated
+ *
+ * @throws AuthenticationException if the credentials could not be validated
+ */
+ abstract protected function checkAuthentication(AccountInterface $account, UsernamePasswordToken $token);
+}
diff --git a/Core/Authentication/RememberMe/InMemoryTokenProvider.php b/Core/Authentication/RememberMe/InMemoryTokenProvider.php
new file mode 100644
index 0000000..80c10d1
--- /dev/null
+++ b/Core/Authentication/RememberMe/InMemoryTokenProvider.php
@@ -0,0 +1,50 @@
+<?php
+
+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>
+ */
+class InMemoryTokenProvider implements TokenProviderInterface
+{
+ protected $tokens = array();
+
+ public function loadTokenBySeries($series)
+ {
+ if (!isset($this->tokens[$series])) {
+ throw new TokenNotFoundException('No token found.');
+ }
+
+ return $this->tokens[$series];
+ }
+
+ public function updateToken($series, $tokenValue, \DateTime $lastUsed)
+ {
+ if (!isset($this->tokens[$series])) {
+ throw new TokenNotFoundException('No token found.');
+ }
+
+ $token = new PersistentToken(
+ $this->tokens[$series]->getClass(),
+ $this->tokens[$series]->getUsername(),
+ $series,
+ $tokenValue,
+ $lastUsed
+ );
+ $this->tokens[$series] = $token;
+ }
+
+ public function deleteTokenBySeries($series)
+ {
+ unset($this->tokens[$series]);
+ }
+
+ public function createNewToken(PersistentTokenInterface $token)
+ {
+ $this->tokens[$token->getSeries()] = $token;
+ }
+} \ No newline at end of file
diff --git a/Core/Authentication/RememberMe/PersistentToken.php b/Core/Authentication/RememberMe/PersistentToken.php
new file mode 100644
index 0000000..9b9bb93
--- /dev/null
+++ b/Core/Authentication/RememberMe/PersistentToken.php
@@ -0,0 +1,107 @@
+<?php
+
+namespace Symfony\Component\Security\Core\Authentication\RememberMe;
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * This class is only used by PersistentTokenRememberMeServices internally.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+final class PersistentToken implements PersistentTokenInterface
+{
+ private $class;
+ private $username;
+ private $series;
+ private $tokenValue;
+ private $lastUsed;
+
+ /**
+ * Constructor
+ *
+ * @param string $class
+ * @param string $username
+ * @param string $series
+ * @param string $tokenValue
+ * @param DateTime $lastUsed
+ */
+ public function __construct($class, $username, $series, $tokenValue, \DateTime $lastUsed)
+ {
+ if (empty($class)) {
+ throw new \InvalidArgumentException('$class must not be empty.');
+ }
+ if (empty($username)) {
+ throw new \InvalidArgumentException('$username must not be empty.');
+ }
+ if (empty($series)) {
+ throw new \InvalidArgumentException('$series must not be empty.');
+ }
+ if (empty($tokenValue)) {
+ throw new \InvalidArgumentException('$tokenValue must not be empty.');
+ }
+
+ $this->class = $class;
+ $this->username = $username;
+ $this->series = $series;
+ $this->tokenValue = $tokenValue;
+ $this->lastUsed = $lastUsed;
+ }
+
+ /**
+ * Returns the class of the user
+ *
+ * @return string
+ */
+ public function getClass()
+ {
+ return $this->class;
+ }
+
+ /**
+ * Returns the username
+ *
+ * @return string
+ */
+ public function getUsername()
+ {
+ return $this->username;
+ }
+
+ /**
+ * Returns the series
+ *
+ * @return string
+ */
+ public function getSeries()
+ {
+ return $this->series;
+ }
+
+ /**
+ * Returns the token value
+ *
+ * @return string
+ */
+ public function getTokenValue()
+ {
+ return $this->tokenValue;
+ }
+
+ /**
+ * Returns the time the token was last used
+ *
+ * @return DateTime
+ */
+ public function getLastUsed()
+ {
+ return $this->lastUsed;
+ }
+} \ No newline at end of file
diff --git a/Core/Authentication/RememberMe/PersistentTokenInterface.php b/Core/Authentication/RememberMe/PersistentTokenInterface.php
new file mode 100644
index 0000000..3696d1f
--- /dev/null
+++ b/Core/Authentication/RememberMe/PersistentTokenInterface.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace Symfony\Component\Security\Core\Authentication\RememberMe;
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * 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 username
+ * @return string
+ */
+ function getUsername();
+
+ /**
+ * Returns the series
+ * @return string
+ */
+ function getSeries();
+
+ /**
+ * Returns the token value
+ * @return string
+ */
+ function getTokenValue();
+
+ /**
+ * Returns the last time the cookie was used
+ * @return \DateTime
+ */
+ function getLastUsed();
+} \ No newline at end of file
diff --git a/Core/Authentication/RememberMe/TokenProviderInterface.php b/Core/Authentication/RememberMe/TokenProviderInterface.php
new file mode 100644
index 0000000..e77e68a
--- /dev/null
+++ b/Core/Authentication/RememberMe/TokenProviderInterface.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace Symfony\Component\Security\Core\Authentication\RememberMe;
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Interface for TokenProviders
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+interface TokenProviderInterface
+{
+ /**
+ * Loads the active token for the given series
+ *
+ * @throws TokenNotFoundException if the token is not found
+ *
+ * @param string $series
+ * @return PersistentTokenInterface
+ */
+ function loadTokenBySeries($series);
+
+ /**
+ * Deletes all tokens belonging to series
+ * @param string $series
+ */
+ function deleteTokenBySeries($series);
+
+ /**
+ * Updates the token according to this data
+ *
+ * @param string $series
+ * @param string $tokenValue
+ * @param DateTime $lastUsed
+ */
+ function updateToken($series, $tokenValue, \DateTime $lastUsed);
+
+ /**
+ * Creates a new token
+ * @param PersistentTokenInterface $token
+ */
+ function createNewToken(PersistentTokenInterface $token);
+} \ No newline at end of file
diff --git a/Core/Authentication/Token/AnonymousToken.php b/Core/Authentication/Token/AnonymousToken.php
new file mode 100644
index 0000000..7735925
--- /dev/null
+++ b/Core/Authentication/Token/AnonymousToken.php
@@ -0,0 +1,58 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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;
+
+/**
+ * AnonymousToken represents an anonymous token.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class AnonymousToken extends Token
+{
+ protected $user;
+ protected $key;
+
+ /**
+ * Constructor.
+ *
+ * @param string $key The key shared with the authentication provider
+ * @param string $user The user
+ * @param Role[] $roles An array of roles
+ */
+ public function __construct($key, $user, array $roles = array())
+ {
+ parent::__construct($roles);
+
+ $this->key = $key;
+ $this->user = $user;
+
+ parent::setAuthenticated(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCredentials()
+ {
+ return '';
+ }
+
+ /**
+ * Returns the key.
+ *
+ * @return string The Key
+ */
+ public function getKey()
+ {
+ return $this->key;
+ }
+}
diff --git a/Core/Authentication/Token/PreAuthenticatedToken.php b/Core/Authentication/Token/PreAuthenticatedToken.php
new file mode 100644
index 0000000..c84ea10
--- /dev/null
+++ b/Core/Authentication/Token/PreAuthenticatedToken.php
@@ -0,0 +1,52 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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;
+
+/**
+ * PreAuthenticatedToken implements a pre-authenticated token.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class PreAuthenticatedToken extends Token
+{
+ protected $providerKey;
+
+ /**
+ * Constructor.
+ */
+ public function __construct($user, $credentials, $providerKey, array $roles = null)
+ {
+ parent::__construct(null === $roles ? array() : $roles);
+ if (null !== $roles) {
+ $this->setAuthenticated(true);
+ }
+
+ $this->user = $user;
+ $this->credentials = $credentials;
+ $this->providerKey = $providerKey;
+ }
+
+ public function getProviderKey()
+ {
+ return $this->providerKey;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function eraseCredentials()
+ {
+ parent::eraseCredentials();
+
+ $this->credentials = null;
+ }
+}
diff --git a/Core/Authentication/Token/RememberMeToken.php b/Core/Authentication/Token/RememberMeToken.php
new file mode 100644
index 0000000..81bf1e0
--- /dev/null
+++ b/Core/Authentication/Token/RememberMeToken.php
@@ -0,0 +1,75 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Authentication\RememberMe\PersistentTokenInterface;
+use Symfony\Component\Security\Core\User\AccountInterface;
+
+/**
+ * Base class for "Remember Me" tokens
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class RememberMeToken extends Token
+{
+ protected $key;
+ protected $providerKey;
+
+ /**
+ * The persistent token which resulted in this authentication token.
+ *
+ * @var PersistentTokenInterface
+ */
+ protected $persistentToken;
+
+ /**
+ * Constructor.
+ *
+ * @param string $username
+ * @param string $key
+ */
+ public function __construct(AccountInterface $user, $providerKey, $key) {
+ parent::__construct($user->getRoles());
+
+ if (empty($key)) {
+ throw new \InvalidArgumentException('$key must not be empty.');
+ }
+ if (empty($providerKey)) {
+ throw new \InvalidArgumentException('$providerKey must not be empty.');
+ }
+
+ $this->setUser($user);
+ $this->providerKey = $providerKey;
+ $this->key = $key;
+ $this->setAuthenticated(true);
+ }
+
+ public function getProviderKey()
+ {
+ return $this->providerKey;
+ }
+
+ public function getKey()
+ {
+ return $this->key;
+ }
+
+ public function getPersistentToken()
+ {
+ return $this->persistentToken;
+ }
+
+ public function setPersistentToken(PersistentTokenInterface $persistentToken)
+ {
+ $this->persistentToken = $persistentToken;
+ }
+} \ No newline at end of file
diff --git a/Core/Authentication/Token/Token.php b/Core/Authentication/Token/Token.php
new file mode 100644
index 0000000..d41bab5
--- /dev/null
+++ b/Core/Authentication/Token/Token.php
@@ -0,0 +1,199 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Role\RoleInterface;
+use Symfony\Component\Security\Core\Role\Role;
+use Symfony\Component\Security\Core\User\AccountInterface;
+
+/**
+ * Base class for Token instances.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+abstract class Token implements TokenInterface
+{
+ protected $roles;
+ protected $authenticated;
+ protected $user;
+ protected $credentials;
+ protected $immutable;
+
+ /**
+ * Constructor.
+ *
+ * @param Role[] $roles An array of roles
+ */
+ public function __construct(array $roles = array())
+ {
+ $this->setRoles($roles);
+ $this->authenticated = false;
+ $this->immutable = false;
+ }
+
+ /**
+ * Adds a Role to the token.
+ *
+ * @param RoleInterface $role A RoleInterface instance
+ */
+ public function addRole(RoleInterface $role)
+ {
+ if ($this->immutable) {
+ throw new \LogicException('This token is considered immutable.');
+ }
+
+ $this->roles[] = $role;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRoles()
+ {
+ return $this->roles;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function setRoles(array $roles)
+ {
+ $this->roles = array();
+
+ foreach ($roles as $role) {
+ if (is_string($role)) {
+ $role = new Role($role);
+ }
+
+ $this->addRole($role);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString()
+ {
+ if (!is_object($this->user)) {
+ return (string) $this->user;
+ } elseif ($this->user instanceof AccountInterface) {
+ return $this->user->getUsername();
+ } else {
+ return 'n/a';
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isAuthenticated()
+ {
+ return $this->authenticated;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setAuthenticated($authenticated)
+ {
+ if ($this->immutable) {
+ throw new \LogicException('This token is considered immutable.');
+ }
+
+ $this->authenticated = (Boolean) $authenticated;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCredentials()
+ {
+ return $this->credentials;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getUser()
+ {
+ return $this->user;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function setUser($user)
+ {
+ if ($this->immutable) {
+ throw new \LogicException('This token is considered immutable.');
+ }
+
+ if (!is_string($user) && !is_object($user)) {
+ throw new \InvalidArgumentException('$user must be an object, or a primitive string.');
+ } else if (is_object($user) && !method_exists($user, '__toString')) {
+ throw new \InvalidArgumentException('If $user is an object, it must implement __toString().');
+ }
+
+ $this->user = $user;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function eraseCredentials()
+ {
+ if ($this->immutable) {
+ throw new \LogicException('This token is considered immutable.');
+ }
+
+ if ($this->getCredentials() instanceof AccountInterface) {
+ $this->getCredentials()->eraseCredentials();
+ }
+
+ if ($this->getUser() instanceof AccountInterface) {
+ $this->getUser()->eraseCredentials();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isImmutable()
+ {
+ return $this->immutable;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setImmutable()
+ {
+ $this->immutable = true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function serialize()
+ {
+ return serialize(array($this->user, $this->credentials, $this->authenticated, $this->roles, $this->immutable));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function unserialize($serialized)
+ {
+ list($this->user, $this->credentials, $this->authenticated, $this->roles, $this->immutable) = unserialize($serialized);
+ }
+}
diff --git a/Core/Authentication/Token/TokenInterface.php b/Core/Authentication/Token/TokenInterface.php
new file mode 100644
index 0000000..b6ac31c
--- /dev/null
+++ b/Core/Authentication/Token/TokenInterface.php
@@ -0,0 +1,102 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\AccountInterface;
+
+/**
+ * TokenInterface is the interface for the user authentication information.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+interface TokenInterface extends \Serializable
+{
+ /**
+ * Returns a string representation of the token.
+ *
+ * @return string A string representation
+ */
+ function __toString();
+
+ /**
+ * Returns the user roles.
+ *
+ * @return Role[] An array of Role instances.
+ */
+ function getRoles();
+
+ /**
+ * Sets the user's roles
+ *
+ * @param array $roles
+ * @return void
+ */
+ function setRoles(array $roles);
+
+ /**
+ * Returns the user credentials.
+ *
+ * @return mixed The user credentials
+ */
+ function getCredentials();
+
+ /**
+ * Returns a user representation.
+ *
+ * @return mixed either returns an object which implements __toString(), or
+ * a primitive string is returned.
+ */
+ function getUser();
+
+ /**
+ * Sets the user.
+ *
+ * @param mixed $user can either be an object which implements __toString(), or
+ * only a primitive string
+ */
+ function setUser($user);
+
+ /**
+ * Checks if the user is authenticated or not.
+ *
+ * @return Boolean true if the token has been authenticated, false otherwise
+ */
+ function isAuthenticated();
+
+ /**
+ * Sets the authenticated flag.
+ *
+ * @param Boolean $isAuthenticated The authenticated flag
+ */
+ function setAuthenticated($isAuthenticated);
+
+ /**
+ * Whether this token is considered immutable
+ *
+ * @return Boolean
+ */
+ function isImmutable();
+
+ /**
+ * Marks this token as immutable. This change cannot be reversed.
+ *
+ * You'll need to create a new token if you want a mutable token again.
+ *
+ * @return void
+ */
+ function setImmutable();
+
+ /**
+ * Removes sensitive information from the token.
+ */
+ function eraseCredentials();
+}
diff --git a/Core/Authentication/Token/UsernamePasswordToken.php b/Core/Authentication/Token/UsernamePasswordToken.php
new file mode 100644
index 0000000..a61acd4
--- /dev/null
+++ b/Core/Authentication/Token/UsernamePasswordToken.php
@@ -0,0 +1,66 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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;
+
+/**
+ * UsernamePasswordToken implements a username and password token.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class UsernamePasswordToken extends Token
+{
+ protected $providerKey;
+
+ /**
+ * Constructor.
+ *
+ * @param string $user The username (like a nickname, email address, etc.)
+ * @param string $credentials This usually is the password of the user
+ */
+ public function __construct($user, $credentials, $providerKey, array $roles = array())
+ {
+ parent::__construct($roles);
+
+ $this->setUser($user);
+ $this->credentials = $credentials;
+ $this->providerKey = $providerKey;
+
+ parent::setAuthenticated((Boolean) count($roles));
+ }
+
+ public function getProviderKey()
+ {
+ return $this->providerKey;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setAuthenticated($isAuthenticated)
+ {
+ if ($isAuthenticated) {
+ throw new \LogicException('Cannot set this token to trusted after instantiation.');
+ }
+
+ parent::setAuthenticated(false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function eraseCredentials()
+ {
+ parent::eraseCredentials();
+
+ $this->credentials = null;
+ }
+}
diff --git a/Core/Authorization/AccessDecisionManager.php b/Core/Authorization/AccessDecisionManager.php
new file mode 100644
index 0000000..d6e642c
--- /dev/null
+++ b/Core/Authorization/AccessDecisionManager.php
@@ -0,0 +1,240 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Authorization;
+
+use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+
+/**
+ * AccessDecisionManager is the base class for all access decision managers
+ * that use decision voters.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class AccessDecisionManager implements AccessDecisionManagerInterface
+{
+ protected $voters;
+ protected $strategy;
+ protected $allowIfAllAbstainDecisions;
+ protected $allowIfEqualGrantedDeniedDecisions;
+
+ /**
+ * Constructor.
+ *
+ * @param VoterInterface[] $voters An array of VoterInterface instances
+ * @param string $strategy The vote strategy
+ * @param Boolean $allowIfAllAbstainDecisions Whether to grant access if all voters abstained or not
+ */
+ public function __construct(array $voters = array(), $strategy = 'affirmative', $allowIfAllAbstainDecisions = false, $allowIfEqualGrantedDeniedDecisions = true)
+ {
+ $this->voters = $voters;
+ $this->strategy = 'decide'.ucfirst($strategy);
+ $this->allowIfAllAbstainDecisions = (Boolean) $allowIfAllAbstainDecisions;
+ $this->allowIfEqualGrantedDeniedDecisions = (Boolean) $allowIfEqualGrantedDeniedDecisions;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function decide(TokenInterface $token, array $attributes, $object = null)
+ {
+ return $this->{$this->strategy}($token, $attributes, $object);
+ }
+
+ /**
+ * Returns all voters.
+ *
+ * @return VoterInterface[] $voters An array of VoterInterface instances
+ */
+ public function getVoters()
+ {
+ return $this->voters;
+ }
+
+ /**
+ * Sets voters.
+ *
+ * @param VoterInterface[] $voters An array of VoterInterface instances
+ */
+ public function setVoters(array $voters)
+ {
+ if (!count($voters)) {
+ throw new \LogicException('You must have at least one voter.');
+ }
+
+ $this->voters = array();
+ foreach ($voters as $voter) {
+ $this->addVoter($voter);
+ }
+ }
+
+ /**
+ * Adds a voter.
+ *
+ * @param VoterInterface $voter A VoterInterface instance
+ */
+ public function addVoter(VoterInterface $voter)
+ {
+ $this->voters[] = $voter;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supportsAttribute($attribute)
+ {
+ foreach ($this->voters as $voter) {
+ if ($voter->supportsAttribute($attribute)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supportsClass($class)
+ {
+ foreach ($this->voters as $voter) {
+ if ($voter->supportsClass($class)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Grants access if any voter returns an affirmative response.
+ *
+ * If all voters abstained from voting, the decision will be based on the
+ * allowIfAllAbstainDecisions property value (defaults to false).
+ */
+ protected function decideAffirmative(TokenInterface $token, array $attributes, $object = null)
+ {
+ $deny = 0;
+ foreach ($this->voters as $voter) {
+ $result = $voter->vote($token, $object, $attributes);
+ switch ($result) {
+ case VoterInterface::ACCESS_GRANTED:
+ return true;
+
+ case VoterInterface::ACCESS_DENIED:
+ ++$deny;
+
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if ($deny > 0) {
+ return false;
+ }
+
+ return $this->allowIfAllAbstainDecisions;
+ }
+
+ /**
+ * Grants access if there is consensus of granted against denied responses.
+ *
+ * Consensus means majority-rule (ignoring abstains) rather than unanimous
+ * agreement (ignoring abstains). If you require unanimity, see
+ * UnanimousBased.
+ *
+ * If there were an equal number of grant and deny votes, the decision will
+ * be based on the allowIfEqualGrantedDeniedDecisions property value
+ * (defaults to true).
+ *
+ * If all voters abstained from voting, the decision will be based on the
+ * allowIfAllAbstainDecisions property value (defaults to false).
+ */
+ protected function decideConsensus(TokenInterface $token, array $attributes, $object = null)
+ {
+ $grant = 0;
+ $deny = 0;
+ $abstain = 0;
+ foreach ($this->voters as $voter) {
+ $result = $voter->vote($token, $object, $attributes);
+
+ switch ($result) {
+ case VoterInterface::ACCESS_GRANTED:
+ ++$grant;
+
+ break;
+
+ case VoterInterface::ACCESS_DENIED:
+ ++$deny;
+
+ break;
+
+ default:
+ ++$abstain;
+
+ break;
+ }
+ }
+
+ if ($grant > $deny) {
+ return true;
+ }
+
+ if ($deny > $grant) {
+ return false;
+ }
+
+ if ($grant == $deny && $grant != 0) {
+ return $this->allowIfEqualGrantedDeniedDecisions;
+ }
+
+ return $this->allowIfAllAbstainDecisions;
+ }
+
+ /**
+ * Grants access if only grant (or abstain) votes were received.
+ *
+ * If all voters abstained from voting, the decision will be based on the
+ * allowIfAllAbstainDecisions property value (defaults to false).
+ */
+ protected function decideUnanimous(TokenInterface $token, array $attributes, $object = null)
+ {
+ $grant = 0;
+ foreach ($attributes as $attribute) {
+ foreach ($this->voters as $voter) {
+ $result = $voter->vote($token, $object, array($attribute));
+
+ switch ($result) {
+ case VoterInterface::ACCESS_GRANTED:
+ ++$grant;
+
+ break;
+
+ case VoterInterface::ACCESS_DENIED:
+ return false;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ // no deny votes
+ if ($grant > 0) {
+ return true;
+ }
+
+ return $this->allowIfAllAbstainDecisions;
+ }
+}
diff --git a/Core/Authorization/AccessDecisionManagerInterface.php b/Core/Authorization/AccessDecisionManagerInterface.php
new file mode 100644
index 0000000..7648a3b
--- /dev/null
+++ b/Core/Authorization/AccessDecisionManagerInterface.php
@@ -0,0 +1,51 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Authorization;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+
+/**
+ * AccessDecisionManagerInterface makes authorization decisions.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+interface AccessDecisionManagerInterface
+{
+ /**
+ * Decides whether the access is possible or not.
+ *
+ * @param TokenInterface $token A TokenInterface instance
+ * @param array $attributes An array of attributes associated with the method being invoked
+ * @param object $object The object to secure
+ *
+ * @return Boolean true if the access is granted, false otherwise
+ */
+ function decide(TokenInterface $token, array $attributes, $object = null);
+
+ /**
+ * Checks if the access decision manager supports the given attribute.
+ *
+ * @param string $attribute An attribute
+ *
+ * @return Boolean true if this decision manager supports the attribute, false otherwise
+ */
+ function supportsAttribute($attribute);
+
+ /**
+ * Checks if the access decision manager supports the given class.
+ *
+ * @param string $class A class name
+ *
+ * @return true if this decision manager can process the class
+ */
+ function supportsClass($class);
+}
diff --git a/Core/Authorization/Voter/AuthenticatedVoter.php b/Core/Authorization/Voter/AuthenticatedVoter.php
new file mode 100644
index 0000000..a400e4d
--- /dev/null
+++ b/Core/Authorization/Voter/AuthenticatedVoter.php
@@ -0,0 +1,96 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Authorization\Voter;
+
+use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+
+/**
+ * AuthenticatedVoter votes if an attribute like IS_AUTHENTICATED_FULLY,
+ * IS_AUTHENTICATED_REMEMBERED, or IS_AUTHENTICATED_ANONYMOUSLY is present.
+ *
+ * This list is most restrictive to least restrictive checking.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class AuthenticatedVoter implements VoterInterface
+{
+ const IS_AUTHENTICATED_FULLY = 'IS_AUTHENTICATED_FULLY';
+ const IS_AUTHENTICATED_REMEMBERED = 'IS_AUTHENTICATED_REMEMBERED';
+ const IS_AUTHENTICATED_ANONYMOUSLY = 'IS_AUTHENTICATED_ANONYMOUSLY';
+
+ protected $authenticationTrustResolver;
+
+ /**
+ * Constructor.
+ *
+ * @param AuthenticationTrustResolverInterface $authenticationTrustResolver
+ *
+ * @return void
+ */
+ public function __construct(AuthenticationTrustResolverInterface $authenticationTrustResolver)
+ {
+ $this->authenticationTrustResolver = $authenticationTrustResolver;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supportsAttribute($attribute)
+ {
+ return null !== $attribute && (self::IS_AUTHENTICATED_FULLY === $attribute || self::IS_AUTHENTICATED_REMEMBERED === $attribute || self::IS_AUTHENTICATED_ANONYMOUSLY === $attribute);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supportsClass($class)
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function vote(TokenInterface $token, $object, array $attributes)
+ {
+ $result = VoterInterface::ACCESS_ABSTAIN;
+ foreach ($attributes as $attribute) {
+ if (!$this->supportsAttribute($attribute)) {
+ continue;
+ }
+
+ $result = VoterInterface::ACCESS_DENIED;
+
+ if (self::IS_AUTHENTICATED_FULLY === $attribute
+ && $this->authenticationTrustResolver->isFullFledged($token)) {
+ return VoterInterface::ACCESS_GRANTED;
+ }
+
+ if (self::IS_AUTHENTICATED_REMEMBERED === $attribute
+ && ($this->authenticationTrustResolver->isRememberMe($token)
+ || $this->authenticationTrustResolver->isFullFledged($token))) {
+ return VoterInterface::ACCESS_GRANTED;
+ }
+
+ if (self::IS_AUTHENTICATED_ANONYMOUSLY === $attribute
+ && ($this->authenticationTrustResolver->isAnonymous($token)
+ || $this->authenticationTrustResolver->isRememberMe($token)
+ || $this->authenticationTrustResolver->isFullFledged($token))) {
+ return VoterInterface::ACCESS_GRANTED;
+ }
+ }
+
+ return $result;
+ }
+}
diff --git a/Core/Authorization/Voter/RoleHierarchyVoter.php b/Core/Authorization/Voter/RoleHierarchyVoter.php
new file mode 100644
index 0000000..7bdff3d
--- /dev/null
+++ b/Core/Authorization/Voter/RoleHierarchyVoter.php
@@ -0,0 +1,41 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Authorization\Voter;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
+
+/**
+ * RoleHierarchyVoter uses a RoleHierarchy to determine the roles granted to
+ * the user before voting.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class RoleHierarchyVoter extends RoleVoter
+{
+ protected $roleHierarchy;
+
+ public function __construct(RoleHierarchyInterface $roleHierarchy, $prefix = 'ROLE_')
+ {
+ $this->roleHierarchy = $roleHierarchy;
+
+ parent::__construct($prefix);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function extractRoles(TokenInterface $token)
+ {
+ return $this->roleHierarchy->getReachableRoles($token->getRoles());
+ }
+}
diff --git a/Core/Authorization/Voter/RoleVoter.php b/Core/Authorization/Voter/RoleVoter.php
new file mode 100644
index 0000000..426093a
--- /dev/null
+++ b/Core/Authorization/Voter/RoleVoter.php
@@ -0,0 +1,79 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Authorization\Voter;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+
+/**
+ * RoleVoter votes if any attribute starts with a given prefix.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class RoleVoter implements VoterInterface
+{
+ protected $prefix;
+
+ /**
+ * Constructor.
+ *
+ * @param string $prefix The role prefix
+ */
+ public function __construct($prefix = 'ROLE_')
+ {
+ $this->prefix = $prefix;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supportsAttribute($attribute)
+ {
+ return 0 === strpos($attribute, $this->prefix);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supportsClass($class)
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function vote(TokenInterface $token, $object, array $attributes)
+ {
+ $result = VoterInterface::ACCESS_ABSTAIN;
+ $roles = $this->extractRoles($token);
+
+ foreach ($attributes as $attribute) {
+ if (!$this->supportsAttribute($attribute)) {
+ continue;
+ }
+
+ $result = VoterInterface::ACCESS_DENIED;
+ foreach ($roles as $role) {
+ if ($attribute === $role->getRole()) {
+ return VoterInterface::ACCESS_GRANTED;
+ }
+ }
+ }
+
+ return $result;
+ }
+
+ protected function extractRoles(TokenInterface $token)
+ {
+ return $token->getRoles();
+ }
+}
diff --git a/Core/Authorization/Voter/VoterInterface.php b/Core/Authorization/Voter/VoterInterface.php
new file mode 100644
index 0000000..add6e19
--- /dev/null
+++ b/Core/Authorization/Voter/VoterInterface.php
@@ -0,0 +1,58 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Authorization\Voter;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+
+/**
+ * VoterInterface is the interface implemented by all voters.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+interface VoterInterface
+{
+ const ACCESS_GRANTED = 1;
+ const ACCESS_ABSTAIN = 0;
+ const ACCESS_DENIED = -1;
+
+ /**
+ * Checks if the voter supports the given attribute.
+ *
+ * @param string $attribute An attribute
+ *
+ * @return Boolean true if this Voter supports the attribute, false otherwise
+ */
+ function supportsAttribute($attribute);
+
+ /**
+ * Checks if the voter supports the given class.
+ *
+ * @param string $class A class name
+ *
+ * @return true if this Voter can process the class
+ */
+ function supportsClass($class);
+
+ /**
+ * Returns the vote for the given parameters.
+ *
+ * This method must return one of the following constant:
+ * ACCESS_GRANTED, ACCESS_DENIED, or ACCESS_ABSTAIN.
+ *
+ * @param TokenInterface $token A TokenInterface instance
+ * @param object $object The object to secure
+ * @param array $attributes An array of attributes associated with the method being invoked
+ *
+ * @return integer either ACCESS_GRANTED, ACCESS_ABSTAIN, or ACCESS_DENIED
+ */
+ function vote(TokenInterface $token, $object, array $attributes);
+}
diff --git a/Core/Encoder/BasePasswordEncoder.php b/Core/Encoder/BasePasswordEncoder.php
new file mode 100644
index 0000000..01f471c
--- /dev/null
+++ b/Core/Encoder/BasePasswordEncoder.php
@@ -0,0 +1,91 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Encoder;
+
+/**
+ * BasePasswordEncoder is the base class for all password encoders.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+abstract class BasePasswordEncoder implements PasswordEncoderInterface
+{
+ /**
+ * Demerges a merge password and salt string.
+ *
+ * @param string $mergedPasswordSalt The merged password and salt string
+ *
+ * @return array An array where the first element is the password and the second the salt
+ */
+ protected function demergePasswordAndSalt($mergedPasswordSalt)
+ {
+ if (empty($mergedPasswordSalt)) {
+ return array('', '');
+ }
+
+ $password = $mergedPasswordSalt;
+ $salt = '';
+ $saltBegins = strrpos($mergedPasswordSalt, '{');
+
+ if (false !== $saltBegins && $saltBegins + 1 < strlen($mergedPasswordSalt)) {
+ $salt = substr($mergedPasswordSalt, $saltBegins + 1, -1);
+ $password = substr($mergedPasswordSalt, 0, $saltBegins);
+ }
+
+ return array($password, $salt);
+ }
+
+ /**
+ * Merges a password and a salt.
+ *
+ * @param string $password the password to be used
+ * @param string $salt the salt to be used
+ *
+ * @return string a merged password and salt
+ */
+ protected function mergePasswordAndSalt($password, $salt)
+ {
+ if (empty($salt)) {
+ return $password;
+ }
+
+ if (false !== strrpos($salt, '{') || false !== strrpos($salt, '}')) {
+ throw new \InvalidArgumentException('Cannot use { or } in salt.');
+ }
+
+ return $password.'{'.$salt.'}';
+ }
+
+ /**
+ * Compares two passwords.
+ *
+ * This method implements a constant-time algorithm to compare passwords to
+ * avoid (remote) timing attacks.
+ *
+ * @param string $password1 The first password
+ * @param string $password2 The second password
+ *
+ * @return Boolean true if the two passwords are the same, false otherwise
+ */
+ protected function comparePasswords($password1, $password2)
+ {
+ if (strlen($password1) !== strlen($password2)) {
+ return false;
+ }
+
+ $result = 0;
+ for ($i = 0; $i < strlen($password1); $i++) {
+ $result |= ord($password1[$i]) ^ ord($password2[$i]);
+ }
+
+ return 0 === $result;
+ }
+}
diff --git a/Core/Encoder/EncoderFactory.php b/Core/Encoder/EncoderFactory.php
new file mode 100644
index 0000000..0f218fe
--- /dev/null
+++ b/Core/Encoder/EncoderFactory.php
@@ -0,0 +1,77 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Encoder;
+
+use Symfony\Component\Security\Core\User\AccountInterface;
+
+/**
+ * A generic encoder factory implementation
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class EncoderFactory implements EncoderFactoryInterface
+{
+ protected $encoders;
+ protected $encoderMap;
+
+ public function __construct(array $encoderMap)
+ {
+ $this->encoders = array();
+ $this->encoderMap = $encoderMap;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getEncoder(AccountInterface $account)
+ {
+ foreach ($this->encoders as $class => $encoder) {
+ if ($account instanceof $class) {
+ return $encoder;
+ }
+ }
+
+ return $this->createEncoder($account);
+ }
+
+ /**
+ * Adds an encoder instance to the factory
+ *
+ * @param string $class
+ * @param PasswordEncoderInterface $encoder
+ * @return void
+ */
+ public function addEncoder($class, PasswordEncoderInterface $encoder)
+ {
+ $this->encoders[$class] = $encoder;
+ }
+
+ /**
+ * Creates the actual encoder instance
+ *
+ * @param AccountInterface $account
+ * @return PasswordEncoderInterface
+ */
+ protected function createEncoder($account)
+ {
+ foreach ($this->encoderMap as $class => $config) {
+ if ($account instanceof $class) {
+ $reflection = new \ReflectionClass($config['class']);
+ $this->encoders[$class] = $reflection->newInstanceArgs($config['arguments']);
+
+ return $this->encoders[$class];
+ }
+ }
+
+ throw new \InvalidArgumentException(sprintf('No encoder has been configured for account "%s".', get_class($account)));
+ }
+} \ No newline at end of file
diff --git a/Core/Encoder/EncoderFactoryInterface.php b/Core/Encoder/EncoderFactoryInterface.php
new file mode 100644
index 0000000..2bdf6fc
--- /dev/null
+++ b/Core/Encoder/EncoderFactoryInterface.php
@@ -0,0 +1,30 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Encoder;
+
+use Symfony\Component\Security\Core\User\AccountInterface;
+
+/**
+ * EncoderFactoryInterface to support different encoders for different accounts.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+interface EncoderFactoryInterface
+{
+ /**
+ * Returns the password encoder to use for the given account
+ *
+ * @param AccountInterface $account
+ * @return PasswordEncoderInterface never null
+ */
+ function getEncoder(AccountInterface $account);
+} \ No newline at end of file
diff --git a/Core/Encoder/MessageDigestPasswordEncoder.php b/Core/Encoder/MessageDigestPasswordEncoder.php
new file mode 100644
index 0000000..811dd4c
--- /dev/null
+++ b/Core/Encoder/MessageDigestPasswordEncoder.php
@@ -0,0 +1,65 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Encoder;
+
+/**
+ * MessageDigestPasswordEncoder uses a message digest algorithm.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class MessageDigestPasswordEncoder extends BasePasswordEncoder
+{
+ protected $algorithm;
+ protected $encodeHashAsBase64;
+
+ /**
+ * Constructor.
+ *
+ * @param string $algorithm The digest algorithm to use
+ * @param Boolean $encodeHashAsBase64 Whether to base64 encode the password hash
+ * @param integer $iterations The number of iterations to use to stretch the password hash
+ */
+ public function __construct($algorithm = 'sha256', $encodeHashAsBase64 = false, $iterations = 1)
+ {
+ $this->algorithm = $algorithm;
+ $this->encodeHashAsBase64 = $encodeHashAsBase64;
+ $this->iterations = $iterations;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function encodePassword($raw, $salt)
+ {
+ if (!in_array($this->algorithm, hash_algos(), true)) {
+ throw new \LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm));
+ }
+
+ $salted = $this->mergePasswordAndSalt($raw, $salt);
+ $digest = hash($this->algorithm, $salted, true);
+
+ // "stretch" hash
+ for ($i = 1; $i < $this->iterations; $i++) {
+ $digest = hash($this->algorithm, $digest, true);
+ }
+
+ return $this->encodeHashAsBase64 ? base64_encode($digest) : bin2hex($digest);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isPasswordValid($encoded, $raw, $salt)
+ {
+ return $this->comparePasswords($encoded, $this->encodePassword($raw, $salt));
+ }
+}
diff --git a/Core/Encoder/PasswordEncoderInterface.php b/Core/Encoder/PasswordEncoderInterface.php
new file mode 100644
index 0000000..393b779
--- /dev/null
+++ b/Core/Encoder/PasswordEncoderInterface.php
@@ -0,0 +1,41 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Encoder;
+
+/**
+ * PasswordEncoderInterface is the interface for all encoders.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+interface PasswordEncoderInterface
+{
+ /**
+ * Encodes the raw password.
+ *
+ * @param string $raw The password to encode
+ * @param string $salt The salt
+ *
+ * @return string The encoded password
+ */
+ function encodePassword($raw, $salt);
+
+ /**
+ * Checks a raw password against an encoded password.
+ *
+ * @param string $encoded An encoded password
+ * @param string $raw A raw password
+ * @param string $salt The salt
+ *
+ * @return Boolean true if the password is valid, false otherwise
+ */
+ function isPasswordValid($encoded, $raw, $salt);
+}
diff --git a/Core/Encoder/PlaintextPasswordEncoder.php b/Core/Encoder/PlaintextPasswordEncoder.php
new file mode 100644
index 0000000..98982b0
--- /dev/null
+++ b/Core/Encoder/PlaintextPasswordEncoder.php
@@ -0,0 +1,49 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Encoder;
+
+/**
+ * PlaintextPasswordEncoder does not do any encoding.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class PlaintextPasswordEncoder extends BasePasswordEncoder
+{
+ protected $ignorePasswordCase;
+
+ public function __construct($ignorePasswordCase = false)
+ {
+ $this->ignorePasswordCase = $ignorePasswordCase;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function encodePassword($raw, $salt)
+ {
+ return $this->mergePasswordAndSalt($raw, $salt);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isPasswordValid($encoded, $raw, $salt)
+ {
+ $pass2 = $this->mergePasswordAndSalt($raw, $salt);
+
+ if (!$this->ignorePasswordCase) {
+ return $this->comparePasswords($encoded, $pass2);
+ } else {
+ return $this->comparePasswords(strtolower($encoded), strtolower($pass2));
+ }
+ }
+}
diff --git a/Core/Exception/AccessDeniedException.php b/Core/Exception/AccessDeniedException.php
new file mode 100644
index 0000000..d065ed7
--- /dev/null
+++ b/Core/Exception/AccessDeniedException.php
@@ -0,0 +1,25 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Exception;
+
+/**
+ * AccessDeniedException is thrown when the account has not the required role.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class AccessDeniedException extends \RuntimeException
+{
+ public function __construct($message = 'Access Denied', \Exception $previous = null)
+ {
+ parent::__construct($message, 403, $previous);
+ }
+}
diff --git a/Core/Exception/AccountExpiredException.php b/Core/Exception/AccountExpiredException.php
new file mode 100644
index 0000000..f0a09f7
--- /dev/null
+++ b/Core/Exception/AccountExpiredException.php
@@ -0,0 +1,21 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Exception;
+
+/**
+ * AccountExpiredException is thrown when the user account has expired.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class AccountExpiredException extends AccountStatusException
+{
+}
diff --git a/Core/Exception/AccountStatusException.php b/Core/Exception/AccountStatusException.php
new file mode 100644
index 0000000..4828d20
--- /dev/null
+++ b/Core/Exception/AccountStatusException.php
@@ -0,0 +1,22 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Exception;
+
+/**
+ * AccountStatusException is the base class for authentication exceptions
+ * caused by the user account status.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+abstract class AccountStatusException extends AuthenticationException
+{
+}
diff --git a/Core/Exception/AuthenticationCredentialsNotFoundException.php b/Core/Exception/AuthenticationCredentialsNotFoundException.php
new file mode 100644
index 0000000..4f95127
--- /dev/null
+++ b/Core/Exception/AuthenticationCredentialsNotFoundException.php
@@ -0,0 +1,22 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Exception;
+
+/**
+ * AuthenticationCredentialsNotFoundException is thrown when an authentication is rejected
+ * because no Token is available.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class AuthenticationCredentialsNotFoundException extends AuthenticationException
+{
+}
diff --git a/Core/Exception/AuthenticationException.php b/Core/Exception/AuthenticationException.php
new file mode 100644
index 0000000..a43b998
--- /dev/null
+++ b/Core/Exception/AuthenticationException.php
@@ -0,0 +1,39 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Exception;
+
+/**
+ * AuthenticationException is the base class for all authentication exceptions.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class AuthenticationException extends \RuntimeException
+{
+ protected $extraInformation;
+
+ public function __construct($message, $extraInformation = null, $code = 0, \Exception $previous = null)
+ {
+ parent::__construct($message, $code, $previous);
+
+ $this->extraInformation = $extraInformation;
+ }
+
+ public function getExtraInformation()
+ {
+ return $this->extraInformation;
+ }
+
+ public function setExtraInformation($extraInformation)
+ {
+ $this->extraInformation = $extraInformation;
+ }
+}
diff --git a/Core/Exception/AuthenticationServiceException.php b/Core/Exception/AuthenticationServiceException.php
new file mode 100644
index 0000000..02fcc2f
--- /dev/null
+++ b/Core/Exception/AuthenticationServiceException.php
@@ -0,0 +1,21 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Exception;
+
+/**
+ * AuthenticationServiceException is thrown when an authentication request could not be processed due to a system problem.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class AuthenticationServiceException extends AuthenticationException
+{
+}
diff --git a/Core/Exception/BadCredentialsException.php b/Core/Exception/BadCredentialsException.php
new file mode 100644
index 0000000..797a806
--- /dev/null
+++ b/Core/Exception/BadCredentialsException.php
@@ -0,0 +1,25 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Exception;
+
+/**
+ * BadCredentialsException is thrown when the user credentials are invalid.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class BadCredentialsException extends AuthenticationException
+{
+ public function __construct($message, $code = 0, \Exception $previous = null)
+ {
+ parent::__construct($message, null, $code, $previous);
+ }
+}
diff --git a/Core/Exception/CookieTheftException.php b/Core/Exception/CookieTheftException.php
new file mode 100644
index 0000000..64a06ca
--- /dev/null
+++ b/Core/Exception/CookieTheftException.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace Symfony\Component\Security\Core\Exception;
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * This exception is thrown when the RememberMeServices implementation
+ * detects that a presented cookie has already been used by someone else.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class CookieTheftException extends AuthenticationException
+{
+} \ No newline at end of file
diff --git a/Core/Exception/CredentialsExpiredException.php b/Core/Exception/CredentialsExpiredException.php
new file mode 100644
index 0000000..43ba982
--- /dev/null
+++ b/Core/Exception/CredentialsExpiredException.php
@@ -0,0 +1,21 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Exception;
+
+/**
+ * CredentialsExpiredException is thrown when the user account credentials have expired.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class CredentialsExpiredException extends AccountStatusException
+{
+}
diff --git a/Core/Exception/DisabledException.php b/Core/Exception/DisabledException.php
new file mode 100644
index 0000000..fd87947
--- /dev/null
+++ b/Core/Exception/DisabledException.php
@@ -0,0 +1,21 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Exception;
+
+/**
+ * DisabledException is thrown when the user account is disabled.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class DisabledException extends AccountStatusException
+{
+}
diff --git a/Core/Exception/InsufficientAuthenticationException.php b/Core/Exception/InsufficientAuthenticationException.php
new file mode 100644
index 0000000..3fbba35
--- /dev/null
+++ b/Core/Exception/InsufficientAuthenticationException.php
@@ -0,0 +1,23 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Exception;
+
+/**
+ * InsufficientAuthenticationException is thrown if the user credentials are not sufficiently trusted.
+ *
+ * This is the case when a user is anonymous and the resource to be displayed has an access role.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class InsufficientAuthenticationException extends AuthenticationException
+{
+}
diff --git a/Core/Exception/LockedException.php b/Core/Exception/LockedException.php
new file mode 100644
index 0000000..8ea820f
--- /dev/null
+++ b/Core/Exception/LockedException.php
@@ -0,0 +1,21 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Exception;
+
+/**
+ * LockedException is thrown if the user account is locked.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class LockedException extends AccountStatusException
+{
+}
diff --git a/Core/Exception/NonceExpiredException.php b/Core/Exception/NonceExpiredException.php
new file mode 100644
index 0000000..5e6a0c5
--- /dev/null
+++ b/Core/Exception/NonceExpiredException.php
@@ -0,0 +1,27 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\Security\EntryPoint;
+
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Core\Authentication\EntryPoint\AuthenticationEntryPointInterface;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+
+/**
+ * NonceExpiredException is thrown when an authentication is rejected because
+ * the digest nonce has expired.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class NonceExpiredException extends AuthenticationException
+{
+}
diff --git a/Core/Exception/ProviderNotFoundException.php b/Core/Exception/ProviderNotFoundException.php
new file mode 100644
index 0000000..50112c5
--- /dev/null
+++ b/Core/Exception/ProviderNotFoundException.php
@@ -0,0 +1,22 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Exception;
+
+/**
+ * ProviderNotFoundException is thrown when no AuthenticationProviderInterface instance
+ * supports an authentication Token.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class ProviderNotFoundException extends AuthenticationException
+{
+}
diff --git a/Core/Exception/TokenNotFoundException.php b/Core/Exception/TokenNotFoundException.php
new file mode 100644
index 0000000..1c13421
--- /dev/null
+++ b/Core/Exception/TokenNotFoundException.php
@@ -0,0 +1,20 @@
+<?php
+namespace Symfony\Component\Security\Core\Exception;
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * TokenNotFoundException is thrown if a Token cannot be found.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class TokenNotFoundException extends AuthenticationException
+{
+}
diff --git a/Core/Exception/UnsupportedAccountException.php b/Core/Exception/UnsupportedAccountException.php
new file mode 100644
index 0000000..0704b65
--- /dev/null
+++ b/Core/Exception/UnsupportedAccountException.php
@@ -0,0 +1,22 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Exception;
+
+/**
+ * This exception is thrown when an account is reloaded from a provider which
+ * doesn't support the passed implementation of AccountInterface.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class UnsupportedAccountException extends AuthenticationServiceException
+{
+} \ No newline at end of file
diff --git a/Core/Exception/UsernameNotFoundException.php b/Core/Exception/UsernameNotFoundException.php
new file mode 100644
index 0000000..a1733fe
--- /dev/null
+++ b/Core/Exception/UsernameNotFoundException.php
@@ -0,0 +1,21 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Exception;
+
+/**
+ * UsernameNotFoundException is thrown if a User cannot be found by its username.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class UsernameNotFoundException extends AuthenticationException
+{
+}
diff --git a/Core/Role/Role.php b/Core/Role/Role.php
new file mode 100644
index 0000000..20e4fd5
--- /dev/null
+++ b/Core/Role/Role.php
@@ -0,0 +1,41 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Role;
+
+/**
+ * Role is a simple implementation of a RoleInterface where the role is a
+ * string.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class Role implements RoleInterface
+{
+ protected $role;
+
+ /**
+ * Constructor.
+ *
+ * @param string $role The role name
+ */
+ public function __construct($role)
+ {
+ $this->role = (string) $role;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRole()
+ {
+ return $this->role;
+ }
+}
diff --git a/Core/Role/RoleHierarchy.php b/Core/Role/RoleHierarchy.php
new file mode 100644
index 0000000..9556801
--- /dev/null
+++ b/Core/Role/RoleHierarchy.php
@@ -0,0 +1,77 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Role;
+
+/**
+ * RoleHierarchy defines a role hierarchy.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class RoleHierarchy implements RoleHierarchyInterface
+{
+ protected $hierarchy;
+ protected $map;
+
+ /**
+ * Constructor.
+ *
+ * @param array $hierarchy An array defining the hierarchy
+ */
+ public function __construct(array $hierarchy)
+ {
+ $this->hierarchy = $hierarchy;
+
+ $this->buildRoleMap();
+ }
+
+ /**
+ * Returns an array of all roles reachable by the given ones.
+ *
+ * @param RoleInterface[] $roles An array of RoleInterface instances
+ *
+ * @return RoleInterface[] An array of RoleInterface instances
+ */
+ public function getReachableRoles(array $roles)
+ {
+ $reachableRoles = $roles;
+ foreach ($roles as $role) {
+ if (!isset($this->map[$role->getRole()])) {
+ continue;
+ }
+
+ foreach ($this->map[$role->getRole()] as $r) {
+ $reachableRoles[] = new Role($r);
+ }
+ }
+
+ return $reachableRoles;
+ }
+
+ protected function buildRoleMap()
+ {
+ $this->map = array();
+ foreach ($this->hierarchy as $main => $roles) {
+ $this->map[$main] = $roles;
+ $visited = array();
+ $additionalRoles = $roles;
+ while ($role = array_shift($additionalRoles)) {
+ if (!isset($this->hierarchy[$role])) {
+ continue;
+ }
+
+ $visited[] = $role;
+ $this->map[$main] = array_unique(array_merge($this->map[$main], $this->hierarchy[$role]));
+ $additionalRoles = array_merge($additionalRoles, array_diff($this->hierarchy[$role], $visited));
+ }
+ }
+ }
+}
diff --git a/Core/Role/RoleHierarchyInterface.php b/Core/Role/RoleHierarchyInterface.php
new file mode 100644
index 0000000..9f5cd5d
--- /dev/null
+++ b/Core/Role/RoleHierarchyInterface.php
@@ -0,0 +1,32 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Role;
+
+/**
+ * RoleHierarchyInterface is the interface for a role hierarchy.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+interface RoleHierarchyInterface
+{
+ /**
+ * Returns an array of all reachable roles.
+ *
+ * Reachable roles are the roles directly assigned but also all roles that
+ * are transitively reachable from them in the role hierarchy.
+ *
+ * @param array $roles An array of directly assigned roles
+ *
+ * @return array An array of all reachable roles
+ */
+ function getReachableRoles(array $roles);
+}
diff --git a/Core/Role/RoleInterface.php b/Core/Role/RoleInterface.php
new file mode 100644
index 0000000..923a933
--- /dev/null
+++ b/Core/Role/RoleInterface.php
@@ -0,0 +1,35 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Role;
+
+/**
+ * RoleInterface represents a role granted to a user.
+ *
+ * A role must either have a string representation or it needs to be explicitly
+ * supported by an at least one AccessDecisionManager.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+interface RoleInterface
+{
+ /**
+ * Returns the role.
+ *
+ * This method returns a string representation whenever possible.
+ *
+ * When the role cannot be represented with sufficient precision by a
+ * string, it should return null.
+ *
+ * @return string|null A string representation of the role, or null
+ */
+ function getRole();
+}
diff --git a/Core/Role/SwitchUserRole.php b/Core/Role/SwitchUserRole.php
new file mode 100644
index 0000000..589129c
--- /dev/null
+++ b/Core/Role/SwitchUserRole.php
@@ -0,0 +1,48 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Role;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+
+/**
+ * SwitchUserRole is used when the current user temporarily impersonates
+ * another one.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class SwitchUserRole extends Role
+{
+ protected $source;
+
+ /**
+ * Constructor.
+ *
+ * @param string $role The role as a string
+ * @param TokenInterface $source The original token
+ */
+ public function __construct($role, TokenInterface $source)
+ {
+ parent::__construct($role);
+
+ $this->source = $source;
+ }
+
+ /**
+ * Returns the original Token.
+ *
+ * @return TokenInterface The original TokenInterface instance
+ */
+ public function getSource()
+ {
+ return $this->source;
+ }
+}
diff --git a/Core/SecurityContext.php b/Core/SecurityContext.php
new file mode 100644
index 0000000..405ace9
--- /dev/null
+++ b/Core/SecurityContext.php
@@ -0,0 +1,94 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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;
+
+use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
+use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Acl\Voter\FieldVote;
+
+/**
+ * SecurityContext is the main entry point of the Security component.
+ *
+ * It gives access to the token representing the current user authentication.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class SecurityContext
+{
+ const ACCESS_DENIED_ERROR = '_security.403_error';
+ const AUTHENTICATION_ERROR = '_security.last_error';
+ const LAST_USERNAME = '_security.last_username';
+
+ protected $token;
+ protected $accessDecisionManager;
+ protected $authenticationManager;
+ protected $alwaysAuthenticate;
+
+ /**
+ * Constructor.
+ *
+ * @param AccessDecisionManagerInterface|null $accessDecisionManager An AccessDecisionManager instance
+ */
+ public function __construct(AuthenticationManagerInterface $authenticationManager, AccessDecisionManagerInterface $accessDecisionManager = null, $alwaysAuthenticate = false)
+ {
+ $this->authenticationManager = $authenticationManager;
+ $this->accessDecisionManager = $accessDecisionManager;
+ $this->alwaysAuthenticate = $alwaysAuthenticate;
+ }
+
+ public function getUser()
+ {
+ return null === $this->token ? null : $this->token->getUser();
+ }
+
+ public function vote($attributes, $object = null, $field = null)
+ {
+ if (null === $this->token || null === $this->accessDecisionManager) {
+ return false;
+ }
+
+ if ($field !== null) {
+ if (null === $object) {
+ throw new \InvalidArgumentException('$object cannot be null when field is not null.');
+ }
+
+ $object = new FieldVote($object, $field);
+ }
+
+ if ($this->alwaysAuthenticate || !$this->token->isAuthenticated()) {
+ $this->token = $this->authenticationManager->authenticate($this->token);
+ }
+
+ return $this->accessDecisionManager->decide($this->token, (array) $attributes, $object);
+ }
+
+ /**
+ * Gets the currently authenticated token.
+ *
+ * @return TokenInterface|null A TokenInterface instance or null if no authentication information is available
+ */
+ public function getToken()
+ {
+ return $this->token;
+ }
+
+ /**
+ * Sets the currently authenticated token.
+ *
+ * @param TokenInterface $token A TokenInterface token, or null if no further authentication information should be stored
+ */
+ public function setToken(TokenInterface $token = null)
+ {
+ $this->token = $token;
+ }
+}
diff --git a/Core/User/AccountChecker.php b/Core/User/AccountChecker.php
new file mode 100644
index 0000000..76befa6
--- /dev/null
+++ b/Core/User/AccountChecker.php
@@ -0,0 +1,61 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\User;
+
+use Symfony\Component\Security\Core\Exception\CredentialsExpiredException;
+use Symfony\Component\Security\Core\Exception\LockedException;
+use Symfony\Component\Security\Core\Exception\DisabledException;
+use Symfony\Component\Security\Core\Exception\AccountExpiredException;
+
+/**
+ * AccountChecker checks the user account flags.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class AccountChecker implements AccountCheckerInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function checkPreAuth(AccountInterface $account)
+ {
+ if (!$account instanceof AdvancedAccountInterface) {
+ return;
+ }
+
+ if (!$account->isCredentialsNonExpired()) {
+ throw new CredentialsExpiredException('User credentials have expired.', $account);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function checkPostAuth(AccountInterface $account)
+ {
+ if (!$account instanceof AdvancedAccountInterface) {
+ return;
+ }
+
+ if (!$account->isAccountNonLocked()) {
+ throw new LockedException('User account is locked.', $account);
+ }
+
+ if (!$account->isEnabled()) {
+ throw new DisabledException('User account is disabled.', $account);
+ }
+
+ if (!$account->isAccountNonExpired()) {
+ throw new AccountExpiredException('User account has expired.', $account);
+ }
+ }
+}
diff --git a/Core/User/AccountCheckerInterface.php b/Core/User/AccountCheckerInterface.php
new file mode 100644
index 0000000..cf0d68b
--- /dev/null
+++ b/Core/User/AccountCheckerInterface.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\User;
+
+/**
+ * AccountCheckerInterface checks user account when authentication occurs.
+ *
+ * This should not be used to make authentication decisions.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+interface AccountCheckerInterface
+{
+ /**
+ * Checks the user account before authentication.
+ *
+ * @param AccountInterface $account An AccountInterface instance
+ */
+ function checkPreAuth(AccountInterface $account);
+
+ /**
+ * Checks the user account after authentication.
+ *
+ * @param AccountInterface $account An AccountInterface instance
+ */
+ function checkPostAuth(AccountInterface $account);
+}
diff --git a/Core/User/AccountInterface.php b/Core/User/AccountInterface.php
new file mode 100644
index 0000000..1863302
--- /dev/null
+++ b/Core/User/AccountInterface.php
@@ -0,0 +1,74 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\User;
+
+/**
+ * AccountInterface is the interface that user classes must implement.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+interface AccountInterface
+{
+ /**
+ * Returns a string representation of the User.
+ *
+ * @return string A string return of the User
+ */
+ function __toString();
+
+ /**
+ * Returns the roles granted to the user.
+ *
+ * @return Role[] The user roles
+ */
+ function getRoles();
+
+ /**
+ * Returns the password used to authenticate the user.
+ *
+ * @return string The password
+ */
+ function getPassword();
+
+ /**
+ * Returns the salt.
+ *
+ * @return string The salt
+ */
+ function getSalt();
+
+ /**
+ * Returns the username used to authenticate the user.
+ *
+ * @return string The username
+ */
+ function getUsername();
+
+ /**
+ * Removes sensitive data from the user.
+ *
+ * @return void
+ */
+ function eraseCredentials();
+
+ /**
+ * The equality comparison should neither be done by referential equality
+ * nor by comparing identities (i.e. getId() === getId()).
+ *
+ * However, you do not need to compare every attribute, but only those that
+ * are relevant for assessing whether re-authentication is required.
+ *
+ * @param AccountInterface $account
+ * @return Boolean
+ */
+ function equals(AccountInterface $account);
+}
diff --git a/Core/User/AdvancedAccountInterface.php b/Core/User/AdvancedAccountInterface.php
new file mode 100644
index 0000000..654ccaf
--- /dev/null
+++ b/Core/User/AdvancedAccountInterface.php
@@ -0,0 +1,48 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\User;
+
+/**
+ * AdvancedAccountInterface adds status flags to a regular account.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+interface AdvancedAccountInterface extends AccountInterface
+{
+ /**
+ * Checks whether the user's account has expired.
+ *
+ * @return Boolean true if the user's account is non expired, false otherwise
+ */
+ function isAccountNonExpired();
+
+ /**
+ * Checks whether the user is locked.
+ *
+ * @return Boolean true if the user is not locked, false otherwise
+ */
+ function isAccountNonLocked();
+
+ /**
+ * Checks whether the user's credentials (password) has expired.
+ *
+ * @return Boolean true if the user's credentials are non expired, false otherwise
+ */
+ function isCredentialsNonExpired();
+
+ /**
+ * Checks whether the user is enabled.
+ *
+ * @return Boolean true if the user is enabled, false otherwise
+ */
+ function isEnabled();
+}
diff --git a/Core/User/InMemoryUserProvider.php b/Core/User/InMemoryUserProvider.php
new file mode 100644
index 0000000..cc15463
--- /dev/null
+++ b/Core/User/InMemoryUserProvider.php
@@ -0,0 +1,98 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\User;
+
+use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
+use Symfony\Component\Security\Core\Exception\UnsupportedAccountException;
+
+/**
+ * InMemoryUserProvider is a simple non persistent user provider.
+ *
+ * Useful for testing, demonstration, prototyping, and for simple needs
+ * (a backend with a unique admin for instance)
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class InMemoryUserProvider implements UserProviderInterface
+{
+ protected $users;
+
+ /**
+ * Constructor.
+ *
+ * The user array is a hash where the keys are usernames and the values are
+ * an array of attributes: 'password', 'enabled', and 'roles'.
+ *
+ * @param array $users An array of users
+ * @param string $name
+ */
+ public function __construct(array $users = array())
+ {
+ foreach ($users as $username => $attributes) {
+ $password = isset($attributes['password']) ? $attributes['password'] : null;
+ $enabled = isset($attributes['enabled']) ? $attributes['enabled'] : true;
+ $roles = isset($attributes['roles']) ? $attributes['roles'] : array();
+ $user = new User($username, $password, $roles, $enabled, true, true, true);
+
+ $this->createUser($user);
+ }
+ }
+
+ /**
+ * Adds a new User to the provider.
+ *
+ * @param AccountInterface $user A AccountInterface instance
+ */
+ public function createUser(AccountInterface $user)
+ {
+ if (isset($this->users[strtolower($user->getUsername())])) {
+ throw new \LogicException('Another user with the same username already exist.');
+ }
+
+ $this->users[strtolower($user->getUsername())] = $user;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function loadUserByUsername($username)
+ {
+ if (!isset($this->users[strtolower($username)])) {
+ throw new UsernameNotFoundException(sprintf('Username "%s" does not exist.', $username));
+ }
+
+ $user = $this->users[strtolower($username)];
+
+ return new User($user->getUsername(), $user->getPassword(), $user->getRoles(), $user->isEnabled(), $user->isAccountNonExpired(),
+ $user->isCredentialsNonExpired(), $user->isAccountNonLocked());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function loadUserByAccount(AccountInterface $account)
+ {
+ if (!$account instanceof User) {
+ throw new UnsupportedAccountException(sprintf('Instances of "%s" are not supported.', get_class($account)));
+ }
+
+ return $this->loadUserByUsername((string) $account);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function supportsClass($class)
+ {
+ return $class === 'Symfony\Component\Security\Core\User\User';
+ }
+}
diff --git a/Core/User/User.php b/Core/User/User.php
new file mode 100644
index 0000000..49f7042
--- /dev/null
+++ b/Core/User/User.php
@@ -0,0 +1,163 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\User;
+
+/**
+ * User is the user implementation used by the in-memory user provider.
+ *
+ * This should not be used for anything else.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class User implements AdvancedAccountInterface
+{
+ protected $username;
+ protected $password;
+ protected $accountNonExpired;
+ protected $credentialsNonExpired;
+ protected $accountNonLocked;
+ protected $roles;
+
+ public function __construct($username, $password, array $roles = array(), $enabled = true, $accountNonExpired = true, $credentialsNonExpired = true, $accountNonLocked = true)
+ {
+ if (empty($username)) {
+ throw new \InvalidArgumentException('The username cannot be empty.');
+ }
+
+ $this->username = $username;
+ $this->password = $password;
+ $this->enabled = $enabled;
+ $this->accountNonExpired = $accountNonExpired;
+ $this->credentialsNonExpired = $credentialsNonExpired;
+ $this->accountNonLocked = $accountNonLocked;
+ $this->roles = $roles;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString()
+ {
+ return $this->username;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRoles()
+ {
+ return $this->roles;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPassword()
+ {
+ return $this->password;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSalt()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getUsername()
+ {
+ return $this->username;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isAccountNonExpired()
+ {
+ return $this->accountNonExpired;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isAccountNonLocked()
+ {
+ return $this->accountNonLocked;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isCredentialsNonExpired()
+ {
+ return $this->credentialsNonExpired;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isEnabled()
+ {
+ return $this->enabled;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function eraseCredentials()
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function equals(AccountInterface $account)
+ {
+ if (!$account instanceof User) {
+ return false;
+ }
+
+ if ($this->password !== $account->getPassword()) {
+ return false;
+ }
+
+ if ($this->getSalt() !== $account->getSalt()) {
+ return false;
+ }
+
+ if ($this->username !== $account->getUsername()) {
+ return false;
+ }
+
+ if ($this->accountNonExpired !== $account->isAccountNonExpired()) {
+ return false;
+ }
+
+ if ($this->accountNonLocked !== $account->isAccountNonLocked()) {
+ return false;
+ }
+
+ if ($this->credentialsNonExpired !== $account->isCredentialsNonExpired()) {
+ return false;
+ }
+
+ if ($this->enabled !== $account->isEnabled()) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/Core/User/UserProviderInterface.php b/Core/User/UserProviderInterface.php
new file mode 100644
index 0000000..70ba0d0
--- /dev/null
+++ b/Core/User/UserProviderInterface.php
@@ -0,0 +1,57 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.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\User;
+
+/**
+ * UserProviderInterface is the implementation that all user provider must
+ * implement.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+interface UserProviderInterface
+{
+ /**
+ * Loads the user for the given username.
+ *
+ * This method must throw UsernameNotFoundException if the user is not
+ * found.
+ *
+ * @throws UsernameNotFoundException if the user is not found
+ * @param string $username The username
+ *
+ * @return AccountInterface
+ */
+ function loadUserByUsername($username);
+
+ /**
+ * Loads the user for the account interface.
+ *
+ * It is up to the implementation if it decides to reload the user data
+ * from the database, or if it simply merges the passed User into the
+ * identity map of an entity manager.
+ *
+ * @throws UnsupportedAccountException if the account is not supported
+ * @param AccountInterface $account
+ *
+ * @return AccountInterface
+ */
+ function loadUserByAccount(AccountInterface $account);
+
+ /**
+ * Whether this provider supports the given user class
+ *
+ * @param string $class
+ *
+ * @return Boolean
+ */
+ function supportsClass($class);
+} \ No newline at end of file