diff options
author | Bernhard Schussek <bernhard.schussek@symfony-project.com> | 2011-03-13 18:10:39 +0100 |
---|---|---|
committer | Bernhard Schussek <bernhard.schussek@symfony-project.com> | 2011-03-13 19:15:25 +0100 |
commit | 263ba4d42870ef5f991540c8b039c2472ba8b204 (patch) | |
tree | 90a84bb2a178be744ef3815c6a2bb7268baa9f34 /Http | |
parent | 4a5d6729bc8c7f4adc89c153606617390bb24ca4 (diff) | |
parent | 5a06947e48c33dc57e21e4316c8b7c6e8f5827b0 (diff) | |
download | symfony-security-263ba4d42870ef5f991540c8b039c2472ba8b204.zip symfony-security-263ba4d42870ef5f991540c8b039c2472ba8b204.tar.gz symfony-security-263ba4d42870ef5f991540c8b039c2472ba8b204.tar.bz2 |
Merge remote branch 'symfony/master' into event-manager
Conflicts:
src/Symfony/Bundle/FrameworkBundle/Debug/TraceableEventManager.php
src/Symfony/Bundle/WebProfilerBundle/WebDebugToolbarListener.php
src/Symfony/Component/Security/Http/Firewall.php
src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php
src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php
src/Symfony/Component/Security/Http/Firewall/AccessListener.php
src/Symfony/Component/Security/Http/Firewall/AnonymousAuthenticationListener.php
src/Symfony/Component/Security/Http/Firewall/BasicAuthenticationListener.php
src/Symfony/Component/Security/Http/Firewall/ChannelListener.php
src/Symfony/Component/Security/Http/Firewall/ContextListener.php
src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php
src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php
src/Symfony/Component/Security/Http/Firewall/ListenerInterface.php
src/Symfony/Component/Security/Http/Firewall/LogoutListener.php
src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php
src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php
tests/Symfony/Tests/Component/Security/Http/Firewall/RememberMeListenerTest.php
Diffstat (limited to 'Http')
29 files changed, 346 insertions, 620 deletions
diff --git a/Http/AccessMap.php b/Http/AccessMap.php index ef7a4f0..6d12b42 100644 --- a/Http/AccessMap.php +++ b/Http/AccessMap.php @@ -22,7 +22,7 @@ use Symfony\Component\HttpFoundation\Request; */ class AccessMap { - protected $map = array(); + private $map = array(); /** * Constructor. diff --git a/Http/EntryPoint/BasicAuthenticationEntryPoint.php b/Http/EntryPoint/BasicAuthenticationEntryPoint.php index 968986c..984fbec 100644 --- a/Http/EntryPoint/BasicAuthenticationEntryPoint.php +++ b/Http/EntryPoint/BasicAuthenticationEntryPoint.php @@ -24,7 +24,7 @@ use Symfony\Component\HttpKernel\Event\GetResponseEventArgs; */ class BasicAuthenticationEntryPoint implements AuthenticationEntryPointInterface { - protected $realmName; + private $realmName; public function __construct($realmName) { diff --git a/Http/EntryPoint/DigestAuthenticationEntryPoint.php b/Http/EntryPoint/DigestAuthenticationEntryPoint.php index 06799bc..578a3e8 100644 --- a/Http/EntryPoint/DigestAuthenticationEntryPoint.php +++ b/Http/EntryPoint/DigestAuthenticationEntryPoint.php @@ -26,10 +26,10 @@ use Symfony\Component\HttpKernel\Event\GetResponseEventArgs; */ class DigestAuthenticationEntryPoint implements AuthenticationEntryPointInterface { - protected $key; - protected $realmName; - protected $nonceValiditySeconds; - protected $logger; + private $key; + private $realmName; + private $nonceValiditySeconds; + private $logger; public function __construct($realmName, $key, $nonceValiditySeconds = 300, LoggerInterface $logger = null) { @@ -62,14 +62,4 @@ class DigestAuthenticationEntryPoint implements AuthenticationEntryPointInterfac return $response; } - - public function getKey() - { - return $this->key; - } - - public function getRealmName() - { - return $this->realmName; - } } diff --git a/Http/EntryPoint/FormAuthenticationEntryPoint.php b/Http/EntryPoint/FormAuthenticationEntryPoint.php index ddd9bb7..f45f9ea 100644 --- a/Http/EntryPoint/FormAuthenticationEntryPoint.php +++ b/Http/EntryPoint/FormAuthenticationEntryPoint.php @@ -26,8 +26,8 @@ use Symfony\Component\HttpKernel\Event\GetResponseEventArgs; */ class FormAuthenticationEntryPoint implements AuthenticationEntryPointInterface { - protected $loginPath; - protected $useForward; + private $loginPath; + private $useForward; /** * Constructor diff --git a/Http/EntryPoint/RetryAuthenticationEntryPoint.php b/Http/EntryPoint/RetryAuthenticationEntryPoint.php index c624c54..1fb6cc1 100644 --- a/Http/EntryPoint/RetryAuthenticationEntryPoint.php +++ b/Http/EntryPoint/RetryAuthenticationEntryPoint.php @@ -27,8 +27,8 @@ use Symfony\Component\HttpKernel\Event\GetResponseEventArgs; */ class RetryAuthenticationEntryPoint implements AuthenticationEntryPointInterface { - protected $httpPort; - protected $httpsPort; + private $httpPort; + private $httpsPort; public function __construct($httpPort = 80, $httpsPort = 443) { diff --git a/Http/Event/SwitchUserEventArgs.php b/Http/Event/SwitchUserEventArgs.php index be38036..c88a500 100644 --- a/Http/Event/SwitchUserEventArgs.php +++ b/Http/Event/SwitchUserEventArgs.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Security\Http\Event; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\Security\Core\User\AccountInterface; +use Symfony\Component\Security\Core\User\UserInterface; use Doctrine\Common\EventArgs; class SwitchUserEventArgs extends EventArgs @@ -21,7 +21,7 @@ class SwitchUserEventArgs extends EventArgs private $targetUser; - public function __construct(Request $request, AccountInterface $targetUser) + public function __construct(Request $request, UserInterface $targetUser) { $this->request = $request; $this->targetUser = $targetUser; diff --git a/Http/Firewall.php b/Http/Firewall.php index 8fe2bcb..bff88b9 100644 --- a/Http/Firewall.php +++ b/Http/Firewall.php @@ -29,9 +29,9 @@ use Doctrine\Common\EventManager; */ class Firewall { - protected $map; - protected $evm; - protected $currentListeners; + private $map; + private $evm; + private $currentListeners; /** * Constructor. @@ -56,38 +56,19 @@ class Firewall return; } - $request = $eventArgs->getRequest(); - - // disconnect all listeners from onCoreSecurity to avoid the overhead - // of most listeners having to do this manually - $this->evm->removeEventListeners(Events::onCoreSecurity); - - // ensure that listeners disconnect from wherever they have connected to - foreach ($this->currentListeners as $listener) { - $listener->unregister($this->evm); - } - // register listeners for this firewall - list($listeners, $exception) = $this->map->getListeners($request); + list($listeners, $exception) = $this->map->getListeners($eventArgs->getRequest()); if (null !== $exception) { $exception->register($this->evm); } - foreach ($listeners as $listener) { - $listener->register($this->evm); - } - - // save current listener instances - $this->currentListeners = $listeners; - if (null !== $exception) { - $this->currentListeners[] = $exception; - } // initiate the listener chain - $securityEventArgs = new GetResponseEventArgs($eventArgs->getKernel(), $request, $eventArgs->getRequestType()); - $this->evm->dispatchEvent($securityEventArgs); + foreach ($listeners as $listener) { + $response = $listener->handle($eventArgs); - if ($securityEventArgs->hasResponse()) { - $eventArgs->setResponse($securityEventArgs->getResponse()); + if ($eventArgs->hasResponse()) { + break; + } } } } diff --git a/Http/Firewall/AbstractAuthenticationListener.php b/Http/Firewall/AbstractAuthenticationListener.php index 9af2a1c..f00d5e8 100644 --- a/Http/Firewall/AbstractAuthenticationListener.php +++ b/Http/Firewall/AbstractAuthenticationListener.php @@ -35,8 +35,8 @@ use Doctrine\Common\EventManager; * Subclasses likely have to implement the following: * - an TokenInterface to hold authentication related data * - an AuthenticationProvider to perform the actual authentication of the - * token, retrieve the AccountInterface implementation from a database, and - * perform the specific account checks using the AccountChecker + * token, retrieve the UserInterface implementation from a database, and + * perform the specific account checks using the UserChecker * * By default, this listener only is active for a specific path, e.g. * /login_check. If you want to change this behavior, you can overwrite the @@ -47,16 +47,16 @@ use Doctrine\Common\EventManager; */ abstract class AbstractAuthenticationListener implements ListenerInterface { - protected $securityContext; - protected $authenticationManager; - protected $sessionStrategy; - protected $providerKey; - protected $evm; protected $options; - protected $successHandler; - protected $failureHandler; protected $logger; - protected $rememberMeServices; + protected $authenticationManager; + protected $providerKey; + private $securityContext; + private $sessionStrategy; + private $evm; + private $successHandler; + private $failureHandler; + private $rememberMeServices; /** * Constructor. @@ -66,7 +66,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface * @param array $options An array of options for the processing of a successful, or failed authentication attempt * @param LoggerInterface $logger A LoggerInterface instance */ - public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, $providerKey, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null) + public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, $providerKey, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null, EventManager $evm = null) { if (empty($providerKey)) { throw new \InvalidArgumentException('$providerKey must not be empty.'); @@ -89,6 +89,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface 'failure_forward' => false, ), $options); $this->logger = $logger; + $this->evm = $evm; } /** @@ -102,25 +103,6 @@ abstract class AbstractAuthenticationListener implements ListenerInterface } /** - * Subscribe to the onCoreSecurity event - * - * @param EventManager $evm An EventManager instance - */ - public function register(EventManager $evm) - { - $evm->addEventListener(KernelEvents::onCoreSecurity, $this); - - $this->evm = $evm; - } - - /** - * {@inheritDoc} - */ - public function unregister(EventManager $evm) - { - } - - /** * Handles form based authentication. * * @param Event $event An Event instance @@ -170,7 +152,18 @@ abstract class AbstractAuthenticationListener implements ListenerInterface return $this->options['check_path'] === $request->getPathInfo(); } - protected function onFailure(GetResponseEventArgs $eventArgs, Request $request, AuthenticationException $failed) + /** + * Performs authentication. + * + * @param Request $request A Request instance + * + * @return TokenInterface The authenticated token, or null if full authentication is not possible + * + * @throws AuthenticationException if the authentication fails + */ + abstract protected function attemptAuthentication(Request $request); + + private function onFailure(GetResponseEventArgs $eventArgs, Request $request, AuthenticationException $failed) { if (null !== $this->logger) { $this->logger->debug(sprintf('Authentication request failed: %s', $failed->getMessage())); @@ -206,7 +199,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface return new RedirectResponse(0 !== strpos($this->options['failure_path'], 'http') ? $request->getUriForPath($this->options['failure_path']) : $this->options['failure_path'], 302); } - protected function onSuccess(GetResponseEventArgs $eventArgs, Request $request, TokenInterface $token) + private function onSuccess(GetResponseEventArgs $eventArgs, Request $request, TokenInterface $token) { if (null !== $this->logger) { $this->logger->debug('User has been authenticated successfully'); @@ -244,7 +237,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface * * @return string */ - protected function determineTargetUrl(Request $request) + private function determineTargetUrl(Request $request) { if ($this->options['always_use_default_target_path']) { return $this->options['default_target_path']; @@ -267,15 +260,4 @@ abstract class AbstractAuthenticationListener implements ListenerInterface return $this->options['default_target_path']; } - - /** - * Performs authentication. - * - * @param Request $request A Request instance - * - * @return TokenInterface The authenticated token, or null if full authentication is not possible - * - * @throws AuthenticationException if the authentication fails - */ - abstract protected function attemptAuthentication(Request $request); } diff --git a/Http/Firewall/AbstractPreAuthenticatedListener.php b/Http/Firewall/AbstractPreAuthenticatedListener.php index 1ed7d86..0177ab7 100644 --- a/Http/Firewall/AbstractPreAuthenticatedListener.php +++ b/Http/Firewall/AbstractPreAuthenticatedListener.php @@ -32,43 +32,25 @@ use Doctrine\Common\EventManager; */ abstract class AbstractPreAuthenticatedListener implements ListenerInterface { - protected $securityContext; - protected $authenticationManager; - protected $providerKey; protected $logger; - protected $evm; + private $securityContext; + private $authenticationManager; + private $providerKey; + private $evm; - public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, LoggerInterface $logger = null) + public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, LoggerInterface $logger = null, EventManager $evm = null) { $this->securityContext = $securityContext; $this->authenticationManager = $authenticationManager; $this->providerKey = $providerKey; $this->logger = $logger; - } - - /** - * - * - * @param EventManager $evm An EventManager instance - */ - public function register(EventManager $evm) - { - $evm->addEventListener(KernelEvents::onCoreSecurity, $this); - $this->evm = $evm; } /** - * {@inheritDoc} - */ - public function unregister(EventManager $evm) - { - } - - /** * Handles X509 authentication. * - * @param EventInterface $event An EventInterface instance + * @param GetResponseEventArgs $eventArgs A GetResponseEventArgs instance */ public function onCoreSecurity(GetResponseEventArgs $eventArgs) { @@ -81,11 +63,7 @@ abstract class AbstractPreAuthenticatedListener implements ListenerInterface list($user, $credentials) = $this->getPreAuthenticatedData($request); if (null !== $token = $this->securityContext->getToken()) { - if ($token->isImmutable()) { - return; - } - - if ($token instanceof PreAuthenticatedToken && $token->isAuthenticated() && (string) $token === $user) { + if ($token instanceof PreAuthenticatedToken && $token->isAuthenticated() && $token->getUsername() === $user) { return; } } diff --git a/Http/Firewall/AccessListener.php b/Http/Firewall/AccessListener.php index 7a0c926..acbb255 100644 --- a/Http/Firewall/AccessListener.php +++ b/Http/Firewall/AccessListener.php @@ -20,7 +20,6 @@ use Symfony\Component\HttpKernel\Event\GetResponseEventArgs; use Symfony\Component\HttpKernel\Events; use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException; use Symfony\Component\Security\Core\Exception\AccessDeniedException; -use Doctrine\Common\EventManager; /** * AccessListener enforces access control rules. @@ -29,11 +28,11 @@ use Doctrine\Common\EventManager; */ class AccessListener implements ListenerInterface { - protected $context; - protected $accessDecisionManager; - protected $map; - protected $authManager; - protected $logger; + private $context; + private $accessDecisionManager; + private $map; + private $authManager; + private $logger; public function __construct(SecurityContext $context, AccessDecisionManagerInterface $accessDecisionManager, AccessMap $map, AuthenticationManagerInterface $authManager, LoggerInterface $logger = null) { @@ -45,23 +44,6 @@ class AccessListener implements ListenerInterface } /** - * Registers a onCoreSecurity listener to enforce authorization rules. - * - * @param EventManager $evm An EventManager instance - */ - public function register(EventManager $evm) - { - $evm->addEventListener(Events::onCoreSecurity, $this); - } - - /** - * {@inheritDoc} - */ - public function unregister(EventManager $evm) - { - } - - /** * Handles access authorization. * * @param GetResponseEventArgs $eventArgs A GetResponseEventArgs instance diff --git a/Http/Firewall/AnonymousAuthenticationListener.php b/Http/Firewall/AnonymousAuthenticationListener.php index 9d23c58..bbdef5d 100644 --- a/Http/Firewall/AnonymousAuthenticationListener.php +++ b/Http/Firewall/AnonymousAuthenticationListener.php @@ -16,7 +16,6 @@ use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEventArgs; use Symfony\Component\HttpKernel\Events; use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; -use Doctrine\Common\EventManager; /** * AnonymousAuthenticationListener automatically addds a Token if none is @@ -26,9 +25,9 @@ use Doctrine\Common\EventManager; */ class AnonymousAuthenticationListener implements ListenerInterface { - protected $context; - protected $key; - protected $logger; + private $context; + private $key; + private $logger; public function __construct(SecurityContextInterface $context, $key, LoggerInterface $logger = null) { @@ -38,24 +37,6 @@ class AnonymousAuthenticationListener implements ListenerInterface } /** - * Registers a onCoreSecurity listener to load the SecurityContext from the - * session. - * - * @param EventManager $evm An EventManager instance - */ - public function register(EventManager $evm) - { - $evm->addEventListener(Events::onCoreSecurity, $this); - } - - /** - * {@inheritDoc} - */ - public function unregister(EventManager $evm) - { - } - - /** * Handles anonymous authentication. * * @param GetResponseEventArgs $eventArgs A GetResponseEventArgs instance diff --git a/Http/Firewall/BasicAuthenticationListener.php b/Http/Firewall/BasicAuthenticationListener.php index 7a4a17a..87d10b8 100644 --- a/Http/Firewall/BasicAuthenticationListener.php +++ b/Http/Firewall/BasicAuthenticationListener.php @@ -19,7 +19,6 @@ use Symfony\Component\HttpKernel\Event\GetResponseEventArgs; use Symfony\Component\HttpKernel\Events; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Exception\AuthenticationException; -use Doctrine\Common\EventManager; /** * BasicAuthenticationListener implements Basic HTTP authentication. @@ -28,12 +27,12 @@ use Doctrine\Common\EventManager; */ class BasicAuthenticationListener implements ListenerInterface { - protected $securityContext; - protected $authenticationManager; - protected $providerKey; - protected $authenticationEntryPoint; - protected $logger; - protected $ignoreFailure; + private $securityContext; + private $authenticationManager; + private $providerKey; + private $authenticationEntryPoint; + private $logger; + private $ignoreFailure; public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, AuthenticationEntryPointInterface $authenticationEntryPoint, LoggerInterface $logger = null) { @@ -50,23 +49,6 @@ class BasicAuthenticationListener implements ListenerInterface } /** - * - * - * @param EventManager $evm An EventManager instance - */ - public function register(EventManager $evm) - { - $evm->addEventListener(Events::onCoreSecurity, $this); - } - - /** - * {@inheritDoc} - */ - public function unregister(EventManager $evm) - { - } - - /** * Handles basic authentication. * * @param GetResponseEventArgs $eventArgs A GetResponseEventArgs instance @@ -80,11 +62,7 @@ class BasicAuthenticationListener implements ListenerInterface } if (null !== $token = $this->securityContext->getToken()) { - if ($token->isImmutable()) { - return; - } - - if ($token instanceof UsernamePasswordToken && $token->isAuthenticated() && (string) $token === $username) { + if ($token instanceof UsernamePasswordToken && $token->isAuthenticated() && $token->getUsername() === $username) { return; } } diff --git a/Http/Firewall/ChannelListener.php b/Http/Firewall/ChannelListener.php index b9416dd..e2b3423 100644 --- a/Http/Firewall/ChannelListener.php +++ b/Http/Firewall/ChannelListener.php @@ -16,7 +16,6 @@ use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEventArgs; use Symfony\Component\HttpKernel\Events; -use Doctrine\Common\EventManager; /** * ChannelListener switches the HTTP protocol based on the access control @@ -26,9 +25,9 @@ use Doctrine\Common\EventManager; */ class ChannelListener implements ListenerInterface { - protected $map; - protected $authenticationEntryPoint; - protected $logger; + private $map; + private $authenticationEntryPoint; + private $logger; public function __construct(AccessMap $map, AuthenticationEntryPointInterface $authenticationEntryPoint, LoggerInterface $logger = null) { @@ -38,23 +37,6 @@ class ChannelListener implements ListenerInterface } /** - * - * - * @param EventManager $evm An EventManager instance - */ - public function register(EventManager $evm) - { - $evm->addEventListener(Events::onCoreSecurity, $this); - } - - /** - * {@inheritDoc} - */ - public function unregister(EventManager $evm) - { - } - - /** * Handles channel management. * * @param GetResponseEventArgs $eventArgs A GetResponseEventArgs instance diff --git a/Http/Firewall/ContextListener.php b/Http/Firewall/ContextListener.php index f19d2bc..72dab1e 100644 --- a/Http/Firewall/ContextListener.php +++ b/Http/Firewall/ContextListener.php @@ -16,12 +16,13 @@ use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEventArgs; use Symfony\Component\HttpKernel\Event\FilterResponseEventArgs; +use Symfony\Component\HttpKernel\Events; use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; -use Symfony\Component\Security\Core\Exception\UnsupportedAccountException; +use Symfony\Component\Security\Core\Exception\UnsupportedUserException; use Symfony\Component\Security\Core\SecurityContext; -use Symfony\Component\Security\Core\User\AccountInterface; +use Symfony\Component\Security\Core\User\UserInterface; use Doctrine\Common\EventManager; /** @@ -32,12 +33,12 @@ use Doctrine\Common\EventManager; */ class ContextListener implements ListenerInterface { - protected $context; - protected $contextKey; - protected $logger; - protected $userProviders; + private $context; + private $contextKey; + private $logger; + private $userProviders; - public function __construct(SecurityContext $context, array $userProviders, $contextKey, LoggerInterface $logger = null) + public function __construct(SecurityContext $context, array $userProviders, $contextKey, LoggerInterface $logger = null, EventManager $evm = null) { if (empty($contextKey)) { throw new \InvalidArgumentException('$contextKey must not be empty.'); @@ -46,29 +47,10 @@ class ContextListener implements ListenerInterface $this->context = $context; $this->userProviders = $userProviders; $this->contextKey = $contextKey; - $this->logger = $logger; - } - - /** - * Registers a onCoreSecurity listener to load the SecurityContext from the - * session. - * - * @param EventManager $evm An EventManager instance - */ - public function register(EventManager $evm) - { - $evm->addEventListener( - array(Events::onCoreSecurity, Events::filterCoreResponse), - $this - ); - } - /** - * {@inheritDoc} - */ - public function unregister(EventManager $evm) - { - $evm->removeEventListener(Events::filterCoreResponse, $this); + if (null !== $evm) { + $evm->connect(Events::onCoreResponse, $this); + } } /** @@ -91,7 +73,7 @@ class ContextListener implements ListenerInterface $token = unserialize($token); - if (null !== $token && false === $token->isImmutable()) { + if (null !== $token) { $token = $this->refreshUser($token); } @@ -102,7 +84,7 @@ class ContextListener implements ListenerInterface /** * Writes the SecurityContext to the session. * - * @param EventInterface $event An EventInterface instance + * @param FilterResponseEventArgs $eventArgs A FilterResponseEventArgs instance */ public function filterCoreResponse(FilterResponseEventArgs $eventArgs) { @@ -132,10 +114,10 @@ class ContextListener implements ListenerInterface * * @return TokenInterface|null */ - protected function refreshUser(TokenInterface $token) + private function refreshUser(TokenInterface $token) { $user = $token->getUser(); - if (!$user instanceof AccountInterface) { + if (!$user instanceof UserInterface) { return $token; } @@ -145,25 +127,18 @@ class ContextListener implements ListenerInterface foreach ($this->userProviders as $provider) { try { - $cUser = $provider->loadUserByAccount($user); - - $token->setRoles($cUser->getRoles()); - $token->setUser($cUser); - - if (false === $cUser->equals($user)) { - $token->setAuthenticated(false); - } + $token->setUser($provider->loadUser($user)); if (null !== $this->logger) { - $this->logger->debug(sprintf('Username "%s" was reloaded from user provider.', $user)); + $this->logger->debug(sprintf('Username "%s" was reloaded from user provider.', $user->getUsername())); } return $token; - } catch (UnsupportedAccountException $unsupported) { + } catch (UnsupportedUserException $unsupported) { // let's try the next user provider } catch (UsernameNotFoundException $notFound) { if (null !== $this->logger) { - $this->logger->debug(sprintf('Username "%s" could not be found.', $user)); + $this->logger->debug(sprintf('Username "%s" could not be found.', $user->getUsername())); } return null; diff --git a/Http/Firewall/DigestAuthenticationListener.php b/Http/Firewall/DigestAuthenticationListener.php index 6426fa1..70b32be 100644 --- a/Http/Firewall/DigestAuthenticationListener.php +++ b/Http/Firewall/DigestAuthenticationListener.php @@ -24,7 +24,6 @@ use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; use Symfony\Component\Security\Core\Exception\NonceExpiredException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\Exception\AuthenticationException; -use Doctrine\Common\EventManager; /** * DigestAuthenticationListener implements Digest HTTP authentication. @@ -33,11 +32,11 @@ use Doctrine\Common\EventManager; */ class DigestAuthenticationListener implements ListenerInterface { - protected $securityContext; - protected $provider; - protected $providerKey; - protected $authenticationEntryPoint; - protected $logger; + private $securityContext; + private $provider; + private $providerKey; + private $authenticationEntryPoint; + private $logger; public function __construct(SecurityContextInterface $securityContext, UserProviderInterface $provider, $providerKey, DigestAuthenticationEntryPoint $authenticationEntryPoint, LoggerInterface $logger = null) { @@ -53,23 +52,6 @@ class DigestAuthenticationListener implements ListenerInterface } /** - * - * - * @param EventManager $evm An EventManager instance - */ - public function register(EventManager $evm) - { - $evm->addEventListener(Events::onCoreSecurity, $this); - } - - /** - * {@inheritDoc} - */ - public function unregister(EventManager $evm) - { - } - - /** * Handles digest authentication. * * @param GetResponseEventArgs $eventArgs A GetResponseEventArgs instance @@ -85,11 +67,7 @@ class DigestAuthenticationListener implements ListenerInterface $digestAuth = new DigestData($header); if (null !== $token = $this->securityContext->getToken()) { - if ($token->isImmutable()) { - return; - } - - if ($token instanceof UsernamePasswordToken && $token->isAuthenticated() && (string) $token === $digestAuth->getUsername()) { + if ($token instanceof UsernamePasswordToken && $token->isAuthenticated() && $token->getUsername() === $digestAuth->getUsername()) { return; } } @@ -101,7 +79,7 @@ class DigestAuthenticationListener implements ListenerInterface try { $digestAuth->validateAndDecode($this->authenticationEntryPoint->getKey(), $this->authenticationEntryPoint->getRealmName()); } catch (BadCredentialsException $e) { - $this->fail($event, $request, $e); + $this->fail($eventArgs, $request, $e); return; } @@ -115,7 +93,7 @@ class DigestAuthenticationListener implements ListenerInterface $serverDigestMd5 = $digestAuth->calculateServerDigest($user->getPassword(), $request->getMethod()); } catch (UsernameNotFoundException $notFound) { - $this->fail($event, $request, new BadCredentialsException(sprintf('Username %s not found.', $digestAuth->getUsername()))); + $this->fail($eventArgs, $request, new BadCredentialsException(sprintf('Username %s not found.', $digestAuth->getUsername()))); return; } @@ -125,13 +103,13 @@ class DigestAuthenticationListener implements ListenerInterface $this->logger->debug(sprintf("Expected response: '%s' but received: '%s'; is AuthenticationDao returning clear text passwords?", $serverDigestMd5, $digestAuth->getResponse())); } - $this->fail($event, $request, new BadCredentialsException('Incorrect response')); + $this->fail($eventArgs, $request, new BadCredentialsException('Incorrect response')); return; } if ($digestAuth->isNonceExpired()) { - $this->fail($event, $request, new NonceExpiredException('Nonce has expired/timed out.')); + $this->fail($eventArgs, $request, new NonceExpiredException('Nonce has expired/timed out.')); return; } @@ -143,7 +121,7 @@ class DigestAuthenticationListener implements ListenerInterface $this->securityContext->setToken(new UsernamePasswordToken($user, $user->getPassword(), $this->providerKey)); } - protected function fail(EventInterface $event, Request $request, AuthenticationException $authException) + private function fail(GetResponseEventArgs $eventArgs, Request $request, AuthenticationException $authException) { $this->securityContext->setToken(null); @@ -151,15 +129,15 @@ class DigestAuthenticationListener implements ListenerInterface $this->logger->debug($authException); } - $this->authenticationEntryPoint->start($event, $request, $authException); + $this->authenticationEntryPoint->start($eventArgs, $request, $authException); } } class DigestData { - protected $elements; - protected $header; - protected $nonceExpiryTime; + private $elements; + private $header; + private $nonceExpiryTime; public function __construct($header) { diff --git a/Http/Firewall/ExceptionListener.php b/Http/Firewall/ExceptionListener.php index 8885ea7..e88b84f 100644 --- a/Http/Firewall/ExceptionListener.php +++ b/Http/Firewall/ExceptionListener.php @@ -32,14 +32,14 @@ use Doctrine\Common\EventManager; * * @author Fabien Potencier <fabien@symfony.com> */ -class ExceptionListener implements ListenerInterface +class ExceptionListener { - protected $context; - protected $accessDeniedHandler; - protected $authenticationEntryPoint; - protected $authenticationTrustResolver; - protected $errorPage; - protected $logger; + private $context; + private $accessDeniedHandler; + private $authenticationEntryPoint; + private $authenticationTrustResolver; + private $errorPage; + private $logger; public function __construct(SecurityContextInterface $context, AuthenticationTrustResolverInterface $trustResolver, AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, AccessDeniedHandlerInterface $accessDeniedHandler = null, LoggerInterface $logger = null) { @@ -62,14 +62,6 @@ class ExceptionListener implements ListenerInterface } /** - * {@inheritDoc} - */ - public function unregister(EventManager $evm) - { - $evm->disconnect(Events::onCoreException, $this); - } - - /** * Handles security related exceptions. * * @param ExceptionEventArgs $event An ExceptionEventArgs instance @@ -145,7 +137,7 @@ class ExceptionListener implements ListenerInterface $eventArgs->setResponse($response); } - protected function startAuthentication(ExceptionEventArgs $eventArgs, Request $request, AuthenticationException $authException) + private function startAuthentication(ExceptionEventArgs $eventArgs, Request $request, AuthenticationException $authException) { $this->context->setToken(null); @@ -157,7 +149,7 @@ class ExceptionListener implements ListenerInterface $this->logger->debug('Calling Authentication entry point'); } - // session isn't required when using http basic authentification mecanism for example + // session isn't required when using http basic authentification mechanism for example if ($request->hasSession()) { $request->getSession()->set('_security.target_path', $request->getUri()); } diff --git a/Http/Firewall/ListenerInterface.php b/Http/Firewall/ListenerInterface.php index 5d7afbd..bfc7478 100644 --- a/Http/Firewall/ListenerInterface.php +++ b/Http/Firewall/ListenerInterface.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Security\Http\Firewall; +use Symfony\Component\HttpKernel\Event\GetResponseEventArgs; use Doctrine\Common\EventManager; /** @@ -21,22 +22,9 @@ use Doctrine\Common\EventManager; interface ListenerInterface { /** - * The implementation must connect this listener to all necessary events. + * This interface must be implemented by firewall listeners. * - * Typical events are: "onCoreSecurity", and "filterCoreResponse" - * - * @param EventManager $evm - */ - function register(EventManager $evm); - - /** - * The implementation must remove this listener from any events that it had - * connected to in register(). - * - * It may remove this listener from "onCoreSecurity", but this is ensured by - * the firewall anyway. - * - * @param EventManager $evm + * @param GetResponseEventArgs $eventArgs */ - function unregister(EventManager $evm); + function onCoreSecurity(GetResponseEventArgs $eventArgs); }
\ No newline at end of file diff --git a/Http/Firewall/LogoutListener.php b/Http/Firewall/LogoutListener.php index a4b6991..d2b18cf 100644 --- a/Http/Firewall/LogoutListener.php +++ b/Http/Firewall/LogoutListener.php @@ -19,7 +19,6 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\Kernel\Event\GetResponseEventArgs; use Symfony\Component\Kernel\Events; -use Doctrine\Common\EventManager; /** * LogoutListener logout users. @@ -28,11 +27,11 @@ use Doctrine\Common\EventManager; */ class LogoutListener implements ListenerInterface { - protected $securityContext; - protected $logoutPath; - protected $targetUrl; - protected $handlers; - protected $successHandler; + private $securityContext; + private $logoutPath; + private $targetUrl; + private $handlers; + private $successHandler; /** * Constructor @@ -62,23 +61,6 @@ class LogoutListener implements ListenerInterface } /** - * Registers a onCoreSecurity listener. - * - * @param EventManager $evm An EventManager instance - */ - public function register(EventManager $evm) - { - $evm->addEventListener(Events::onCoreSecurity, $this); - } - - /** - * {@inheritDoc} - */ - public function unregister(EventManager $evm) - { - } - - /** * Performs the logout if requested * * @param GetResponseEventArgs $eventArgs A GetResponseEventArgs instance diff --git a/Http/Firewall/RememberMeListener.php b/Http/Firewall/RememberMeListener.php index 73514bc..af5fc83 100644 --- a/Http/Firewall/RememberMeListener.php +++ b/Http/Firewall/RememberMeListener.php @@ -34,12 +34,11 @@ use Doctrine\Common\EventManager; */ class RememberMeListener implements ListenerInterface { - protected $securityContext; - protected $rememberMeServices; - protected $authenticationManager; - protected $logger; - protected $lastState; - protected $evm; + private $securityContext; + private $rememberMeServices; + private $authenticationManager; + private $logger; + private $evm; /** * Constructor @@ -49,111 +48,53 @@ class RememberMeListener implements ListenerInterface * @param AuthenticationManagerInterface $authenticationManager * @param LoggerInterface $logger */ - public function __construct(SecurityContext $securityContext, RememberMeServicesInterface $rememberMeServices, AuthenticationManagerInterface $authenticationManager, LoggerInterface $logger = null) + public function __construct(SecurityContext $securityContext, RememberMeServicesInterface $rememberMeServices, AuthenticationManagerInterface $authenticationManager, LoggerInterface $logger = null, EventManager $evm = null) { $this->securityContext = $securityContext; $this->rememberMeServices = $rememberMeServices; $this->authenticationManager = $authenticationManager; $this->logger = $logger; - } - - /** - * Listen to onCoreSecurity and filterCoreResponse event - * - * @param EventManager $evm An EventManager instance - */ - public function register(EventManager $evm) - { - $evm->addEventListener( - array(KernelEvents::onCoreSecurity, KernelEvents::filterCoreResponse), - $this - ); - $this->evm = $evm; } /** - * {@inheritDoc} - */ - public function unregister(EventManager $evm) - { - $evm->removeEventListener(KernelEvents::onCoreSecurity, $this); - } - - /** * Handles remember-me cookie based authentication. * * @param GetResponseEventArgs $eventArgs A GetResponseEventArgs instance */ public function onCoreSecurity(GetResponseEventArgs $eventArgs) { - $this->lastState = null; - if (null !== $this->securityContext->getToken()) { return; } - try { - if (null === $token = $this->rememberMeServices->autoLogin($eventArgs->getRequest())) { - return; - } - - try { - if (null === $token = $this->authenticationManager->authenticate($token)) { - return; - } - - $this->securityContext->setToken($token); - - if (null !== $this->evm) { - $loginEventArgs = new InteractiveLoginEventArgs($eventArgs->getRequest(), $token); - $this->evm->dispatchEvent(Events::onSecurityInteractiveLogin, $loginEventArgs); - } - - if (null !== $this->logger) { - $this->logger->debug('SecurityContext populated with remember-me token.'); - } + $request = $eventArgs->getRequest(); + if (null === $token = $this->rememberMeServices->autoLogin($request)) { + return; + } - $this->lastState = $token; - } catch (AuthenticationException $failed) { - if (null !== $this->logger) { - $this->logger->debug( - 'SecurityContext not populated with remember-me token as the' - .' AuthenticationManager rejected the AuthenticationToken returned' - .' by the RememberMeServices: '.$failed->getMessage() - ); - } + try { + $token = $this->authenticationManager->authenticate($token); + $this->securityContext->setToken($token); - $this->lastState = $failed; + if (null !== $this->evm) { + $loginEventArgs = new InteractiveLoginEventArgs($request, $token); + $this->evm->dispatchEvent(Events::onSecurityInteractiveLogin, $loginEventArgs); } - } catch (AuthenticationException $cookieInvalid) { - $this->lastState = $cookieInvalid; if (null !== $this->logger) { - $this->logger->debug('The presented cookie was invalid: '.$cookieInvalid->getMessage()); + $this->logger->debug('SecurityContext populated with remember-me token.'); } - - // silently ignore everything except a cookie theft exception - if ($cookieInvalid instanceof CookieTheftException) { - throw $cookieInvalid; + } catch (AuthenticationException $failed) { + if (null !== $this->logger) { + $this->logger->debug( + 'SecurityContext not populated with remember-me token as the' + .' AuthenticationManager rejected the AuthenticationToken returned' + .' by the RememberMeServices: '.$failed->getMessage() + ); } - } - } - - /** - * Update cookies - * @param Event $event - */ - public function filterCoreResponse(FilterResponseEventArgs $eventArgs) - { - if (HttpKernelInterface::MASTER_REQUEST !== $eventArgs->getRequestType()) { - return; - } - if ($this->lastState instanceof TokenInterface) { - $this->rememberMeServices->loginSuccess($eventArgs->getRequest(), $eventArgs->getResponse(), $this->lastState); - } else if ($this->lastState instanceof AuthenticationException) { - $this->rememberMeServices->loginFail($eventArgs->getRequest(), $eventArgs->getResponse()); + $this->rememberMeServices->loginFail($request); } } }
\ No newline at end of file diff --git a/Http/Firewall/SwitchUserListener.php b/Http/Firewall/SwitchUserListener.php index 5e352b9..11671ef 100644 --- a/Http/Firewall/SwitchUserListener.php +++ b/Http/Firewall/SwitchUserListener.php @@ -13,7 +13,7 @@ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; -use Symfony\Component\Security\Core\User\AccountCheckerInterface; +use Symfony\Component\Security\Core\User\UserCheckerInterface; use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEventArgs; @@ -38,20 +38,20 @@ use Doctrine\Common\EventManager; */ class SwitchUserListener implements ListenerInterface { - protected $securityContext; - protected $provider; - protected $accountChecker; - protected $providerKey; - protected $accessDecisionManager; - protected $usernameParameter; - protected $role; - protected $logger; - protected $evm; + private $securityContext; + private $provider; + private $userChecker; + private $providerKey; + private $accessDecisionManager; + private $usernameParameter; + private $role; + private $logger; + private $evm; /** * Constructor. */ - public function __construct(SecurityContextInterface $securityContext, UserProviderInterface $provider, AccountCheckerInterface $accountChecker, $providerKey, AccessDecisionManagerInterface $accessDecisionManager, LoggerInterface $logger = null, $usernameParameter = '_switch_user', $role = 'ROLE_ALLOWED_TO_SWITCH') + public function __construct(SecurityContextInterface $securityContext, UserProviderInterface $provider, UserCheckerInterface $userChecker, $providerKey, AccessDecisionManagerInterface $accessDecisionManager, LoggerInterface $logger = null, $usernameParameter = '_switch_user', $role = 'ROLE_ALLOWED_TO_SWITCH', EventManager $evm = null) { if (empty($providerKey)) { throw new \InvalidArgumentException('$providerKey must not be empty.'); @@ -59,34 +59,16 @@ class SwitchUserListener implements ListenerInterface $this->securityContext = $securityContext; $this->provider = $provider; - $this->accountChecker = $accountChecker; + $this->userChecker = $userChecker; $this->providerKey = $providerKey; $this->accessDecisionManager = $accessDecisionManager; $this->usernameParameter = $usernameParameter; $this->role = $role; $this->logger = $logger; - } - - /** - * - * - * @param EventManager $evm An EventManager instance - */ - public function register(EventManager $evm) - { - $evm->addEventListener(Events::onCoreSecurity, $this); - $this->evm = $evm; } /** - * {@inheritDoc} - */ - public function unregister(EventManager $evm) - { - } - - /** * Handles digest authentication. * * @param GetResponseEventArgs $eventArgs A GetResponseEventArgs instance @@ -124,11 +106,11 @@ class SwitchUserListener implements ListenerInterface * * @return TokenInterface|null The new TokenInterface if successfully switched, null otherwise */ - protected function attemptSwitchUser(Request $request) + private function attemptSwitchUser(Request $request) { $token = $this->securityContext->getToken(); if (false !== $this->getOriginalToken($token)) { - throw new \LogicException(sprintf('You are already switched to "%s" user.', (string) $token)); + throw new \LogicException(sprintf('You are already switched to "%s" user.', $token->getUsername())); } $this->accessDecisionManager->decide($token, array($this->role)); @@ -140,13 +122,12 @@ class SwitchUserListener implements ListenerInterface } $user = $this->provider->loadUserByUsername($username); - $this->accountChecker->checkPostAuth($user); + $this->userChecker->checkPostAuth($user); $roles = $user->getRoles(); $roles[] = new SwitchUserRole('ROLE_PREVIOUS_ADMIN', $this->securityContext->getToken()); $token = new UsernamePasswordToken($user, $user->getPassword(), $this->providerKey, $roles); - $token->setImmutable(true); if (null !== $this->evm) { $switchEventArgs = new SwitchUserEventArgs($request, $token->getUser()); @@ -163,7 +144,7 @@ class SwitchUserListener implements ListenerInterface * * @return TokenInterface The original TokenInterface instance */ - protected function attemptExitUser(Request $request) + private function attemptExitUser(Request $request) { if (false === $original = $this->getOriginalToken($this->securityContext->getToken())) { throw new AuthenticationCredentialsNotFoundException(sprintf('Could not find original Token object.')); @@ -184,7 +165,7 @@ class SwitchUserListener implements ListenerInterface * * @return TokenInterface|false The original TokenInterface instance, false if the current TokenInterface is not switched */ - protected function getOriginalToken(TokenInterface $token) + private function getOriginalToken(TokenInterface $token) { foreach ($token->getRoles() as $role) { if ($role instanceof SwitchUserRole) { diff --git a/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php index 126ef41..7f60daa 100644 --- a/Http/Firewall/UsernamePasswordFormAuthenticationListener.php +++ b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php @@ -21,6 +21,7 @@ use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterfac use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException; use Symfony\Component\Security\Core\SecurityContextInterface; +use Doctrine\Common\EventManager; /** * UsernamePasswordFormAuthenticationListener is the default implementation of @@ -30,12 +31,12 @@ use Symfony\Component\Security\Core\SecurityContextInterface; */ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationListener { - protected $csrfProvider; + private $csrfProvider; /** * {@inheritdoc} */ - public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, $providerKey, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null, CsrfProviderInterface $csrfProvider = null) + public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, $providerKey, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null, EventManager $evm = null, CsrfProviderInterface $csrfProvider = null) { parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $providerKey, array_merge(array( 'username_parameter' => '_username', @@ -43,7 +44,7 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL 'csrf_parameter' => '_csrf_token', 'csrf_page_id' => 'form_login', 'post_only' => true, - ), $options), $successHandler, $failureHandler, $logger); + ), $options), $successHandler, $failureHandler, $logger, $evm); $this->csrfProvider = $csrfProvider; } @@ -76,5 +77,4 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL return $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey)); } -} - +}
\ No newline at end of file diff --git a/Http/Firewall/X509AuthenticationListener.php b/Http/Firewall/X509AuthenticationListener.php index 3505b99..509f541 100644 --- a/Http/Firewall/X509AuthenticationListener.php +++ b/Http/Firewall/X509AuthenticationListener.php @@ -16,6 +16,7 @@ use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterfac use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\Exception\BadCredentialsException; +use Doctrine\Common\EventManager; /** * X509 authentication listener. @@ -27,9 +28,9 @@ class X509AuthenticationListener extends AbstractPreAuthenticatedListener protected $userKey; protected $credentialKey; - public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, $userKey = 'SSL_CLIENT_S_DN_Email', $credentialKey = 'SSL_CLIENT_S_DN', LoggerInterface $logger = null) + public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, $userKey = 'SSL_CLIENT_S_DN_Email', $credentialKey = 'SSL_CLIENT_S_DN', LoggerInterface $logger = null, EventManager $evm = null) { - parent::__construct($securityContext, $authenticationManager, $providerKey, $logger); + parent::__construct($securityContext, $authenticationManager, $providerKey, $logger, $evm); $this->userKey = $userKey; $this->credentialKey = $credentialKey; diff --git a/Http/FirewallMap.php b/Http/FirewallMap.php index c7a57f2..d5fc331 100644 --- a/Http/FirewallMap.php +++ b/Http/FirewallMap.php @@ -23,7 +23,7 @@ use Symfony\Component\Security\Http\Firewall\ExceptionListener; */ class FirewallMap implements FirewallMapInterface { - protected $map = array(); + private $map = array(); public function add(RequestMatcherInterface $requestMatcher = null, array $listeners = array(), ExceptionListener $exceptionListener = null) { diff --git a/Http/Logout/CookieClearingLogoutHandler.php b/Http/Logout/CookieClearingLogoutHandler.php index 8ca284d..ebdcbed 100644 --- a/Http/Logout/CookieClearingLogoutHandler.php +++ b/Http/Logout/CookieClearingLogoutHandler.php @@ -22,7 +22,7 @@ use Symfony\Component\HttpFoundation\Request; */ class CookieClearingLogoutHandler implements LogoutHandlerInterface { - protected $cookies; + private $cookies; /** * Constructor diff --git a/Http/RememberMe/RememberMeServices.php b/Http/RememberMe/AbstractRememberMeServices.php index 4370d92..b090e24 100644 --- a/Http/RememberMe/RememberMeServices.php +++ b/Http/RememberMe/AbstractRememberMeServices.php @@ -2,14 +2,19 @@ namespace Symfony\Component\Security\Http\RememberMe; -use Symfony\Component\Security\Core\User\AccountInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken; use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Core\Exception\UnsupportedUserException; +use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; +use Symfony\Component\Security\Core\Exception\CookieTheftException; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpKernel\Log\LoggerInterface; /* @@ -26,15 +31,15 @@ use Symfony\Component\HttpKernel\Log\LoggerInterface; * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ -abstract class RememberMeServices implements RememberMeServicesInterface, LogoutHandlerInterface +abstract class AbstractRememberMeServices implements RememberMeServicesInterface, LogoutHandlerInterface { const COOKIE_DELIMITER = ':'; - protected $userProviders; - protected $options; protected $logger; - protected $key; - protected $providerKey; + protected $options; + private $providerKey; + private $key; + private $userProviders; /** * Constructor @@ -73,6 +78,11 @@ abstract class RememberMeServices implements RememberMeServicesInterface, Logout return $this->options['remember_me_parameter']; } + public function getKey() + { + return $this->key; + } + /** * Implementation of RememberMeServicesInterface. Detects whether a remember-me * cookie was set, decodes it, and hands it to subclasses for further processing. @@ -80,7 +90,7 @@ abstract class RememberMeServices implements RememberMeServicesInterface, Logout * @param Request $request * @return TokenInterface */ - public function autoLogin(Request $request) + public final function autoLogin(Request $request) { if (null === $cookie = $request->cookies->get($this->options['name'])) { return; @@ -91,17 +101,40 @@ abstract class RememberMeServices implements RememberMeServicesInterface, Logout } $cookieParts = $this->decodeCookie($cookie); - $token = $this->processAutoLoginCookie($cookieParts, $request); - if (!$token instanceof TokenInterface) { - throw new \RuntimeException('processAutoLoginCookie() must return a TokenInterface implementation.'); - } + try { + $user = $this->processAutoLoginCookie($cookieParts, $request); - if (null !== $this->logger) { - $this->logger->debug('Remember-me cookie accepted.'); + if (!$user instanceof UserInterface) { + throw new \RuntimeException('processAutoLoginCookie() must return a UserInterface implementation.'); + } + + if (null !== $this->logger) { + $this->logger->debug('Remember-me cookie accepted.'); + } + + return new RememberMeToken($user, $this->providerKey, $this->key); + } catch (CookieTheftException $theft) { + $this->cancelCookie($request); + + throw $theft; + } catch (UsernameNotFoundException $notFound) { + if (null !== $this->logger) { + $this->logger->debug('User for remember-me cookie not found.'); + } + } catch (UnsupportedUserException $unSupported) { + if (null !== $this->logger) { + $this->logger->debug('User class for remember-me cookie not supported.'); + } + } catch (AuthenticationException $invalid) { + if (null !== $this->logger) { + $this->logger->debug('Remember-Me authentication failed: '.$invalid->getMessage()); + } } - return $token; + $this->cancelCookie($request); + + return null; } /** @@ -114,7 +147,7 @@ abstract class RememberMeServices implements RememberMeServicesInterface, Logout */ public function logout(Request $request, Response $response, TokenInterface $token) { - $this->cancelCookie($response); + $this->cancelCookie($request); } /** @@ -122,12 +155,12 @@ abstract class RememberMeServices implements RememberMeServicesInterface, Logout * an attempted authentication fails. * * @param Request $request - * @param Response $response * @return void */ - public function loginFail(Request $request, Response $response) + public final function loginFail(Request $request) { - $this->cancelCookie($response); + $this->cancelCookie($request); + $this->onLoginFail($request); } /** @@ -139,30 +172,26 @@ abstract class RememberMeServices implements RememberMeServicesInterface, Logout * @param TokenInterface $token The token that resulted in a successful authentication * @return void */ - public function loginSuccess(Request $request, Response $response, TokenInterface $token) + public final function loginSuccess(Request $request, Response $response, TokenInterface $token) { - if (!$token instanceof RememberMeToken) { - if (!$token->getUser() instanceof AccountInterface) { - if (null !== $this->logger) { - $this->logger->debug('Remember-me ignores token since it does not contain an AccountInterface implementation.'); - } - - return; + if (!$token->getUser() instanceof UserInterface) { + if (null !== $this->logger) { + $this->logger->debug('Remember-me ignores token since it does not contain an UserInterface implementation.'); } - if (!$this->isRememberMeRequested($request)) { - if (null !== $this->logger) { - $this->logger->debug('Remember-me was not requested.'); - } - - return; - } + return; + } + if (!$this->isRememberMeRequested($request)) { if (null !== $this->logger) { - $this->logger->debug('Remember-me was requested; setting cookie.'); + $this->logger->debug('Remember-me was not requested.'); } - } else if (null !== $this->logger) { - $this->logger->debug('Re-newing remember-me token; setting cookie.'); + + return; + } + + if (null !== $this->logger) { + $this->logger->debug('Remember-me was requested; setting cookie.'); } $this->onLoginSuccess($request, $response, $token); @@ -178,6 +207,10 @@ abstract class RememberMeServices implements RememberMeServicesInterface, Logout */ abstract protected function processAutoLoginCookie(array $cookieParts, Request $request); + protected function onLoginFail(Request $request) + { + } + /** * This is called after a user has been logged in successfully, and has * requested remember-me capabilities. The implementation usually sets a @@ -190,7 +223,7 @@ abstract class RememberMeServices implements RememberMeServicesInterface, Logout */ abstract protected function onLoginSuccess(Request $request, Response $response, TokenInterface $token); - protected function getUserProvider($class) + protected final function getUserProvider($class) { foreach ($this->userProviders as $provider) { if ($provider->supportsClass($class)) { @@ -198,7 +231,7 @@ abstract class RememberMeServices implements RememberMeServicesInterface, Logout } } - throw new \RuntimeException(sprintf('There is no user provider that supports class "%s".', $class)); + throw new UnsupportedUserException(sprintf('There is no user provider that supports class "%s".', $class)); } /** @@ -226,16 +259,16 @@ abstract class RememberMeServices implements RememberMeServicesInterface, Logout /** * Deletes the remember-me cookie * - * @param Response $response + * @param Request $request * @return void */ - protected function cancelCookie(Response $response) + protected function cancelCookie(Request $request) { if (null !== $this->logger) { $this->logger->debug(sprintf('Clearing remember-me cookie "%s"', $this->options['name'])); } - $response->headers->clearCookie($this->options['name'], $this->options['path'], $this->options['domain']); + $request->attributes->set(self::COOKIE_ATTR_NAME, new Cookie($this->options['name'], null, 1, $this->options['path'], $this->options['domain'])); } /** diff --git a/Http/RememberMe/PersistentTokenBasedRememberMeServices.php b/Http/RememberMe/PersistentTokenBasedRememberMeServices.php index ff3306e..f2a0249 100644 --- a/Http/RememberMe/PersistentTokenBasedRememberMeServices.php +++ b/Http/RememberMe/PersistentTokenBasedRememberMeServices.php @@ -28,9 +28,9 @@ use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken; * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ -class PersistentTokenBasedRememberMeServices extends RememberMeServices +class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices { - protected $tokenProvider; + private $tokenProvider; /** * Sets the token provider @@ -46,6 +46,21 @@ class PersistentTokenBasedRememberMeServices extends RememberMeServices /** * {@inheritDoc} */ + public function logout(Request $request, Response $response, TokenInterface $token) + { + parent::logout($request, $response, $token); + + if (null !== ($cookie = $request->cookies->get($this->options['name'])) + && count($parts = $this->decodeCookie($cookie)) === 2 + ) { + list($series, $tokenValue) = $parts; + $this->tokenProvider->deleteTokenBySeries($series); + } + } + + /** + * {@inheritDoc} + */ protected function processAutoLoginCookie(array $cookieParts, Request $request) { if (count($cookieParts) !== 2) { @@ -65,11 +80,22 @@ class PersistentTokenBasedRememberMeServices extends RememberMeServices throw new AuthenticationException('The cookie has expired.'); } - $user = $this->getUserProvider($persistentToken->getClass())->loadUserByUsername($persistentToken->getUsername()); - $authenticationToken = new RememberMeToken($user, $this->providerKey, $this->key); - $authenticationToken->setPersistentToken($persistentToken); + $series = $persistentToken->getSeries(); + $tokenValue = $this->generateRandomValue(); + $this->tokenProvider->updateToken($series, $tokenValue, new \DateTime()); + $request->attributes->set(self::COOKIE_ATTR_NAME, + new Cookie( + $this->options['name'], + $this->encodeCookie(array($series, $tokenValue)), + time() + $this->options['lifetime'], + $this->options['path'], + $this->options['domain'], + $this->options['secure'], + $this->options['httponly'] + ) + ); - return $authenticationToken; + return $this->getUserProvider($persistentToken->getClass())->loadUserByUsername($persistentToken->getUsername()); } /** @@ -77,34 +103,23 @@ class PersistentTokenBasedRememberMeServices extends RememberMeServices */ protected function onLoginSuccess(Request $request, Response $response, TokenInterface $token) { - if ($token instanceof RememberMeToken) { - if (null === $persistentToken = $token->getPersistentToken()) { - throw new \RuntimeException('RememberMeToken must contain a PersistentTokenInterface implementation when used as login.'); - } - - $series = $persistentToken->getSeries(); - $tokenValue = $this->generateRandomValue(); - - $this->tokenProvider->updateToken($series, $tokenValue, new \DateTime()); - } else { - $series = $this->generateRandomValue(); - $tokenValue = $this->generateRandomValue(); - - $this->tokenProvider->createNewToken( - new PersistentToken( - get_class($user = $token->getUser()), - $user->getUsername(), - $series, - $tokenValue, - new \DateTime() - ) - ); - } + $series = $this->generateRandomValue(); + $tokenValue = $this->generateRandomValue(); + + $this->tokenProvider->createNewToken( + new PersistentToken( + get_class($user = $token->getUser()), + $user->getUsername(), + $series, + $tokenValue, + new \DateTime() + ) + ); $response->headers->setCookie( new Cookie( $this->options['name'], - $this->generateCookieValue($series, $tokenValue), + $this->encodeCookie(array($series, $tokenValue)), time() + $this->options['lifetime'], $this->options['path'], $this->options['domain'], @@ -115,33 +130,6 @@ class PersistentTokenBasedRememberMeServices extends RememberMeServices } /** - * {@inheritDoc} - */ - public function logout(Request $request, Response $response, TokenInterface $token) - { - parent::logout($request, $response, $token); - - if (null !== ($cookie = $request->cookies->get($this->options['name'])) - && count($parts = $this->decodeCookie($cookie)) === 2 - ) { - list($series, $tokenValue) = $parts; - $this->tokenProvider->deleteTokenBySeries($series); - } - } - - /** - * Generates the value for the cookie - * - * @param string $series - * @param string $tokenValue - * @return string - */ - protected function generateCookieValue($series, $tokenValue) - { - return $this->encodeCookie(array($series, $tokenValue)); - } - - /** * Generates a cryptographically strong random value * * @return string @@ -149,7 +137,7 @@ class PersistentTokenBasedRememberMeServices extends RememberMeServices protected function generateRandomValue() { if (function_exists('openssl_random_pseudo_bytes')) { - $bytes = openssl_random_pseudo_bytes(32, $strong); + $bytes = openssl_random_pseudo_bytes(64, $strong); if (true === $strong && false !== $bytes) { return base64_encode($bytes); @@ -160,6 +148,6 @@ class PersistentTokenBasedRememberMeServices extends RememberMeServices $this->logger->warn('Could not produce a cryptographically strong random value. Please install/update the OpenSSL extension.'); } - return base64_encode(hash('sha256', uniqid(mt_rand(), true), true)); + return base64_encode(hash('sha512', uniqid(mt_rand(), true), true)); } -} +}
\ No newline at end of file diff --git a/Http/RememberMe/RememberMeServicesInterface.php b/Http/RememberMe/RememberMeServicesInterface.php index b038a0d..c740d28 100644 --- a/Http/RememberMe/RememberMeServicesInterface.php +++ b/Http/RememberMe/RememberMeServicesInterface.php @@ -17,50 +17,67 @@ use Symfony\Component\HttpFoundation\Request; /** * Interface that needs to be implemented by classes which provide remember-me * capabilities. - * + * * We provide two implementations out-of-the-box: * - TokenBasedRememberMeServices (does not require a TokenProvider) * - PersistentTokenBasedRememberMeServices (requires a TokenProvider) - * + * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ interface RememberMeServicesInterface { /** - * This method will be called whenever the SecurityContext does not contain - * an TokenInterface object and the framework wishes to provide an implementation - * with an opportunity to authenticate the request using remember-me capabilities. - * + * This attribute name can be used by the implementation if it needs to set + * a cookie on the Request when there is no actual Response, yet. + * + * @var string + */ + const COOKIE_ATTR_NAME = '_security_remember_me_cookie'; + + /** + * This method will be called whenever the SecurityContext does not contain + * an TokenInterface object and the framework wishes to provide an implementation + * with an opportunity to authenticate the request using remember-me capabilities. + * * No attempt whatsoever is made to determine whether the browser has requested * remember-me services or presented a valid cookie. Any and all such determinations - * are left to the implementation of this method. - * + * are left to the implementation of this method. + * * If a browser has presented an unauthorised cookie for whatever reason, - * make sure to throw an AuthenticationException as this will consequentially + * make sure to throw an AuthenticationException as this will consequentially * result in a call to loginFail() and therefore an invalidation of the cookie. - * + * * @param Request $request * @return TokenInterface */ function autoLogin(Request $request); - + /** - * Called whenever an authentication attempt was made, but the credentials - * supplied by the user were missing or otherwise invalid. - * + * Called whenever an interactive authentication attempt was made, but the + * credentials supplied by the user were missing or otherwise invalid. + * * This method needs to take care of invalidating the cookie. + * + * @param Request $request + * @return void */ - function loginFail(Request $request, Response $response); + function loginFail(Request $request); /** - * Called whenever authentication attempt is successful (e.g. a form login). - * - * An implementation may always set a remember-me cookie in the Response, - * although this is not recommended. - * - * Instead, implementations should typically look for a request parameter + * Called whenever an interactive authentication attempt is successful + * (e.g. a form login). + * + * An implementation may always set a remember-me cookie in the Response, + * although this is not recommended. + * + * Instead, implementations should typically look for a request parameter * (such as a HTTP POST parameter) that indicates the browser has explicitly * requested for the authentication to be remembered. + * + * @param Request $request + * @param Response $response + * @param TokenInterface $token + * @return void */ function loginSuccess(Request $request, Response $response, TokenInterface $token); }
\ No newline at end of file diff --git a/Http/RememberMe/TokenBasedRememberMeServices.php b/Http/RememberMe/TokenBasedRememberMeServices.php index 40757f4..0fd5c41 100644 --- a/Http/RememberMe/TokenBasedRememberMeServices.php +++ b/Http/RememberMe/TokenBasedRememberMeServices.php @@ -8,7 +8,7 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken; use Symfony\Component\Security\Core\Exception\AuthenticationException; -use Symfony\Component\Security\Core\User\AccountInterface; +use Symfony\Component\Security\Core\User\UserInterface; /* * This file is part of the Symfony package. @@ -25,7 +25,7 @@ use Symfony\Component\Security\Core\User\AccountInterface; * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ -class TokenBasedRememberMeServices extends RememberMeServices +class TokenBasedRememberMeServices extends AbstractRememberMeServices { /** * {@inheritDoc} @@ -50,8 +50,8 @@ class TokenBasedRememberMeServices extends RememberMeServices throw $ex; } - if (!$user instanceof AccountInterface) { - throw new \RuntimeException(sprintf('The UserProviderInterface implementation must return an instance of AccountInterface, but returned "%s".', get_class($user))); + if (!$user instanceof UserInterface) { + throw new \RuntimeException(sprintf('The UserProviderInterface implementation must return an instance of UserInterface, but returned "%s".', get_class($user))); } if (true !== $this->compareHashes($hash, $this->generateCookieHash($class, $username, $expires, $user->getPassword()))) { @@ -62,7 +62,7 @@ class TokenBasedRememberMeServices extends RememberMeServices throw new AuthenticationException('The cookie has expired.'); } - return new RememberMeToken($user, $this->providerKey, $this->key); + return $user; } /** @@ -76,7 +76,7 @@ class TokenBasedRememberMeServices extends RememberMeServices * * @return Boolean true if the two hashes are the same, false otherwise */ - protected function compareHashes($hash1, $hash2) + private function compareHashes($hash1, $hash2) { if (strlen($hash1) !== $c = strlen($hash2)) { return false; @@ -95,10 +95,6 @@ class TokenBasedRememberMeServices extends RememberMeServices */ protected function onLoginSuccess(Request $request, Response $response, TokenInterface $token) { - if ($token instanceof RememberMeToken) { - return; - } - $user = $token->getUser(); $expires = time() + $this->options['lifetime']; $value = $this->generateCookieValue(get_class($user), $user->getUsername(), $expires, $user->getPassword()); @@ -150,6 +146,6 @@ class TokenBasedRememberMeServices extends RememberMeServices */ protected function generateCookieHash($class, $username, $expires, $password) { - return hash('sha256', $class.$username.$expires.$password.$this->key); + return hash('sha256', $class.$username.$expires.$password.$this->getKey()); } } diff --git a/Http/Session/SessionAuthenticationStrategy.php b/Http/Session/SessionAuthenticationStrategy.php index 1d25bd9..dea34be 100644 --- a/Http/Session/SessionAuthenticationStrategy.php +++ b/Http/Session/SessionAuthenticationStrategy.php @@ -21,7 +21,7 @@ class SessionAuthenticationStrategy implements SessionAuthenticationStrategyInte const MIGRATE = 'migrate'; const INVALIDATE = 'invalidate'; - protected $strategy; + private $strategy; public function __construct($strategy) { |