[Security] many improvements, and fixes

This commit is contained in:
Johannes Schmitt 2011-01-25 20:28:26 +01:00 committed by Fabien Potencier
parent fb889a2eee
commit 57ae50e894
77 changed files with 3776 additions and 266 deletions

View File

@ -65,6 +65,14 @@ class EntityUserProvider implements UserProviderInterface
throw new UnsupportedAccountException(sprintf('Instances of "%s" are not supported.', get_class($account)));
}
return $this->loadUserByUsername((string) $account);
return $this->loadUserByUsername($account->getUsername());
}
/**
* {@inheritDoc}
*/
public function supportsClass($class)
{
return $class === $this->class;
}
}

View File

@ -72,8 +72,6 @@ EOT
}
}
$paths = array_filter($paths, 'is_dir');
$loader = new \Doctrine\Common\DataFixtures\Loader();
foreach ($paths as $path) {
$loader->loadFromDirectory($path);

View File

@ -65,6 +65,14 @@ class DocumentUserProvider implements UserProviderInterface
throw new UnsupportedAccountException(sprintf('Instances of "%s" are not supported.', get_class($account)));
}
return $this->loadUserByUsername((string) $account);
return $this->loadUserByUsername($account->getUsername());
}
/**
* {@inheritDoc}
*/
public function supportsClass($class)
{
return $class === $this->class;
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
class AddAuthenticationProvidersPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('security.authentication.manager')) {
return;
}
$providers = array();
foreach ($container->findTaggedServiceIds('security.authentication_provider') as $id => $attributes) {
$providers[] = new Reference($id);
}
$container
->getDefinition('security.authentication.manager')
->setArguments(array($providers))
;
}
}

View File

@ -26,17 +26,28 @@ class FormLoginFactory implements SecurityFactoryInterface
$provider = 'security.authentication.provider.dao.'.$id;
$container
->register($provider, '%security.authentication.provider.dao.class%')
->setArguments(array(new Reference($userProvider), new Reference('security.account_checker'), new Reference('security.encoder_factory')))
->setArguments(array(new Reference($userProvider), new Reference('security.account_checker'), $id, new Reference('security.encoder_factory')))
->setPublic(false)
->addTag('security.authentication_provider')
;
// listener
$listenerId = 'security.authentication.listener.form.'.$id;
$listener = $container->setDefinition($listenerId, clone $container->getDefinition('security.authentication.listener.form'));
$arguments = $listener->getArguments();
$arguments[1] = new Reference($provider);
$listener->setArguments($arguments);
$listener->setArgument(3, $id);
// add remember-me tag
$rememberMe = true;
if (isset($config['remember-me']) && false === $config['remember-me']) {
$rememberMe = false;
} else if (isset($config['remember_me']) && false === $config['remember_me']) {
$rememberMe = false;
}
if ($rememberMe) {
$listener->addTag('security.remember_me_aware', array('id' => $id, 'provider' => $userProvider));
}
// generate options
$options = array(
'check_path' => '/login_check',
'login_path' => '/login',
@ -53,11 +64,29 @@ class FormLoginFactory implements SecurityFactoryInterface
$options[$key] = $config[$key];
}
}
$container->setParameter('security.authentication.form.options', $options);
$container->setParameter('security.authentication.form.login_path', $options['login_path']);
$container->setParameter('security.authentication.form.use_forward', $options['use_forward']);
$listener->setArgument(4, $options);
return array($provider, $listenerId, 'security.authentication.form_entry_point');
// success handler
if (isset($config['success_handler'])) {
$config['success-handler'] = $config['success_handler'];
}
if (isset($config['success-handler'])) {
$listener->setArgument(5, new Reference($config['success-handler']));
}
// failure handler
if (isset($config['failure_handler'])) {
$config['failure-handler'] = $config['failure_handler'];
}
if (isset($config['failure-handler'])) {
$listener->setArgument(6, new Reference($config['failure-handler']));
}
// form entry point
$entryPoint = $container->setDefinition($entryPointId = 'security.authentication.form_entry_point.'.$id, clone $container->getDefinition('security.authentication.form_entry_point'));
$entryPoint->setArguments(array($options['login_path'], $options['use_forward']));
return array($provider, $listenerId, $entryPointId);
}
public function getPosition()

View File

@ -26,16 +26,15 @@ class HttpBasicFactory implements SecurityFactoryInterface
$provider = 'security.authentication.provider.dao.'.$id;
$container
->register($provider, '%security.authentication.provider.dao.class%')
->setArguments(array(new Reference($userProvider), new Reference('security.account_checker'), new Reference('security.encoder_factory')))
->setArguments(array(new Reference($userProvider), new Reference('security.account_checker'), $id, new Reference('security.encoder_factory')))
->setPublic(false)
->addTag('security.authentication_provider')
;
// listener
$listenerId = 'security.authentication.listener.basic.'.$id;
$listener = $container->setDefinition($listenerId, clone $container->getDefinition('security.authentication.listener.basic'));
$arguments = $listener->getArguments();
$arguments[1] = new Reference($provider);
$listener->setArguments($arguments);
$listener->setArgument(2, $id);
if (isset($config['path'])) {
$container->setParameter('security.authentication.form.path', $config['path']);

View File

@ -26,16 +26,15 @@ class HttpDigestFactory implements SecurityFactoryInterface
$provider = 'security.authentication.provider.dao.'.$id;
$container
->register($provider, '%security.authentication.provider.dao.class%')
->setArguments(array(new Reference($userProvider), new Reference('security.account_checker'), new Reference('security.encoder_factory')))
->setArguments(array(new Reference($userProvider), new Reference('security.account_checker'), $id, new Reference('security.encoder_factory')))
->setPublic(false)
->addTag('security.authentication_provider')
;
// listener
$listenerId = 'security.authentication.listener.digest.'.$id;
$listener = $container->setDefinition($listenerId, clone $container->getDefinition('security.authentication.listener.digest'));
$arguments = $listener->getArguments();
$arguments[1] = new Reference($userProvider);
$listener->setArguments($arguments);
$listener->setArgument(2, $id);
if (null === $defaultEntryPoint) {
$defaultEntryPoint = 'security.authentication.digest_entry_point';

View File

@ -0,0 +1,110 @@
<?php
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Security\Factory;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class RememberMeFactory implements SecurityFactoryInterface
{
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
{
if (!isset($config['key']) || empty($config['key'])) {
throw new \RuntimeException('A "key" must be defined for each remember-me section.');
}
if (isset($config['provider'])) {
throw new \RuntimeException('You must not set a user provider for remember-me.');
}
// authentication provider
$authenticationProviderId = 'security.authentication.provider.rememberme.'.$id;
$container
->register($authenticationProviderId, '%security.authentication.provider.rememberme.class%')
->setArguments(array(new Reference('security.account_checker'), $config['key'], $id))
->setPublic(false)
->addTag('security.authentication_provider')
;
// remember me services
if (isset($config['token_provider'])) {
$config['token-provider'] = $config['token_provider'];
}
if (isset($config['token-provider'])) {
$templateId = 'security.authentication.rememberme.services.persistent';
$rememberMeServicesId = $templateId.'.'.$id;
} else {
$templateId = 'security.authentication.rememberme.services.simplehash';
$rememberMeServicesId = $templateId.'.'.$id;
}
if ($container->hasDefinition('security.logout_listener.'.$id)) {
$container
->getDefinition('security.logout_listener.'.$id)
->addMethodCall('addHandler', array(new Reference($rememberMeServicesId)))
;
}
$rememberMeServices = $container->setDefinition($rememberMeServicesId, clone $container->getDefinition($templateId));
$arguments = $rememberMeServices->getArguments();
$arguments[1] = $config['key'];
$arguments[2] = $id;
if (isset($config['token-provider'])) {
// FIXME: make the naming assumption more flexible
$rememberMeServices->addMethodCall('setTokenProvider', array(
new Reference('security.rememberme.token.provider.'.$config['token-provider'])
));
}
// remember-me options
foreach ($arguments[3] as $name => $option) {
if (array_key_exists($name, $config)) {
$arguments[3][$name] = $config[$name];
}
}
$rememberMeServices->setArguments($arguments);
// attach to remember-me aware listeners
$userProviders = array();
foreach ($container->findTaggedServiceIds('security.remember_me_aware') as $serviceId => $attributes) {
foreach ($attributes as $attribute) {
if (!isset($attribute['id']) || $attribute['id'] !== $id) {
continue;
}
if (!isset($attribute['provider'])) {
throw new \RuntimeException('Each "security.remember_me_aware" tag must have a provider attribute.');
}
$userProviders[] = new Reference($attribute['provider']);
$container
->getDefinition($serviceId)
->addMethodCall('setRememberMeServices', array(new Reference($rememberMeServicesId)))
;
}
}
if (count($userProviders) === 0) {
throw new \RuntimeException('You must configure at least one remember-me aware listener (such as form-login) for each firewall that has remember-me enabled.');
}
$rememberMeServices->setArgument(0, $userProviders);
// remember-me listener
$listenerId = 'security.authentication.listener.rememberme.'.$id;
$listener = $container->setDefinition($listenerId, clone $container->getDefinition('security.authentication.listener.rememberme'));
$listener->setArgument(1, new Reference($rememberMeServicesId));
return array($authenticationProviderId, $listenerId, $defaultEntryPoint);
}
public function getPosition()
{
return 'remember_me';
}
public function getKey()
{
return 'remember-me';
}
}

View File

@ -26,15 +26,16 @@ class X509Factory implements SecurityFactoryInterface
$provider = 'security.authentication.provider.pre_authenticated.'.$id;
$container
->register($provider, '%security.authentication.provider.pre_authenticated.class%')
->setArguments(array(new Reference($userProvider), new Reference('security.account_checker')))
->setArguments(array(new Reference($userProvider), new Reference('security.account_checker'), $id))
->setPublic(false)
->addTag('security.authentication_provider')
;
// listener
$listenerId = 'security.authentication.listener.x509.'.$id;
$listener = $container->setDefinition($listenerId, clone $container->getDefinition('security.authentication.listener.x509'));
$arguments = $listener->getArguments();
$arguments[1] = new Reference($provider);
$arguments[2] = $id;
$listener->setArguments($arguments);
return array($provider, $listenerId, $defaultEntryPoint);

View File

@ -12,12 +12,12 @@
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Resource\FileResource;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\HttpFoundation\RequestMatcher;
@ -26,10 +26,12 @@ use Symfony\Component\HttpFoundation\RequestMatcher;
* SecurityExtension.
*
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class SecurityExtension extends Extension
{
protected $requestMatchers = array();
protected $contextListeners = array();
public function configLoad(array $configs, ContainerBuilder $container)
{
@ -59,7 +61,15 @@ class SecurityExtension extends Extension
}
if (isset($config['access-denied-url'])) {
$container->setParameter('security.access_denied.url', $config['access-denied-url']);
$container->setParameter('security.access.denied_url', $config['access-denied-url']);
}
// session fixation protection
if (isset($config['session_fixation_protection'])) {
$config['session-fixation-protection'] = $config['session_fixation_protection'];
}
if (isset($config['session-fixation-protection'])) {
$container->setParameter('security.authentication.session_strategy.strategy', $config['session-fixation-protection']);
}
$this->createFirewalls($config, $container);
@ -208,7 +218,13 @@ class SecurityExtension extends Extension
// Matcher
$i = 0;
$matcher = null;
if (isset($firewall['pattern'])) {
if (isset($firewall['request_matcher'])) {
$firewall['request-matcher'] = $firewall['request_matcher'];
}
if (isset($firewall['request-matcher'])) {
$matcher = new Reference($firewall['request-matcher']);
} else if (isset($firewall['pattern'])) {
$matcher = $this->createRequestMatcher($container, $firewall['pattern']);
}
@ -236,7 +252,12 @@ class SecurityExtension extends Extension
// Context serializer listener
if (!isset($firewall['stateless']) || !$firewall['stateless']) {
$listeners[] = new Reference('security.context_listener');
$contextKey = $id;
if (isset($firewall['context'])) {
$contextKey = $firewall['context'];
}
$listeners[] = new Reference($this->createContextListener($container, $contextKey));
}
// Logout listener
@ -246,6 +267,10 @@ class SecurityExtension extends Extension
$listeners[] = new Reference($listenerId);
if (!is_array($firewall['logout'])) {
$firewall['logout'] = array();
}
$arguments = $listener->getArguments();
if (isset($firewall['logout']['path'])) {
$arguments[1] = $firewall['logout']['path'];
@ -256,10 +281,19 @@ class SecurityExtension extends Extension
}
$listener->setArguments($arguments);
if (!isset($firewall['stateless']) || !$firewall['stateless']) {
// add session logout handler
$invalidateSession = true;
if (array_key_exists('invalidate_session', $firewall['logout'])) {
$firewall['logout']['invalidate-session'] = $firewall['logout']['invalidate_session'];
}
if (array_key_exists('invalidate-session', $firewall['logout'])) {
$invalidateSession = (Boolean) $invalidateSession;
}
if (true === $invalidateSession && (!isset($firewall['stateless']) || !$firewall['stateless'])) {
$listener->addMethodCall('addHandler', array(new Reference('security.logout.handler.session')));
}
// add cookie logout handler
if (count($cookies = $this->normalizeConfig($firewall['logout'], 'cookie')) > 0) {
$cookieHandlerId = 'security.logout.handler.cookie_clearing.'.$id;
$cookieHandler = $container->setDefinition($cookieHandlerId, clone $container->getDefinition('security.logout.handler.cookie_clearing'));
@ -275,7 +309,7 @@ class SecurityExtension extends Extension
$listeners = array_merge($listeners, $authListeners);
// Access listener
$listeners[] = new Reference($this->createAccessListener($container, $id, $providers));
$listeners[] = new Reference('security.access_listener');
// Switch user listener
if (array_key_exists('switch_user', $firewall)) {
@ -285,12 +319,35 @@ class SecurityExtension extends Extension
$listeners[] = new Reference($this->createSwitchUserListener($container, $id, $firewall['switch-user'], $defaultProvider));
}
// Determine default entry point
if (isset($firewall['entry_point'])) {
$firewall['entry-point'] = $firewall['entry_point'];
}
if (isset($firewall['entry-point'])) {
$defaultEntryPoint = $firewall['entry-point'];
}
// Exception listener
$exceptionListener = new Reference($this->createExceptionListener($container, $id, $defaultEntryPoint));
$exceptionListener = new Reference($this->createExceptionListener($container, $firewall, $id, $defaultEntryPoint));
return array($matcher, $listeners, $exceptionListener);
}
protected function createContextListener($container, $contextKey)
{
if (isset($this->contextListeners[$contextKey])) {
return $this->contextListeners[$contextKey];
}
$listenerId = 'security.context_listener.'.count($this->contextListeners);
$listener = $container->setDefinition($listenerId, clone $container->getDefinition('security.context_listener'));
$arguments = $listener->getArguments();
$arguments[2] = $contextKey;
$listener->setArguments($arguments);
return $this->contextListeners[$contextKey] = $listenerId;
}
protected function createAuthenticationListeners($container, $id, $firewall, $defaultProvider)
{
$listeners = array();
@ -298,7 +355,7 @@ class SecurityExtension extends Extension
$hasListeners = false;
$defaultEntryPoint = null;
$positions = array('pre_auth', 'form', 'http');
$positions = array('pre_auth', 'form', 'http', 'remember_me');
$tags = $container->findTaggedServiceIds('security.listener.factory');
$factories = array();
@ -323,9 +380,9 @@ class SecurityExtension extends Extension
if (array_key_exists($key, $firewall) && $firewall[$key] !== false) {
$userProvider = isset($firewall[$key]['provider']) ? $this->getUserProviderId($firewall[$key]['provider']) : $defaultProvider;
list($provider, $listener, $defaultEntryPoint) = $factory->create($container, $id, $firewall[$key], $userProvider, $defaultEntryPoint);
list($provider, $listenerId, $defaultEntryPoint) = $factory->create($container, $id, $firewall[$key], $userProvider, $defaultEntryPoint);
$listeners[] = new Reference($listener);
$listeners[] = new Reference($listenerId);
$providers[] = new Reference($provider);
$hasListeners = true;
}
@ -553,32 +610,27 @@ class SecurityExtension extends Extension
return 'security.authentication.provider.'.$name;
}
protected function createAccessListener($container, $id, $providers)
protected function createExceptionListener($container, $config, $id, $defaultEntryPoint)
{
// Authentication manager
$authManager = 'security.authentication.manager.'.$id;
$container
->register($authManager, '%security.authentication.manager.class%')
->addArgument($providers)
->setPublic(false)
;
if (isset($config['access_denied_handler'])) {
$config['access-denied-handler'] = $config['access_denied_handler'];
}
if (isset($config['access_denied_url'])) {
$config['access-denied-url'] = $config['access_denied_url'];
}
// Access listener
$listenerId = 'security.access_listener.'.$id;
$listener = $container->setDefinition($listenerId, clone $container->getDefinition('security.access_listener'));
$arguments = $listener->getArguments();
$arguments[3] = new Reference($authManager);
$listener->setArguments($arguments);
return $listenerId;
}
protected function createExceptionListener($container, $id, $defaultEntryPoint)
{
$exceptionListenerId = 'security.exception_listener.'.$id;
$listener = $container->setDefinition($exceptionListenerId, clone $container->getDefinition('security.exception_listener'));
$arguments = $listener->getArguments();
$arguments[2] = null === $defaultEntryPoint ? null : new Reference($defaultEntryPoint);
// access denied handler setup
if (isset($config['access-denied-handler'])) {
$arguments[4] = new Reference($config['access-denied-handler']);
} else if (isset($config['access-denied-url'])) {
$arguments[3] = $config['access-denied-url'];
}
$listener->setArguments($arguments);
return $exceptionListenerId;

View File

@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddAuthenticationProvidersPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConstraintValidatorsPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddFieldFactoryGuessersPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TemplatingPass;
@ -67,6 +68,7 @@ class FrameworkBundle extends Bundle
$container->addCompilerPass(new AddClassesToCachePass());
$container->addCompilerPass(new TranslatorPass());
$container->addCompilerPass(new AddCacheWarmerPass());
$container->addCompilerPass(new AddAuthenticationProvidersPass());
}
/**

View File

@ -6,6 +6,7 @@
<parameters>
<parameter key="security.context.class">Symfony\Component\Security\SecurityContext</parameter>
<parameter key="security.context.always_authenticate">false</parameter>
<parameter key="security.account_checker.class">Symfony\Component\Security\User\AccountChecker</parameter>
@ -23,14 +24,16 @@
<parameter key="security.authentication.provider.dao.class">Symfony\Component\Security\Authentication\Provider\DaoAuthenticationProvider</parameter>
<parameter key="security.authentication.provider.pre_authenticated.class">Symfony\Component\Security\Authentication\Provider\PreAuthenticatedAuthenticationProvider</parameter>
<parameter key="security.authentication.provider.rememberme.class">Symfony\Component\Security\Authentication\Provider\RememberMeAuthenticationProvider</parameter>
<parameter key="security.authentication.manager.class">Symfony\Component\Security\Authentication\AuthenticationProviderManager</parameter>
<parameter key="security.authentication.retry_entry_point.class">Symfony\Component\HttpKernel\Security\EntryPoint\RetryAuthenticationEntryPoint</parameter>
<parameter key="security.authentication.session_strategy.class">Symfony\Component\HttpKernel\Security\Session\SessionAuthenticationStrategy</parameter>
<parameter key="security.authentication.session_strategy.strategy">migrate</parameter>
<parameter key="security.authentication.form_entry_point.class">Symfony\Component\HttpKernel\Security\EntryPoint\FormAuthenticationEntryPoint</parameter>
<parameter key="security.authentication.form.login_path">/login</parameter>
<parameter key="security.authentication.form.use_forward">false</parameter>
<parameter key="security.authentication.listener.form.class">Symfony\Component\HttpKernel\Security\Firewall\UsernamePasswordFormAuthenticationListener</parameter>
<parameter key="security.authentication.form.options" type="collection" />
@ -48,8 +51,24 @@
<parameter key="security.authentication.listener.basic.class">Symfony\Component\HttpKernel\Security\Firewall\BasicAuthenticationListener</parameter>
<parameter key="security.authentication.listener.digest.class">Symfony\Component\HttpKernel\Security\Firewall\DigestAuthenticationListener</parameter>
<parameter key="security.authentication.listener.anonymous.class">Symfony\Component\HttpKernel\Security\Firewall\AnonymousAuthenticationListener</parameter>
<parameter key="security.authentication.provider.anonymous">Symfony\Component\Security\Authentication\Provider\AnonymousAuthenticationProvider</parameter>
<parameter key="security.anonymous.key">SomeRandomValue</parameter>
<parameter key="security.authentication.listener.rememberme.class">Symfony\Component\HttpKernel\Security\Firewall\RememberMeListener</parameter>
<parameter key="security.rembemerme.token.provider.in_memory.class">Symfony\Component\Security\Authentication\RememberMe\InMemoryTokenProvider</parameter>
<parameter key="security.authentication.rememberme.services.persistent.class">Symfony\Component\HttpKernel\Security\RememberMe\PersistentTokenBasedRememberMeServices</parameter>
<parameter key="security.authentication.rememberme.services.simplehash.class">Symfony\Component\HttpKernel\Security\RememberMe\TokenBasedRememberMeServices</parameter>
<parameter key="security.authentication.rememberme.services.options.name">SYMFONY_REMEMBERME</parameter>
<parameter key="security.authentication.rememberme.services.options.lifetime">31536000</parameter>
<parameter key="security.authentication.rememberme.services.options.path">/</parameter>
<parameter key="security.authentication.rememberme.services.options.domain" />
<parameter key="security.authentication.rememberme.services.options.secure">false</parameter>
<parameter key="security.authentication.rememberme.services.options.httponly">true</parameter>
<parameter key="security.authentication.rememberme.services.options.always_remember_me">false</parameter>
<parameter key="security.authentication.rememberme.services.options.remember_me_parameter">_remember_me</parameter>
<parameter key="security.channel_listener.class">Symfony\Component\HttpKernel\Security\Firewall\ChannelListener</parameter>
<parameter key="security.logout_listener.class">Symfony\Component\HttpKernel\Security\Firewall\LogoutListener</parameter>
@ -67,6 +86,8 @@
<parameter key="security.access.decision_manager.allow_if_all_abstain">false</parameter>
<parameter key="security.access.decision_manager.allow_if_equal_granted_denied">true</parameter>
<parameter key="security.access.denied_url">/access_denied</parameter>
<parameter key="security.access.simple_role_voter.class">Symfony\Component\Security\Authorization\Voter\RoleVoter</parameter>
<parameter key="security.access.authenticated_voter.class">Symfony\Component\Security\Authorization\Voter\AuthenticatedVoter</parameter>
<parameter key="security.access.role_hierarchy_voter.class">Symfony\Component\Security\Authorization\Voter\RoleHierarchyVoter</parameter>
@ -85,7 +106,9 @@
<services>
<service id="security.context" class="%security.context.class%">
<argument type="service" id="security.authentication.manager" />
<argument type="service" id="security.access.decision_manager" />
<argument>%security.context.always_authenticate%</argument>
</service>
<service id="security.role_hierarchy" class="%security.role_hierarchy.class%" public="false">
@ -108,18 +131,28 @@
<argument type="service" id="logger" on-invalid="null" />
</service>
<service id="security.authentication.manager" class="%security.authentication.manager.class%" public="false">
<argument type="collection" />
</service>
<service id="security.authentication.provider.anonymous" class="%security.authentication.provider.anonymous%" public="false">
<argument>%security.anonymous.key%</argument>
<tag name="security.authentication_provider" />
</service>
<service id="security.authentication.trust_resolver" class="%security.authentication.trust_resolver.class%" public="false">
<argument>%security.authentication.trust_resolver.anonymous_class%</argument>
<argument>%security.authentication.trust_resolver.rememberme_class%</argument>
</service>
<service id="security.authentication.retry_entry_point" class="%security.authentication.retry_entry_point.class%" public="false" />
<service id="security.authentication.form_entry_point" class="%security.authentication.form_entry_point.class%" public="false">
<argument>%security.authentication.form.login_path%</argument>
<argument>%security.authentication.form.use_forward%</argument>
<service id="security.authentication.session_strategy" class="%security.authentication.session_strategy.class%" public="false">
<argument>%security.authentication.session_strategy.strategy%</argument>
</service>
<service id="security.rememberme.token.provider.in_memory" class="%security.rembemerme.token.provider.in_memory.class%" public="false"></service>
<service id="security.authentication.retry_entry_point" class="%security.authentication.retry_entry_point.class%" public="false" />
<service id="security.authentication.basic_entry_point" class="%security.authentication.basic_entry_point.class%" public="false">
<argument>%security.authentication.basic_entry_point.realm%</argument>
</service>
@ -168,6 +201,7 @@
<service id="security.context_listener" class="%security.context_listener.class%" public="false">
<argument type="service" id="security.context" />
<argument type="collection"></argument>
<argument />
<argument type="service" id="logger" on-invalid="null" />
</service>
</services>

View File

@ -21,26 +21,47 @@
<tag name="security.listener.factory" />
</service>
<service id="security.authentication.factory.remember_me" class="Symfony\Bundle\FrameworkBundle\DependencyInjection\Security\Factory\RememberMeFactory" public="false">
<tag name="security.listener.factory" />
</service>
<service id="security.logout_listener" class="%security.logout_listener.class%" public="false">
<argument type="service" id="security.context" />
<argument>%security.logout.path%</argument>
<argument>%security.logout.target_path%</argument>
</service>
<service id="security.logout.handler.cookie_clearing" class="%security.logout.handler.cookie_clearing.class%" public="false">
<argument type="collection"></argument>
</service>
<service id="security.authentication.form_entry_point" class="%security.authentication.form_entry_point.class%" public="false">
<argument/>
<argument/>
</service>
<service id="security.authentication.listener.form" class="%security.authentication.listener.form.class%" public="false">
<argument type="service" id="security.context" />
<argument type="service" id="security.authentication.manager" />
<argument>%security.authentication.form.options%</argument>
<argument type="service" id="security.authentication.session_strategy" />
<argument />
<argument type="collection"></argument>
<argument type="service" id="security.authentication.success_handler" on-invalid="null" />
<argument type="service" id="security.authentication.failure_handler" on-invalid="null" />
<argument type="service" id="logger" on-invalid="null" />
</service>
<service id="security.authentication.listener.rememberme" class="%security.authentication.listener.rememberme.class%" public="false">
<argument type="service" id="security.context" />
<argument type="service" id="security.authentication.rememberme" />
<argument type="service" id="security.authentication.manager" />
<argument type="service" id="logger" on-invalid="null" />
</service>
<service id="security.authentication.listener.x509" class="%security.authentication.listener.x509.class%" public="false">
<argument type="service" id="security.context" />
<argument type="service" id="security.authentication.manager" />
<argument />
<argument>%security.authentication.x509.user%</argument>
<argument>%security.authentication.x509.credentials%</argument>
<argument type="service" id="logger" on-invalid="null" />
@ -49,6 +70,7 @@
<service id="security.authentication.listener.basic" class="%security.authentication.listener.basic.class%" public="false">
<argument type="service" id="security.context" />
<argument type="service" id="security.authentication.manager" />
<argument></argument>
<argument type="service" id="security.authentication.basic_entry_point" />
<argument type="service" id="logger" on-invalid="null" />
</service>
@ -56,18 +78,55 @@
<service id="security.authentication.listener.digest" class="%security.authentication.listener.digest.class%" public="false">
<argument type="service" id="security.context" />
<argument type="service" id="security.user.provider.in_memory" />
<argument></argument>
<argument type="service" id="security.authentication.digest_entry_point" />
<argument type="service" id="logger" on-invalid="null" />
</service>
<service id="security.authentication.rememberme.services.simplehash" class="%security.authentication.rememberme.services.simplehash.class%" public="false">
<argument type="collection" />
<argument />
<argument />
<argument type="collection">
<argument key="name">%security.authentication.rememberme.services.options.name%</argument>
<argument key="lifetime">%security.authentication.rememberme.services.options.lifetime%</argument>
<argument key="path">%security.authentication.rememberme.services.options.path%</argument>
<argument key="domain">%security.authentication.rememberme.services.options.domain%</argument>
<argument key="secure">%security.authentication.rememberme.services.options.secure%</argument>
<argument key="httponly">%security.authentication.rememberme.services.options.httponly%</argument>
<argument key="always_remember_me">%security.authentication.rememberme.services.options.always_remember_me%</argument>
<argument key="remember_me_parameter">%security.authentication.rememberme.services.options.remember_me_parameter%</argument>
</argument>
<argument type="service" id="logger" on-invalid="null" />
</service>
<service id="security.authentication.rememberme.services.persistent" class="%security.authentication.rememberme.services.persistent.class%" public="false">
<argument type="collection" />
<argument />
<argument />
<argument type="collection">
<argument key="name">%security.authentication.rememberme.services.options.name%</argument>
<argument key="lifetime">%security.authentication.rememberme.services.options.lifetime%</argument>
<argument key="path">%security.authentication.rememberme.services.options.path%</argument>
<argument key="domain">%security.authentication.rememberme.services.options.domain%</argument>
<argument key="secure">%security.authentication.rememberme.services.options.secure%</argument>
<argument key="httponly">%security.authentication.rememberme.services.options.httponly%</argument>
<argument key="always_remember_me">%security.authentication.rememberme.services.options.always_remember_me%</argument>
<argument key="remember_me_parameter">%security.authentication.rememberme.services.options.remember_me_parameter%</argument>
</argument>
<argument type="service" id="logger" on-invalid="null" />
</service>
<service id="security.exception_listener" class="%security.exception_listener.class%" public="false">
<argument type="service" id="security.context" />
<argument type="service" id="security.authentication.trust_resolver" />
<argument type="service" id="security.authentication.entry_point" on-invalid="null" />
<argument>%security.access_denied.url%</argument>
<argument>%security.access.denied_url%</argument>
<argument type="service" id="security.access.denied_handler" on-invalid="null" />
<argument type="service" id="logger" on-invalid="null" />
</service>
<service id="security.authentication.switchuser_listener" class="%security.authentication.switchuser_listener.class%" public="false">
<argument type="service" id="security.context" />
<argument type="service" id="security.user.provider.in_memory" />

View File

@ -35,7 +35,7 @@ abstract class SecurityExtensionTest extends TestCase
$providers = array_values(array_filter($container->getServiceIds(), function ($key) { return 0 === strpos($key, 'security.authentication.provider.'); }));
$this->assertEquals(array(
$expectedProviders = array(
'security.authentication.provider.digest',
'security.authentication.provider.digest_0ff1b54f2a4b7f71b2b9d6604fcca4b8',
'security.authentication.provider.basic',
@ -43,7 +43,11 @@ abstract class SecurityExtensionTest extends TestCase
'security.authentication.provider.basic_98e44377704554700e68c22094b51ca4',
'security.authentication.provider.doctrine',
'security.authentication.provider.service',
), $providers);
'security.authentication.provider.anonymous',
);
$this->assertEquals(array(), array_diff($expectedProviders, $providers));
$this->assertEquals(array(), array_diff($providers, $expectedProviders));
}
public function testFirewalls()

View File

@ -0,0 +1,11 @@
<?php
namespace Symfony\Component\HttpKernel\Security\Authentication;
use Symfony\Component\EventDispatcher\EventInterface;
use Symfony\Component\HttpFoundation\Request;
interface AuthenticationFailureHandlerInterface
{
function onAuthenticationFailure(EventInterface $event, Request $request, \Exception $exception);
}

View File

@ -0,0 +1,12 @@
<?php
namespace Symfony\Component\HttpKernel\Security\Authentication;
use Symfony\Component\EventDispatcher\EventInterface;
use Symfony\Component\Security\Authentication\Token\TokenInterface;
use Symfony\Component\HttpFoundation\Request;
interface AuthenticationSuccessHandlerInterface
{
function onAuthenticationSuccess(EventInterface $event, Request $request, TokenInterface $token);
}

View File

@ -0,0 +1,27 @@
<?php
namespace Symfony\Component\HttpKernel\Security\ExceptionTranslation;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\EventDispatcher\EventInterface;
use Symfony\Component\Security\Exception\AccessDeniedException;
/**
* This is used by the ExceptionListener to translate an AccessDeniedException
* to a Response object.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
interface AccessDeniedHandlerInterface
{
/**
* Handles an access denied failure.
*
* @param EventInterface $event
* @param Request $request
* @param AccessDeniedException $accessDeniedException
*
* @return Response may return null
*/
function handle(EventInterface $event, Request $request, AccessDeniedException $accessDeniedException);
}

View File

@ -11,6 +11,12 @@
namespace Symfony\Component\HttpKernel\Security\Firewall;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\HttpKernel\Security\Session\SessionAuthenticationStrategyInterface;
use Symfony\Component\HttpKernel\Security\Authentication\AuthenticationFailureHandlerInterface;
use Symfony\Component\HttpKernel\Security\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\HttpKernel\Security\RememberMe\RememberMeServicesInterface;
use Symfony\Component\Security\SecurityContext;
use Symfony\Component\Security\Authentication\AuthenticationManagerInterface;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
@ -23,29 +29,55 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Authentication\Token\TokenInterface;
/**
* FormAuthenticationListener implements authentication via a form.
* The AbstractAuthenticationListener is the preferred base class for all
* browser-/HTTP-based authentication requests.
*
* 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
*
* 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
* requiresAuthentication() method.
*
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
abstract class FormAuthenticationListener
abstract class AbstractAuthenticationListener implements ListenerInterface
{
protected $securityContext;
protected $authenticationManager;
protected $sessionStrategy;
protected $providerKey;
protected $eventDispatcher;
protected $options;
protected $successHandler;
protected $failureHandler;
protected $logger;
protected $rememberMeServices;
/**
* Constructor.
*
* @param SecurityContext $securityContext A SecurityContext instance
* @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance
* @param array $options An array of options
* @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(SecurityContext $securityContext, AuthenticationManagerInterface $authenticationManager, array $options = array(), LoggerInterface $logger = null)
public function __construct(SecurityContext $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, $providerKey, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null)
{
if (empty($providerKey)) {
throw new \InvalidArgumentException('$providerKey must not be empty.');
}
$this->securityContext = $securityContext;
$this->authenticationManager = $authenticationManager;
$this->sessionStrategy = $sessionStrategy;
$this->providerKey = $providerKey;
$this->successHandler = $successHandler;
$this->failureHandler = $failureHandler;
$this->options = array_merge(array(
'check_path' => '/login_check',
'login_path' => '/login',
@ -60,14 +92,26 @@ abstract class FormAuthenticationListener
}
/**
* Sets the RememberMeServices implementation to use
*
* @param RememberMeServicesInterface $rememberMeServices
*/
public function setRememberMeServices(RememberMeServicesInterface $rememberMeServices)
{
$this->rememberMeServices = $rememberMeServices;
}
/**
* Subscribe to the core.security event
*
* @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
* @param integer $priority The priority
* @param EventDispatcher $dispatcher An EventDispatcher instance
* @param integer $priority The priority
*/
public function register(EventDispatcherInterface $dispatcher)
{
$dispatcher->connect('core.security', array($this, 'handle'), 0);
$this->eventDispatcher = $dispatcher;
}
/**
@ -80,32 +124,56 @@ abstract class FormAuthenticationListener
/**
* Handles form based authentication.
*
* @param EventInterface $event An EventInterface instance
* @param Event $event An Event instance
*/
public function handle(EventInterface $event)
{
$request = $event->get('request');
if ($this->options['check_path'] !== $request->getPathInfo()) {
if (!$this->requiresAuthentication($request)) {
return;
}
try {
if (null === $token = $this->attemptAuthentication($request)) {
if (null === $returnValue = $this->attemptAuthentication($request)) {
return;
}
$response = $this->onSuccess($request, $token);
if ($returnValue instanceof TokenInterface) {
$this->sessionStrategy->onAuthentication($request, $returnValue);
$response = $this->onSuccess($event, $request, $returnValue);
} else if ($returnValue instanceof Response) {
$response = $returnValue;
} else {
throw new \RuntimeException('attemptAuthentication() must either return a Response, an implementation of TokenInterface, or null.');
}
} catch (AuthenticationException $failed) {
$response = $this->onFailure($event->getSubject(), $request, $failed);
$response = $this->onFailure($event, $request, $failed);
}
$event->setProcessed();
$event->setReturnValue($response);
return $response;
return true;
}
protected function onFailure($kernel, Request $request, \Exception $failed)
/**
* Whether this request requires authentication.
*
* The default implementation only processed requests to a specific path,
* but a subclass could change this to only authenticate requests where a
* certain parameters is present.
*
* @param Request $request
*
* @return Boolean
*/
protected function requiresAuthentication(Request $request)
{
return $this->options['check_path'] === $request->getPathInfo();
}
protected function onFailure($event, Request $request, \Exception $failed)
{
if (null !== $this->logger) {
$this->logger->debug(sprintf('Authentication request failed: %s', $failed->getMessage()));
@ -113,6 +181,10 @@ abstract class FormAuthenticationListener
$this->securityContext->setToken(null);
if (null !== $this->failureHandler) {
return $this->failureHandler->onAuthenticationFailure($event, $request, $failed);
}
if (null === $this->options['failure_path']) {
$this->options['failure_path'] = $this->options['login_path'];
}
@ -125,7 +197,7 @@ abstract class FormAuthenticationListener
$subRequest = Request::create($this->options['failure_path']);
$subRequest->attributes->set(SecurityContext::AUTHENTICATION_ERROR, $failed->getMessage());
return $kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
return $event->getSubject()->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
} else {
if (null !== $this->logger) {
$this->logger->debug(sprintf('Redirecting to %s', $this->options['failure_path']));
@ -140,7 +212,7 @@ abstract class FormAuthenticationListener
}
}
protected function onSuccess(Request $request, TokenInterface $token)
protected function onSuccess(EventInterface $event, Request $request, TokenInterface $token)
{
if (null !== $this->logger) {
$this->logger->debug('User has been authenticated successfully');
@ -152,15 +224,29 @@ abstract class FormAuthenticationListener
$session->remove(SecurityContext::AUTHENTICATION_ERROR);
$session->remove(SecurityContext::LAST_USERNAME);
$this->eventDispatcher->notify(new Event($this, 'security.login_success', array('request' => $request, 'token' => $token)));
if (null !== $this->successHandler) {
return $this->successHandler->onAuthenticationSuccess($request, $token);
}
$response = new Response();
$path = $this->determineTargetUrl($request);
$response->setRedirect(0 !== strpos($path, 'http') ? $request->getUriForPath($path) : $path, 302);
if (null !== $this->rememberMeServices) {
$this->rememberMeServices->loginSuccess($request, $response, $token);
}
return $response;
}
/**
* Builds the target URL according to the defined options.
*
* @param Request $request
*
* @return string
*/
protected function determineTargetUrl(Request $request)
{
@ -180,7 +266,6 @@ abstract class FormAuthenticationListener
}
if ($this->options['use_referer'] && $targetUrl = $request->headers->get('Referer')) {
return $targetUrl;
}

View File

@ -29,21 +29,27 @@ class BasicAuthenticationListener implements ListenerInterface
{
protected $securityContext;
protected $authenticationManager;
protected $providerKey;
protected $authenticationEntryPoint;
protected $logger;
protected $ignoreFailure;
public function __construct(SecurityContext $securityContext, AuthenticationManagerInterface $authenticationManager, AuthenticationEntryPointInterface $authenticationEntryPoint, LoggerInterface $logger = null)
public function __construct(SecurityContext $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, AuthenticationEntryPointInterface $authenticationEntryPoint, LoggerInterface $logger = null)
{
if (empty($providerKey)) {
throw new \InvalidArgumentException('$providerKey must not be empty.');
}
$this->securityContext = $securityContext;
$this->authenticationManager = $authenticationManager;
$this->providerKey = $providerKey;
$this->authenticationEntryPoint = $authenticationEntryPoint;
$this->logger = $logger;
$this->ignoreFailure = false;
}
/**
*
*
*
* @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
* @param integer $priority The priority
@ -52,7 +58,7 @@ class BasicAuthenticationListener implements ListenerInterface
{
$dispatcher->connect('core.security', array($this, 'handle'), 0);
}
/**
* {@inheritDoc}
*/
@ -88,7 +94,7 @@ class BasicAuthenticationListener implements ListenerInterface
}
try {
$token = $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $request->server->get('PHP_AUTH_PW')));
$token = $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $request->server->get('PHP_AUTH_PW'), $this->providerKey));
$this->securityContext->setToken($token);
} catch (AuthenticationException $failed) {
$this->securityContext->setToken(null);

View File

@ -32,13 +32,19 @@ use Symfony\Component\Security\User\AccountInterface;
class ContextListener implements ListenerInterface
{
protected $context;
protected $contextKey;
protected $logger;
protected $userProviders;
public function __construct(SecurityContext $context, array $userProviders, LoggerInterface $logger = null)
public function __construct(SecurityContext $context, array $userProviders, $contextKey, LoggerInterface $logger = null)
{
if (empty($contextKey)) {
throw new \InvalidArgumentException('$contextKey must not be empty.');
}
$this->context = $context;
$this->userProviders = $userProviders;
$this->contextKey = $contextKey;
$this->logger = $logger;
}
@ -74,7 +80,7 @@ class ContextListener implements ListenerInterface
$session = $request->hasSession() ? $request->getSession() : null;
if (null === $session || null === $token = $session->get('_security')) {
if (null === $session || null === $token = $session->get('_security_'.$this->contextKey)) {
$this->context->setToken(null);
} else {
if (null !== $this->logger) {
@ -114,7 +120,7 @@ class ContextListener implements ListenerInterface
$this->logger->debug('Write SecurityContext in the session');
}
$event->get('request')->getSession()->set('_security', serialize($token));
$event->get('request')->getSession()->set('_security_'.$this->contextKey, serialize($token));
return $response;
}
@ -148,10 +154,18 @@ class ContextListener implements ListenerInterface
$token->setAuthenticated(false);
}
if (null !== $this->logger) {
$this->logger->debug(sprintf('Username "%s" was reloaded from user provider.', $user));
}
return $token;
} catch (UnsupportedAccountException $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));
}
return null;
}
}

View File

@ -34,19 +34,25 @@ class DigestAuthenticationListener implements ListenerInterface
{
protected $securityContext;
protected $provider;
protected $providerKey;
protected $authenticationEntryPoint;
protected $logger;
public function __construct(SecurityContext $securityContext, UserProviderInterface $provider, DigestAuthenticationEntryPoint $authenticationEntryPoint, LoggerInterface $logger = null)
public function __construct(SecurityContext $securityContext, UserProviderInterface $provider, $providerKey, DigestAuthenticationEntryPoint $authenticationEntryPoint, LoggerInterface $logger = null)
{
if (empty($providerKey)) {
throw new \InvalidArgumentException('$providerKey must not be empty.');
}
$this->securityContext = $securityContext;
$this->provider = $provider;
$this->providerKey = $providerKey;
$this->authenticationEntryPoint = $authenticationEntryPoint;
$this->logger = $logger;
}
/**
*
*
*
* @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
* @param integer $priority The priority
@ -55,7 +61,7 @@ class DigestAuthenticationListener implements ListenerInterface
{
$dispatcher->connect('core.security', array($this, 'handle'), 0);
}
/**
* {@inheritDoc}
*/
@ -134,7 +140,7 @@ class DigestAuthenticationListener implements ListenerInterface
$this->logger->debug(sprintf('Authentication success for user "%s" with response "%s"', $digestAuth->getUsername(), $digestAuth->getResponse()));
}
$this->securityContext->setToken(new UsernamePasswordToken($user, $user->getPassword()));
$this->securityContext->setToken(new UsernamePasswordToken($user, $user->getPassword(), $this->providerKey));
}
protected function fail(Request $request, AuthenticationException $failed)

View File

@ -11,6 +11,9 @@
namespace Symfony\Component\HttpKernel\Security\Firewall;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Security\AccessDeniedHandler;
use Symfony\Component\HttpKernel\Security\ExceptionTranslation\AccessDeniedHandlerInterface;
use Symfony\Component\Security\SecurityContext;
use Symfony\Component\Security\Authentication\AuthenticationTrustResolverInterface;
use Symfony\Component\Security\Authentication\EntryPoint\AuthenticationEntryPointInterface;
@ -33,14 +36,16 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
class ExceptionListener implements ListenerInterface
{
protected $context;
protected $accessDeniedHandler;
protected $authenticationEntryPoint;
protected $authenticationTrustResolver;
protected $errorPage;
protected $logger;
public function __construct(SecurityContext $context, AuthenticationTrustResolverInterface $trustResolver, AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, LoggerInterface $logger = null)
public function __construct(SecurityContext $context, AuthenticationTrustResolverInterface $trustResolver, AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, AccessDeniedHandlerInterface $accessDeniedHandler = null, LoggerInterface $logger = null)
{
$this->context = $context;
$this->accessDeniedHandler = $accessDeniedHandler;
$this->authenticationEntryPoint = $authenticationEntryPoint;
$this->authenticationTrustResolver = $trustResolver;
$this->errorPage = $errorPage;
@ -57,7 +62,7 @@ class ExceptionListener implements ListenerInterface
{
$dispatcher->connect('core.exception', array($this, 'handleException'), 0);
}
/**
* {@inheritDoc}
*/
@ -107,15 +112,26 @@ class ExceptionListener implements ListenerInterface
$this->logger->info('Access is denied (and user is neither anonymous, nor remember-me)');
}
if (null === $this->errorPage) {
return;
}
$subRequest = Request::create($this->errorPage);
$subRequest->attributes->set(SecurityContext::ACCESS_DENIED_ERROR, $exception->getMessage());
try {
$response = $event->getSubject()->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true);
if (null !== $this->accessDeniedHandler) {
$response = $this->accessDeniedHandler->handle($event, $request, $exception);
if (!$response instanceof Response) {
return;
}
} else {
if (null === $this->errorPage) {
return;
}
$subRequest = Request::create($this->errorPage);
$subRequest->attributes->set(SecurityContext::ACCESS_DENIED_ERROR, $exception->getMessage());
$response = $event->getSubject()->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true);
$response->setStatusCode(403);
return $response;
}
} catch (\Exception $e) {
if (null !== $this->logger) {
$this->logger->err(sprintf('Exception thrown when handling an exception (%s: %s)', get_class($e), $e->getMessage()));
@ -125,7 +141,6 @@ class ExceptionListener implements ListenerInterface
return;
}
$response->setStatusCode(403);
}
} else {
return;

View File

@ -89,6 +89,7 @@ class LogoutListener implements ListenerInterface
$response = new Response();
$response->setRedirect(0 !== strpos($this->targetUrl, 'http') ? $request->getUriForPath($this->targetUrl) : $this->targetUrl, 302);
// handle multiple logout attempts gracefully
if ($token = $this->securityContext->getToken()) {
foreach ($this->handlers as $handler) {
$handler->logout($request, $response, $token);

View File

@ -31,17 +31,19 @@ abstract class PreAuthenticatedListener implements ListenerInterface
{
protected $securityContext;
protected $authenticationManager;
protected $providerKey;
protected $logger;
public function __construct(SecurityContext $securityContext, AuthenticationManagerInterface $authenticationManager, LoggerInterface $logger = null)
public function __construct(SecurityContext $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, LoggerInterface $logger = null)
{
$this->securityContext = $securityContext;
$this->authenticationManager = $authenticationManager;
$this->providerKey = $providerKey;
$this->logger = $logger;
}
/**
*
*
*
* @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
* @param integer $priority The priority
@ -50,14 +52,14 @@ abstract class PreAuthenticatedListener implements ListenerInterface
{
$dispatcher->connect('core.security', array($this, 'handle'), 0);
}
/**
* {@inheritDoc}
*/
public function unregister(EventDispatcherInterface $dispatcher)
{
}
/**
* Handles X509 authentication.
*
@ -88,7 +90,7 @@ abstract class PreAuthenticatedListener implements ListenerInterface
}
try {
$token = $this->authenticationManager->authenticate(new PreAuthenticatedToken($user, $credentials));
$token = $this->authenticationManager->authenticate(new PreAuthenticatedToken($user, $credentials, $this->providerKey));
if (null !== $this->logger) {
$this->logger->debug(sprintf('Authentication success: %s', $token));

View File

@ -0,0 +1,148 @@
<?php
namespace Symfony\Component\HttpKernel\Security\Firewall;
use Symfony\Component\Security\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Exception\AuthenticationException;
use Symfony\Component\Security\Exception\CookieTheftException;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
use Symfony\Component\Security\Authentication\AuthenticationManagerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\SecurityContext;
use Symfony\Component\HttpKernel\Security\RememberMe\RememberMeServicesInterface;
/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* RememberMeListener implements authentication capabilities via a cookie
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class RememberMeListener implements ListenerInterface
{
protected $securityContext;
protected $rememberMeServices;
protected $authenticationManager;
protected $logger;
protected $lastState;
/**
* Constructor
*
* @param SecurityContext $securityContext
* @param RememberMeServicesInterface $rememberMeServices
* @param AuthenticationManagerInterface $authenticationManager
* @param LoggerInterface $logger
*/
public function __construct(SecurityContext $securityContext, RememberMeServicesInterface $rememberMeServices, AuthenticationManagerInterface $authenticationManager, LoggerInterface $logger = null)
{
$this->securityContext = $securityContext;
$this->rememberMeServices = $rememberMeServices;
$this->authenticationManager = $authenticationManager;
$this->logger = $logger;
}
/**
* Listen to core.security, and core.response event
*
* @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
* @param integer $priority The priority
*/
public function register(EventDispatcherInterface $dispatcher)
{
$dispatcher->connect('core.security', array($this, 'checkCookies'), 0);
$dispatcher->connect('core.response', array($this, 'updateCookies'), 0);
}
/**
* {@inheritDoc}
*/
public function unregister(EventDispatcherInterface $dispatcher)
{
$dispatcher->disconnect('core.response', array($this, 'updateCookies'));
}
/**
* Handles remember-me cookie based authentication.
*
* @param Event $event An Event instance
*/
public function checkCookies(EventInterface $event)
{
$this->lastState = null;
if (null !== $this->securityContext->getToken()) {
return;
}
try {
if (null === $token = $this->rememberMeServices->autoLogin($event->get('request'))) {
return;
}
try {
if (null === $token = $this->authenticationManager->authenticate($token)) {
return;
}
$this->securityContext->setToken($token);
if (null !== $this->logger) {
$this->logger->debug('SecurityContext populated with remember-me token.');
}
$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()
);
}
$this->lastState = $failed;
}
} catch (AuthenticationException $cookieInvalid) {
$this->lastState = $cookieInvalid;
if (null !== $this->logger) {
$this->logger->debug('The presented cookie was invalid: '.$cookieInvalid->getMessage());
}
// silently ignore everything except a cookie theft exception
if ($cookieInvalid instanceof CookieTheftException) {
throw $cookieInvalid;
}
}
}
/**
* Update cookies
* @param Event $event
*/
public function updateCookies(EventInterface $event, Response $response)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->get('request_type')) {
return $response;
}
if ($this->lastState instanceof TokenInterface) {
$this->rememberMeServices->loginSuccess($event->get('request'), $response, $this->lastState);
} else if ($this->lastState instanceof AuthenticationException) {
$this->rememberMeServices->loginFail($event->get('request'), $response);
}
return $response;
}
}

View File

@ -37,6 +37,7 @@ class SwitchUserListener implements ListenerInterface
protected $securityContext;
protected $provider;
protected $accountChecker;
protected $providerKey;
protected $accessDecisionManager;
protected $usernameParameter;
protected $role;
@ -45,11 +46,16 @@ class SwitchUserListener implements ListenerInterface
/**
* Constructor.
*/
public function __construct(SecurityContext $securityContext, UserProviderInterface $provider, AccountCheckerInterface $accountChecker, AccessDecisionManagerInterface $accessDecisionManager, LoggerInterface $logger = null, $usernameParameter = '_switch_user', $role = 'ROLE_ALLOWED_TO_SWITCH')
public function __construct(SecurityContext $securityContext, UserProviderInterface $provider, AccountCheckerInterface $accountChecker, $providerKey, AccessDecisionManagerInterface $accessDecisionManager, LoggerInterface $logger = null, $usernameParameter = '_switch_user', $role = 'ROLE_ALLOWED_TO_SWITCH')
{
if (empty($providerKey)) {
throw new \InvalidArgumentException('$providerKey must not be empty.');
}
$this->securityContext = $securityContext;
$this->provider = $provider;
$this->accountChecker = $accountChecker;
$this->providerKey = $providerKey;
$this->accessDecisionManager = $accessDecisionManager;
$this->usernameParameter = $usernameParameter;
$this->role = $role;
@ -57,7 +63,7 @@ class SwitchUserListener implements ListenerInterface
}
/**
*
*
*
* @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
* @param integer $priority The priority
@ -66,14 +72,14 @@ class SwitchUserListener implements ListenerInterface
{
$dispatcher->connect('core.security', array($this, 'handle'), 0);
}
/**
* {@inheritDoc}
*/
public function unregister(EventDispatcherInterface $dispatcher)
{
}
/**
* Handles digest authentication.
*
@ -136,7 +142,7 @@ class SwitchUserListener implements ListenerInterface
$roles = $user->getRoles();
$roles[] = new SwitchUserRole('ROLE_PREVIOUS_ADMIN', $this->securityContext->getToken());
$token = new UsernamePasswordToken($user, $user->getPassword(), $roles);
$token = new UsernamePasswordToken($user, $user->getPassword(), $this->providerKey, $roles);
$token->setImmutable(true);
return $token;

View File

@ -11,6 +11,12 @@
namespace Symfony\Component\HttpKernel\Security\Firewall;
use Symfony\Component\HttpKernel\Security\Authentication\AuthenticationFailureHandlerInterface;
use Symfony\Component\HttpKernel\Security\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\HttpKernel\Security\Session\SessionAuthenticationStrategyInterface;
use Symfony\Component\Security\SecurityContext;
use Symfony\Component\Security\Authentication\AuthenticationManagerInterface;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
@ -23,18 +29,18 @@ use Symfony\Component\Security\Authentication\Token\UsernamePasswordToken;
*
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
*/
class UsernamePasswordFormAuthenticationListener extends FormAuthenticationListener
class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationListener
{
/**
* {@inheritdoc}
*/
public function __construct(SecurityContext $securityContext, AuthenticationManagerInterface $authenticationManager, array $options = array(), LoggerInterface $logger = null)
public function __construct(SecurityContext $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, $providerKey, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null)
{
parent::__construct($securityContext, $authenticationManager, array_merge(array(
parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $providerKey, array_merge(array(
'username_parameter' => '_username',
'password_parameter' => '_password',
'post_only' => true,
), $options), $logger);
), $options), $successHandler, $failureHandler, $logger);
}
/**
@ -55,6 +61,6 @@ class UsernamePasswordFormAuthenticationListener extends FormAuthenticationListe
$request->getSession()->set(SecurityContext::LAST_USERNAME, $username);
return $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password));
return $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey));
}
}

View File

@ -27,9 +27,9 @@ class X509AuthenticationListener extends PreAuthenticatedListener
protected $userKey;
protected $credentialKey;
public function __construct(SecurityContext $securityContext, AuthenticationManagerInterface $authenticationManager, $userKey = 'SSL_CLIENT_S_DN_Email', $credentialKey = 'SSL_CLIENT_S_DN', LoggerInterface $logger = null)
public function __construct(SecurityContext $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, $userKey = 'SSL_CLIENT_S_DN_Email', $credentialKey = 'SSL_CLIENT_S_DN', LoggerInterface $logger = null)
{
parent::__construct($securityContext, $authenticationManager, $logger);
parent::__construct($securityContext, $authenticationManager, $providerKey, $logger);
$this->userKey = $userKey;
$this->credentialKey = $credentialKey;

View File

@ -56,4 +56,4 @@ class CookieClearingLogoutHandler implements LogoutHandlerInterface
$response->headers->clearCookie($cookieName);
}
}
}
}

View File

@ -17,7 +17,7 @@ use Symfony\Component\HttpFoundation\Request;
/**
* Interface that needs to be implemented by LogoutHandlers.
*
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
interface LogoutHandlerInterface
@ -26,7 +26,7 @@ interface LogoutHandlerInterface
* This method is called by the LogoutListener when a user has requested
* to be logged out. Usually, you would unset session variables, or remove
* cookies, etc.
*
*
* @param Request $request
* @param Response $response
* @param TokenInterface $token

View File

@ -17,14 +17,14 @@ use Symfony\Component\HttpFoundation\Request;
/**
* Handler for clearing invalidating the current session.
*
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class SessionLogoutHandler implements LogoutHandlerInterface
{
/**
* Invalidate the current session
*
*
* @param Request $request
* @param Response $response
* @param TokenInterface $token
@ -33,5 +33,5 @@ class SessionLogoutHandler implements LogoutHandlerInterface
public function logout(Request $request, Response $response, TokenInterface $token)
{
$request->getSession()->invalidate();
}
}
}

View File

@ -0,0 +1,165 @@
<?php
namespace Symfony\Component\HttpKernel\Security\RememberMe;
use Symfony\Component\Security\Authentication\RememberMe\TokenProviderInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Exception\AuthenticationException;
use Symfony\Component\Security\Exception\CookieTheftException;
use Symfony\Component\Security\Authentication\RememberMe\PersistentToken;
use Symfony\Component\Security\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Authentication\Token\RememberMeToken;
/*
* 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.
*/
/**
* Concrete implementation of the RememberMeServicesInterface which needs
* an implementation of TokenProviderInterface for providing remember-me
* capabilities.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class PersistentTokenBasedRememberMeServices extends RememberMeServices
{
protected $tokenProvider;
/**
* Sets the token provider
*
* @param TokenProviderInterface $tokenProvider
* @return void
*/
public function setTokenProvider(TokenProviderInterface $tokenProvider)
{
$this->tokenProvider = $tokenProvider;
}
/**
* {@inheritDoc}
*/
protected function processAutoLoginCookie(array $cookieParts, Request $request)
{
if (count($cookieParts) !== 2) {
throw new AuthenticationException('The cookie is invalid.');
}
list($series, $tokenValue) = $cookieParts;
$persistentToken = $this->tokenProvider->loadTokenBySeries($series);
if ($persistentToken->getTokenValue() !== $tokenValue) {
$this->tokenProvider->deleteTokenBySeries($series);
throw new CookieTheftException('This token was already used. The account is possibly compromised.');
}
if ($persistentToken->getLastUsed()->getTimestamp() + $this->options['lifetime'] < time()) {
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);
return $authenticationToken;
}
/**
* {@inheritDoc}
*/
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()
)
);
}
$response->headers->setCookie(
new Cookie(
$this->options['name'],
$this->generateCookieValue($series, $tokenValue),
time() + $this->options['lifetime'],
$this->options['path'],
$this->options['domain'],
$this->options['secure'],
$this->options['httponly']
)
);
}
/**
* {@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
*/
protected function generateRandomValue()
{
if (function_exists('openssl_random_pseudo_bytes')) {
$bytes = openssl_random_pseudo_bytes(32, $strong);
if (true === $strong && false !== $bytes) {
return base64_encode($bytes);
}
}
if (null !== $this->logger) {
$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));
}
}

View File

@ -0,0 +1,250 @@
<?php
namespace Symfony\Component\HttpKernel\Security\RememberMe;
use Symfony\Component\Security\User\AccountInterface;
use Symfony\Component\Security\Authentication\Token\RememberMeToken;
use Symfony\Component\HttpKernel\Security\Logout\LogoutHandlerInterface;
use Symfony\Component\Security\Authentication\Token\TokenInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\User\UserProviderInterface;
use Symfony\Component\Security\Authentication\AuthenticationManagerInterface;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
/*
* 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.
*/
/**
* Base class implementing the RememberMeServicesInterface
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
abstract class RememberMeServices implements RememberMeServicesInterface, LogoutHandlerInterface
{
const COOKIE_DELIMITER = ':';
protected $userProviders;
protected $options;
protected $logger;
protected $key;
protected $providerKey;
/**
* Constructor
*
* @param array $userProviders
* @param array $options
* @param LoggerInterface $logger
*/
public function __construct(array $userProviders, $key, $providerKey, array $options = array(), LoggerInterface $logger = null)
{
if (empty($key)) {
throw new \InvalidArgumentException('$key must not be empty.');
}
if (empty($providerKey)) {
throw new \InvalidArgumentException('$providerKey must not be empty.');
}
if (0 === count($userProviders)) {
throw new \InvalidArgumentException('You must provide at least one user provider.');
}
$this->userProviders = $userProviders;
$this->key = $key;
$this->providerKey = $providerKey;
$this->options = $options;
$this->logger = $logger;
}
/**
* Implementation of RememberMeServicesInterface. Detects whether a remember-me
* cookie was set, decodes it, and hands it to subclasses for further processing.
*
* @param Request $request
* @return TokenInterface
*/
public function autoLogin(Request $request)
{
if (null === $cookie = $request->cookies->get($this->options['name'])) {
return;
}
if (null !== $this->logger) {
$this->logger->debug('Remember-me cookie detected.');
}
$cookieParts = $this->decodeCookie($cookie);
$token = $this->processAutoLoginCookie($cookieParts, $request);
if (!$token instanceof TokenInterface) {
throw new \RuntimeException('processAutoLoginCookie() must return a TokenInterface implementation.');
}
if (null !== $this->logger) {
$this->logger->debug('Remember-me cookie accepted.');
}
return $token;
}
/**
* Implementation for LogoutHandlerInterface. Deletes the cookie.
*
* @param Request $request
* @param Response $response
* @param TokenInterface $token
* @return void
*/
public function logout(Request $request, Response $response, TokenInterface $token)
{
$this->cancelCookie($response);
}
/**
* Implementation for RememberMeServicesInterface. Deletes the cookie when
* an attempted authentication fails.
*
* @param Request $request
* @param Response $response
* @return void
*/
public function loginFail(Request $request, Response $response)
{
$this->cancelCookie($response);
}
/**
* Implementation for RememberMeServicesInterface. This is called when an
* authentication is successful.
*
* @param Request $request
* @param Response $response
* @param TokenInterface $token The token that resulted in a successful authentication
* @return void
*/
public 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 (!$this->isRememberMeRequested($request)) {
if (null !== $this->logger) {
$this->logger->debug('Remember-me was not requested.');
}
return;
}
if (null !== $this->logger) {
$this->logger->debug('Remember-me was requested; setting cookie.');
}
} else if (null !== $this->logger) {
$this->logger->debug('Re-newing remember-me token; setting cookie.');
}
$this->onLoginSuccess($request, $response, $token);
}
/**
* Subclasses should validate the cookie and do any additional processing
* that is required. This is called from autoLogin().
*
* @param array $cookieParts
* @param Request $request
* @return TokenInterface
*/
abstract protected function processAutoLoginCookie(array $cookieParts, Request $request);
/**
* This is called after a user has been logged in successfully, and has
* requested remember-me capabilities. The implementation usually sets a
* cookie and possibly stores a persistent record of it.
*
* @param Request $request
* @param Response $response
* @param TokenInterface $token
* @return void
*/
abstract protected function onLoginSuccess(Request $request, Response $response, TokenInterface $token);
protected function getUserProvider($class)
{
foreach ($this->userProviders as $provider) {
if ($provider->supportsClass($class)) {
return $provider;
}
}
throw new \RuntimeException(sprintf('There is no user provider that supports class "%s".', $class));
}
/**
* Decodes the raw cookie value
*
* @param string $rawCookie
* @return array
*/
protected function decodeCookie($rawCookie)
{
return explode(self::COOKIE_DELIMITER, base64_decode($rawCookie));
}
/**
* Encodes the cookie parts
*
* @param array $cookieParts
* @return string
*/
protected function encodeCookie(array $cookieParts)
{
return base64_encode(implode(self::COOKIE_DELIMITER, $cookieParts));
}
/**
* Deletes the remember-me cookie
*
* @param Response $response
* @return void
*/
protected function cancelCookie(Response $response)
{
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']);
}
/**
* Checks whether remember-me capabilities where requested
*
* @param Request $request
* @return Boolean
*/
protected function isRememberMeRequested(Request $request)
{
if (true === $this->options['always_remember_me']) {
return true;
}
$parameter = $request->request->get($this->options['remember_me_parameter']);
if ($parameter === null && null !== $this->logger) {
$this->logger->debug(sprintf('Did not send remember-me cookie (remember-me parameter "%s" was not sent).', $this->options['remember_me_parameter']));
}
return $parameter === 'true' || $parameter === 'on' || $parameter === '1' || $parameter === 'yes';
}
}

View File

@ -0,0 +1,66 @@
<?php
namespace Symfony\Component\HttpKernel\Security\RememberMe;
use Symfony\Component\Security\Authentication\Token\TokenInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
/*
* 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 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.
*
* 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.
*
* If a browser has presented an unauthorised cookie for whatever reason,
* 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.
*
* This method needs to take care of invalidating the cookie.
*/
function loginFail(Request $request, Response $response);
/**
* 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
* (such as a HTTP POST parameter) that indicates the browser has explicitly
* requested for the authentication to be remembered.
*/
function loginSuccess(Request $request, Response $response, TokenInterface $token);
}

View File

@ -0,0 +1,153 @@
<?php
namespace Symfony\Component\HttpKernel\Security\RememberMe;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Authentication\Token\RememberMeToken;
use Symfony\Component\Security\Exception\AuthenticationException;
use Symfony\Component\Security\User\AccountInterface;
/*
* 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.
*/
/**
* Concrete implementation of the RememberMeServicesInterface providing
* remember-me capabilities without requiring a TokenProvider.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class TokenBasedRememberMeServices extends RememberMeServices
{
/**
* {@inheritDoc}
*/
protected function processAutoLoginCookie(array $cookieParts, Request $request)
{
if (count($cookieParts) !== 4) {
throw new AuthenticationException('The cookie is invalid.');
}
list($class, $username, $expires, $hash) = $cookieParts;
if (false === $username = base64_decode($username, true)) {
throw new AuthenticationException('$username contains a character from outside the base64 alphabet.');
}
try {
$user = $this->getUserProvider($class)->loadUserByUsername($username);
} catch (\Exception $ex) {
if (!$ex instanceof AuthenticationException) {
$ex = new AuthenticationException($ex->getMessage(), null, $ex->getCode(), $ex);
}
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 (true !== $this->compareHashes($hash, $this->generateCookieHash($class, $username, $expires, $user->getPassword()))) {
throw new AuthenticationException('The cookie\'s hash is invalid.');
}
if ($expires < time()) {
throw new AuthenticationException('The cookie has expired.');
}
return new RememberMeToken($user, $this->providerKey, $this->key);
}
/**
* Compares two hashes using a constant-time algorithm to avoid (remote)
* timing attacks.
*
* This is the same implementation as used in the BasePasswordEncoder.
*
* @param string $hash1 The first hash
* @param string $hash2 The second hash
*
* @return Boolean true if the two hashes are the same, false otherwise
*/
protected function compareHashes($hash1, $hash2)
{
if (strlen($hash1) !== $c = strlen($hash2)) {
return false;
}
$result = 0;
for ($i = 0; $i < $c; $i++) {
$result |= ord($hash1[$i]) ^ ord($hash2[$i]);
}
return 0 === $result;
}
/**
* {@inheritDoc}
*/
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());
$response->headers->setCookie(
new Cookie(
$this->options['name'],
$value,
$expires,
$this->options['path'],
$this->options['domain'],
$this->options['secure'],
$this->options['httponly']
)
);
}
/**
* Generates the cookie value
*
* @param strign $class
* @param string $username The username
* @param integer $expires The unixtime when the cookie expires
* @param string $password The encoded password
* @throws \RuntimeException if username contains invalid chars
* @return string
*/
protected function generateCookieValue($class, $username, $expires, $password)
{
return $this->encodeCookie(array(
$class,
base64_encode($username),
$expires,
$this->generateCookieHash($class, $username, $expires, $password)
));
}
/**
* Generates a hash for the cookie to ensure it is not being tempered with
*
* @param string $class
* @param string $username The username
* @param integer $expires The unixtime when the cookie expires
* @param string $password The encoded password
* @throws \RuntimeException when the private key is empty
* @return string
*/
protected function generateCookieHash($class, $username, $expires, $password)
{
return hash('sha256', $class.$username.$expires.$password.$this->key);
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace Symfony\Component\HttpKernel\Security\Session;
use Symfony\Component\Security\Authentication\Token\TokenInterface;
use Symfony\Component\HttpFoundation\Request;
class SessionAuthenticationStrategy implements SessionAuthenticationStrategyInterface
{
const NONE = 'none';
const MIGRATE = 'migrate';
const INVALIDATE = 'invalidate';
protected $strategy;
public function __construct($strategy)
{
$this->strategy = $strategy;
}
public function onAuthentication(Request $request, TokenInterface $token)
{
switch ($this->strategy) {
case self::NONE:
return;
case self::MIGRATE:
$request->getSession()->migrate();
break;
case self::INVALIDATE:
$request->getSession()->invalidate();
default:
throw new \RuntimeException(sprintf('Invalid session authentication strategy "%s"', $this->strategy));
}
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace Symfony\Component\HttpKernel\Security\Session;
use Symfony\Component\Security\Authentication\Token\TokenInterface;
use Symfony\Component\HttpFoundation\Request;
interface SessionAuthenticationStrategyInterface
{
function onAuthentication(Request $request, TokenInterface $token);
}

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\Security\Acl\Domain;
use Symfony\Component\Security\Authentication\Token\AnonymousToken;
use Symfony\Component\Security\User\AccountInterface;
use Symfony\Component\Security\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Acl\Model\SecurityIdentityRetrievalStrategyInterface;
@ -49,9 +51,12 @@ class SecurityIdentityRetrievalStrategy implements SecurityIdentityRetrievalStra
$sids = array();
// add user security identity
$user = $token->getUser();
if ($user instanceof AccountInterface) {
$sids[] = UserSecurityIdentity::fromAccount($user);
if (!$token instanceof AnonymousToken) {
try {
$sids[] = UserSecurityIdentity::fromToken($token);
} catch (\InvalidArgumentException $invalid) {
// ignore, user has no user security identity
}
}
// add all reachable roles

View File

@ -11,6 +11,7 @@
namespace Symfony\Component\Security\Acl\Domain;
use Symfony\Component\Security\Authentication\Token\TokenInterface;
use Symfony\Component\Security\User\AccountInterface;
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
@ -51,7 +52,24 @@ class UserSecurityIdentity implements SecurityIdentityInterface
*/
public static function fromAccount(AccountInterface $user)
{
return new self((string) $user, get_class($user));
return new self($user->getUsername(), get_class($user));
}
/**
* Creates a user security identity from a TokenInterface
*
* @param TokenInterface $token
* @return UserSecurityIdentity
*/
public static function fromToken(TokenInterface $token)
{
$user = $token->getUser();
if ($user instanceof AccountInterface) {
return self::fromAccount($user);
}
return new self((string) $user, is_object($user)? get_class($user) : get_class($token));
}
/**

View File

@ -11,6 +11,7 @@
namespace Symfony\Component\Security\Authentication\Provider;
use Symfony\Component\Security\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Encoder\EncoderFactoryInterface;
use Symfony\Component\Security\User\UserProviderInterface;
use Symfony\Component\Security\User\AccountCheckerInterface;
@ -38,9 +39,9 @@ class DaoAuthenticationProvider extends UserAuthenticationProvider
* @param AccountCheckerInterface $accountChecker An AccountCheckerInterface instance
* @param EncoderFactoryInterface $encoderFactory A EncoderFactoryInterface instance
*/
public function __construct(UserProviderInterface $userProvider, AccountCheckerInterface $accountChecker, EncoderFactoryInterface $encoderFactory, $hideUserNotFoundExceptions = true)
public function __construct(UserProviderInterface $userProvider, AccountCheckerInterface $accountChecker, $providerKey, EncoderFactoryInterface $encoderFactory, $hideUserNotFoundExceptions = true)
{
parent::__construct($accountChecker, $hideUserNotFoundExceptions);
parent::__construct($accountChecker, $providerKey, $hideUserNotFoundExceptions);
$this->encoderFactory = $encoderFactory;
$this->userProvider = $userProvider;

View File

@ -11,6 +11,7 @@
namespace Symfony\Component\Security\Authentication\Provider;
use Symfony\Component\Security\User\AccountInterface;
use Symfony\Component\Security\User\UserProviderInterface;
use Symfony\Component\Security\User\AccountCheckerInterface;
use Symfony\Component\Security\Exception\BadCredentialsException;
@ -31,6 +32,7 @@ class PreAuthenticatedAuthenticationProvider implements AuthenticationProviderIn
{
protected $userProvider;
protected $accountChecker;
protected $providerKey;
/**
* Constructor.
@ -38,10 +40,11 @@ class PreAuthenticatedAuthenticationProvider implements AuthenticationProviderIn
* @param UserProviderInterface $userProvider A UserProviderInterface instance
* @param AccountCheckerInterface $accountChecker An AccountCheckerInterface instance
*/
public function __construct(UserProviderInterface $userProvider, AccountCheckerInterface $accountChecker)
public function __construct(UserProviderInterface $userProvider, AccountCheckerInterface $accountChecker, $providerKey)
{
$this->userProvider = $userProvider;
$this->accountChecker = $accountChecker;
$this->providerKey = $providerKey;
}
/**
@ -73,6 +76,6 @@ class PreAuthenticatedAuthenticationProvider implements AuthenticationProviderIn
*/
public function supports(TokenInterface $token)
{
return $token instanceof PreAuthenticatedToken;
return $token instanceof PreAuthenticatedToken && $this->providerKey === $token->getProviderKey();
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace Symfony\Component\Security\Authentication\Provider;
use Symfony\Component\Security\User\AccountCheckerInterface;
use Symfony\Component\Security\User\AccountInterface;
use Symfony\Component\Security\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Authentication\Token\RememberMeToken;
use Symfony\Component\Security\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;
}
}

View File

@ -29,6 +29,7 @@ abstract class UserAuthenticationProvider implements AuthenticationProviderInter
{
protected $hideUserNotFoundExceptions;
protected $accountChecker;
protected $providerKey;
/**
* Constructor.
@ -36,9 +37,14 @@ abstract class UserAuthenticationProvider implements AuthenticationProviderInter
* @param AccountCheckerInterface $accountChecker An AccountCheckerInterface interface
* @param Boolean $hideUserNotFoundExceptions Whether to hide user not found exception or not
*/
public function __construct(AccountCheckerInterface $accountChecker, $hideUserNotFoundExceptions = true)
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;
}
@ -64,7 +70,7 @@ abstract class UserAuthenticationProvider implements AuthenticationProviderInter
$this->checkAuthentication($user, $token);
$this->accountChecker->checkPostAuth($user);
return new UsernamePasswordToken($user, $token->getCredentials(), $user->getRoles());
return new UsernamePasswordToken($user, $token->getCredentials(), $this->providerKey, $user->getRoles());
} catch (UsernameNotFoundException $notFound) {
if ($this->hideUserNotFoundExceptions) {
throw new BadCredentialsException('Bad credentials', 0, $notFound);
@ -79,7 +85,7 @@ abstract class UserAuthenticationProvider implements AuthenticationProviderInter
*/
public function supports(TokenInterface $token)
{
return $token instanceof UsernamePasswordToken;
return $token instanceof UsernamePasswordToken && $this->providerKey === $token->getProviderKey();
}
/**

View File

@ -0,0 +1,50 @@
<?php
namespace Symfony\Component\Security\Authentication\RememberMe;
use Symfony\Component\Security\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;
}
}

View File

@ -0,0 +1,107 @@
<?php
namespace Symfony\Component\Security\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;
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace Symfony\Component\Security\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();
}

View File

@ -0,0 +1,51 @@
<?php
namespace Symfony\Component\Security\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);
}

View File

@ -18,10 +18,12 @@ namespace Symfony\Component\Security\Authentication\Token;
*/
class PreAuthenticatedToken extends Token
{
protected $providerKey;
/**
* Constructor.
*/
public function __construct($user, $credentials, array $roles = null)
public function __construct($user, $credentials, $providerKey, array $roles = null)
{
parent::__construct(null === $roles ? array() : $roles);
if (null !== $roles) {
@ -30,6 +32,12 @@ class PreAuthenticatedToken extends Token
$this->user = $user;
$this->credentials = $credentials;
$this->providerKey = $providerKey;
}
public function getProviderKey()
{
return $this->providerKey;
}
/**

View File

@ -22,6 +22,7 @@ use Symfony\Component\Security\User\AccountInterface;
class RememberMeToken extends Token
{
protected $key;
protected $providerKey;
/**
* The persistent token which resulted in this authentication token.
@ -36,30 +37,39 @@ class RememberMeToken extends Token
* @param string $username
* @param string $key
*/
public function __construct(AccountInterface $user, $key) {
public function __construct(AccountInterface $user, $providerKey, $key) {
parent::__construct($user->getRoles());
if (0 === strlen($key)) {
throw new \InvalidArgumentException('$key cannot be empty.');
if (empty($key)) {
throw new \InvalidArgumentException('$key must not be empty.');
}
if (empty($providerKey)) {
throw new \InvalidArgumentException('$providerKey must not be empty.');
}
$this->user = $user;
$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 setPersistentToken(PersistentTokenInterface $persistentToken)
{
$this->persistentToken = $persistentToken;
}
public function getPersistentToken()
{
return $this->persistentToken;
}
}
public function setPersistentToken(PersistentTokenInterface $persistentToken)
{
$this->persistentToken = $persistentToken;
}
}

View File

@ -18,19 +18,30 @@ namespace Symfony\Component\Security\Authentication\Token;
*/
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, array $roles = array())
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}
*/

View File

@ -0,0 +1,22 @@
<?php
namespace Symfony\Component\Security\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
{
}

View File

@ -0,0 +1,20 @@
<?php
namespace Symfony\Component\Security\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
{
}

View File

@ -11,8 +11,9 @@
namespace Symfony\Component\Security;
use Symfony\Component\Security\Authorization\AccessDecisionManagerInterface;
use Symfony\Component\Security\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Authorization\AccessDecisionManager;
use Symfony\Component\Security\Acl\Voter\FieldVote;
/**
@ -30,15 +31,19 @@ class SecurityContext
protected $token;
protected $accessDecisionManager;
protected $authenticationManager;
protected $alwaysAuthenticate;
/**
* Constructor.
*
* @param AccessDecisionManager|null $accessDecisionManager An AccessDecisionManager instance
* @param AccessDecisionManagerInterface|null $accessDecisionManager An AccessDecisionManager instance
*/
public function __construct(AccessDecisionManager $accessDecisionManager = null)
public function __construct(AuthenticationManagerInterface $authenticationManager, AccessDecisionManagerInterface $accessDecisionManager = null, $alwaysAuthenticate = false)
{
$this->authenticationManager = $authenticationManager;
$this->accessDecisionManager = $accessDecisionManager;
$this->alwaysAuthenticate = $alwaysAuthenticate;
}
public function getUser()
@ -60,6 +65,10 @@ class SecurityContext
$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);
}

View File

@ -87,4 +87,12 @@ class InMemoryUserProvider implements UserProviderInterface
return $this->loadUserByUsername((string) $account);
}
/**
* {@inheritDoc}
*/
public function supportsClass($class)
{
return $class === 'Symfony\Component\Security\User\User';
}
}

View File

@ -119,7 +119,6 @@ class User implements AdvancedAccountInterface
*/
public function eraseCredentials()
{
$this->password = null;
}
/**

View File

@ -36,13 +36,22 @@ interface UserProviderInterface
* 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
* 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 $user
* @param AccountInterface $account
*
* @return AccountInterface
*/
function loadUserByAccount(AccountInterface $user);
function loadUserByAccount(AccountInterface $account);
/**
* Whether this provider supports the given user class
*
* @param string $class
*
* @return Boolean
*/
function supportsClass($class);
}

View File

@ -0,0 +1,396 @@
<?php
namespace Symfony\Tests\Component\HttpKernel\Security\Firewall;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Exception\CookieTheftException;
use Symfony\Component\Security\Exception\AuthenticationException;
use Symfony\Component\HttpKernel\Security\Firewall\RememberMeListener;
use Symfony\Component\HttpFoundation\Request;
class RememberMeListenerTest extends \PHPUnit_Framework_TestCase
{
public function testRegister()
{
list($listener,,,,) = $this->getListener();
$dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcher');
$dispatcher
->expects($this->at(0))
->method('connect')
->with($this->equalTo('core.security'))
;
$dispatcher
->expects($this->at(1))
->method('connect')
->with($this->equalTo('core.response'))
;
$listener->register($dispatcher);
}
public function testCheckCookiesDoesNotTryToPopulateNonEmptySecurityContext()
{
list($listener, $context, $service,,) = $this->getListener();
$context
->expects($this->once())
->method('getToken')
->will($this->returnValue($this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface')))
;
$context
->expects($this->never())
->method('setToken')
;
$this->assertNull($this->getLastState($listener));
$this->assertNull($listener->checkCookies($this->getEvent()));
$this->assertNull($this->getLastState($listener));
}
public function testCheckCookiesDoesNothingWhenNoCookieIsSet()
{
list($listener, $context, $service,,) = $this->getListener();
$context
->expects($this->once())
->method('getToken')
->will($this->returnValue(null))
;
$service
->expects($this->once())
->method('autoLogin')
->will($this->returnValue(null))
;
$event = $this->getEvent();
$event
->expects($this->once())
->method('get')
->with('request')
->will($this->returnValue(new Request()))
;
$this->assertNull($this->getLastState($listener));
$this->assertNull($listener->checkCookies($event));
$this->assertNull($this->getLastState($listener));
}
public function testCheckCookiesIgnoresAuthenticationExceptionThrownByTheRememberMeServicesImplementation()
{
list($listener, $context, $service,,) = $this->getListener();
$context
->expects($this->once())
->method('getToken')
->will($this->returnValue(null))
;
$exception = new AuthenticationException('cookie invalid.');
$service
->expects($this->once())
->method('autoLogin')
->will($this->throwException($exception))
;
$event = $this->getEvent();
$event
->expects($this->once())
->method('get')
->with('request')
->will($this->returnValue(new Request()))
;
$this->assertNull($this->getLastState($listener));
$this->assertNull($listener->checkCookies($event));
$this->assertSame($exception, $this->getLastState($listener));
}
public function testCheckCookiesThrowsCookieTheftExceptionIfThrownByTheRememberMeServicesImplementation()
{
list($listener, $context, $service,,) = $this->getListener();
$context
->expects($this->once())
->method('getToken')
->will($this->returnValue(null))
;
$exception = new CookieTheftException('cookie was stolen.');
$service
->expects($this->once())
->method('autoLogin')
->will($this->throwException($exception))
;
$event = $this->getEvent();
$event
->expects($this->once())
->method('get')
->with('request')
->will($this->returnValue(new Request()))
;
try {
$listener->checkCookies($event);
}
catch (CookieTheftException $theft) {
$this->assertSame($theft, $this->getLastState($listener));
return;
}
$this->fail('Expected CookieTheftException was not thrown.');
}
public function testCheckCookiesAuthenticationManagerDoesNotChangeListenerStateWhenTokenIsNotSupported()
{
list($listener, $context, $service, $manager,) = $this->getListener();
$context
->expects($this->once())
->method('getToken')
->will($this->returnValue(null))
;
$service
->expects($this->once())
->method('autoLogin')
->will($this->returnValue($this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface')))
;
$event = $this->getEvent();
$event
->expects($this->once())
->method('get')
->with('request')
->will($this->returnValue(new Request()))
;
$this->assertNull($this->getLastState($listener));
$this->assertNull($listener->checkCookies($event));
$this->assertNull($this->getLastState($listener));
}
public function testCheckCookiesIgnoresAuthenticationExceptionThrownByAuthenticationManagerImplementation()
{
list($listener, $context, $service, $manager,) = $this->getListener();
$context
->expects($this->once())
->method('getToken')
->will($this->returnValue(null))
;
$service
->expects($this->once())
->method('autoLogin')
->will($this->returnValue($this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface')))
;
$exception = new AuthenticationException('Authentication failed.');
$manager
->expects($this->once())
->method('authenticate')
->will($this->throwException($exception))
;
$event = $this->getEvent();
$event
->expects($this->once())
->method('get')
->with('request')
->will($this->returnValue(new Request()))
;
$this->assertNull($this->getLastState($listener));
$this->assertNull($listener->checkCookies($event));
$this->assertSame($exception, $this->getLastState($listener));
}
public function testCheckCookies()
{
list($listener, $context, $service, $manager,) = $this->getListener();
$context
->expects($this->once())
->method('getToken')
->will($this->returnValue(null))
;
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface');
$service
->expects($this->once())
->method('autoLogin')
->will($this->returnValue($token))
;
$context
->expects($this->once())
->method('setToken')
->with($this->equalTo($token))
;
$manager
->expects($this->once())
->method('authenticate')
->will($this->returnValue($token))
;
$event = $this->getEvent();
$event
->expects($this->once())
->method('get')
->with('request')
->will($this->returnValue(new Request()))
;
$this->assertNull($this->getLastState($listener));
$this->assertNull($listener->checkCookies($event));
$this->assertSame($token, $this->getLastState($listener));
}
public function testUpdateCookiesIgnoresAnythingButMasterRequests()
{
list($listener,,,,) = $this->getListener();
$event = $this->getEvent();
$event
->expects($this->once())
->method('get')
->with($this->equalTo('request_type'))
->will($this->returnValue('foo'))
;
$response = $this->getMock('Symfony\Component\HttpFoundation\Response');
$this->assertSame($response, $listener->updateCookies($event, $response));
}
public function testUpdateCookiesCallsLoginSuccessOnRememberMeServicesImplementationWhenAuthenticationWasSuccessful()
{
list($listener,, $service,,) = $this->getListener();
$request = new Request();
$response = new Response();
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface');
$this->setLastState($listener, $token);
$event = $this->getEvent();
$event
->expects($this->at(0))
->method('get')
->with('request_type')
->will($this->returnValue(HttpKernelInterface::MASTER_REQUEST))
;
$event
->expects($this->at(1))
->method('get')
->with('request')
->will($this->returnValue($request))
;
$service
->expects($this->once())
->method('loginSuccess')
->with($this->equalTo($request), $this->equalTo($response), $this->equalTo($token))
->will($this->returnValue(null))
;
$this->assertSame($response, $listener->updateCookies($event, $response));
}
public function testUpdateCookiesCallsLoginFailOnRememberMeServicesImplementationWhenAuthenticationWasNotSuccessful()
{
list($listener,, $service,,) = $this->getListener();
$request = new Request();
$response = new Response();
$exception = new AuthenticationException('foo');
$this->setLastState($listener, $exception);
$event = $this->getEvent();
$event
->expects($this->at(0))
->method('get')
->with('request_type')
->will($this->returnValue(HttpKernelInterface::MASTER_REQUEST))
;
$event
->expects($this->at(1))
->method('get')
->with('request')
->will($this->returnValue($request))
;
$service
->expects($this->once())
->method('loginFail')
->with($this->equalTo($request), $this->equalTo($response))
->will($this->returnValue(null))
;
$this->assertSame($response, $listener->updateCookies($event, $response));
}
protected function setLastState($listener, $state)
{
$r = new \ReflectionObject($listener);
$p = $r->getProperty('lastState');
$p->setAccessible(true);
$p->setValue($listener, $state);
}
protected function getLastState($listener)
{
$r = new \ReflectionObject($listener);
$p = $r->getProperty('lastState');
$p->setAccessible(true);
return $p->getValue($listener);
}
protected function getEvent()
{
return $this->getMock('Symfony\Component\EventDispatcher\Event', array(), array(), '', false);
}
protected function getListener()
{
$listener = new RememberMeListener(
$context = $this->getContext(),
$service = $this->getService(),
$manager = $this->getManager(),
$logger = $this->getLogger()
);
return array($listener, $context, $service, $manager, $logger);
}
protected function getLogger()
{
return $this->getMock('Symfony\Component\HttpKernel\Log\LoggerInterface');
}
protected function getManager()
{
return $this->getMock('Symfony\Component\Security\Authentication\AuthenticationManagerInterface');
}
protected function getService()
{
return $this->getMock('Symfony\Component\HttpKernel\Security\RememberMe\RememberMeServicesInterface');
}
protected function getContext()
{
return $this->getMockBuilder('Symfony\Component\Security\SecurityContext')
->disableOriginalConstructor()
->getMock();
}
}

View File

@ -49,4 +49,4 @@ class CookieClearingLogoutHandlerTest extends \PHPUnit_Framework_TestCase
$this->assertStringStartsWith('foo2', $cookie->getName());
$this->assertTrue($cookie->isCleared());
}
}
}

View File

@ -19,22 +19,22 @@ class SessionLogoutHandlerTest extends \PHPUnit_Framework_TestCase
public function testLogout()
{
$handler = new SessionLogoutHandler();
$request = $this->getMock('Symfony\Component\HttpFoundation\Request');
$response = new Response();
$session = $this->getMock('Symfony\Component\HttpFoundation\Session', array(), array(), '', false);
$request
->expects($this->once())
->method('getSession')
->will($this->returnValue($session))
;
$session
->expects($this->once())
->method('invalidate')
;
$handler->logout($request, $response, $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface'));
}
}

View File

@ -0,0 +1,403 @@
<?php
namespace Symfony\Tests\Component\HttpKernel\Security\RememberMe;
use Symfony\Component\Security\Authentication\Token\RememberMeToken;
use Symfony\Component\HttpFoundation\HeaderBag;
use Symfony\Component\Security\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Authentication\RememberMe\PersistentToken;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Security\RememberMe\PersistentTokenBasedRememberMeServices;
use Symfony\Component\Security\Exception\TokenNotFoundException;
use Symfony\Component\Security\Exception\CookieTheftException;
class PersistentTokenBasedRememberMeServicesTest extends \PHPUnit_Framework_TestCase
{
public function testAutoLoginReturnsNullWhenNoCookie()
{
$service = $this->getService(null, array('name' => 'foo'));
$this->assertNull($service->autoLogin(new Request()));
}
/**
* @expectedException Symfony\Component\Security\Exception\AuthenticationException
* @expectedMessage The cookie is invalid.
*/
public function testAutoLoginThrowsExceptionOnInvalidCookie()
{
$service = $this->getService(null, array('name' => 'foo', 'always_remember_me' => false, 'remember_me_parameter' => 'foo'));
$request = new Request;
$request->request->set('foo', 'true');
$request->cookies->set('foo', 'foo');
$service->autoLogin($request);
}
/**
* @expectedException Symfony\Component\Security\Exception\TokenNotFoundException
*/
public function testAutoLoginThrowsExceptionOnNonExistentToken()
{
$service = $this->getService(null, array('name' => 'foo', 'always_remember_me' => false, 'remember_me_parameter' => 'foo'));
$request = new Request;
$request->request->set('foo', 'true');
$request->cookies->set('foo', $this->encodeCookie(array(
$series = 'fooseries',
$tokenValue = 'foovalue',
)));
$tokenProvider = $this->getMock('Symfony\Component\Security\Authentication\RememberMe\TokenProviderInterface');
$tokenProvider
->expects($this->once())
->method('loadTokenBySeries')
->will($this->throwException(new TokenNotFoundException('Token not found.')))
;
$service->setTokenProvider($tokenProvider);
$service->autoLogin($request);
}
/**
* @expectedException Symfony\Component\Security\Exception\UsernameNotFoundException
*/
public function testAutoLoginThrowsExceptionOnNonExistentUser()
{
$userProvider = $this->getProvider();
$service = $this->getService($userProvider, array('name' => 'foo', 'always_remember_me' => true, 'lifetime' => 3600));
$request = new Request;
$request->cookies->set('foo', $this->encodeCookie(array('fooseries', 'foovalue')));
$tokenProvider = $this->getMock('Symfony\Component\Security\Authentication\RememberMe\TokenProviderInterface');
$tokenProvider
->expects($this->once())
->method('loadTokenBySeries')
->will($this->returnValue(new PersistentToken('fooclass', 'fooname', 'fooseries', 'foovalue', new \DateTime())))
;
$service->setTokenProvider($tokenProvider);
$userProvider
->expects($this->once())
->method('loadUserByUsername')
->will($this->throwException(new UsernameNotFoundException('user not found')))
;
$service->autoLogin($request);
}
public function testAutoLoginThrowsExceptionOnStolenCookieAndRemovesItFromThePersistentBackend()
{
$userProvider = $this->getProvider();
$service = $this->getService($userProvider, array('name' => 'foo', 'always_remember_me' => true));
$request = new Request;
$request->cookies->set('foo', $this->encodeCookie(array('fooseries', 'foovalue')));
$tokenProvider = $this->getMock('Symfony\Component\Security\Authentication\RememberMe\TokenProviderInterface');
$service->setTokenProvider($tokenProvider);
$tokenProvider
->expects($this->once())
->method('loadTokenBySeries')
->will($this->returnValue(new PersistentToken('fooclass', 'foouser', 'fooseries', 'anotherFooValue', new \DateTime())))
;
$tokenProvider
->expects($this->once())
->method('deleteTokenBySeries')
->with($this->equalTo('fooseries'))
->will($this->returnValue(null))
;
try {
$service->autoLogin($request);
} catch (CookieTheftException $theft) {
return;
}
$this->fail('Expected CookieTheftException was not thrown.');
}
/**
* @expectedException Symfony\Component\Security\Exception\AuthenticationException
* @expectedMessage The cookie has expired.
*/
public function testAutoLoginDoesNotAcceptAnExpiredCookie()
{
$service = $this->getService(null, array('name' => 'foo', 'always_remember_me' => true, 'lifetime' => 3600));
$request = new Request;
$request->cookies->set('foo', $this->encodeCookie(array('fooseries', 'foovalue')));
$tokenProvider = $this->getMock('Symfony\Component\Security\Authentication\RememberMe\TokenProviderInterface');
$tokenProvider
->expects($this->once())
->method('loadTokenBySeries')
->with($this->equalTo('fooseries'))
->will($this->returnValue(new PersistentToken('fooclass', 'username', 'fooseries', 'newFooValue', new \DateTime('yesterday'))))
;
$service->setTokenProvider($tokenProvider);
$service->autoLogin($request);
}
public function testAutoLogin()
{
$user = $this->getMock('Symfony\Component\Security\User\AccountInterface');
$user
->expects($this->once())
->method('getRoles')
->will($this->returnValue(array('ROLE_FOO')))
;
$userProvider = $this->getProvider();
$userProvider
->expects($this->once())
->method('loadUserByUsername')
->with($this->equalTo('foouser'))
->will($this->returnValue($user))
;
$service = $this->getService($userProvider, array('name' => 'foo', 'always_remember_me' => true, 'lifetime' => 3600));
$request = new Request;
$request->cookies->set('foo', $this->encodeCookie(array('fooseries', 'foovalue')));
$tokenProvider = $this->getMock('Symfony\Component\Security\Authentication\RememberMe\TokenProviderInterface');
$tokenProvider
->expects($this->once())
->method('loadTokenBySeries')
->with($this->equalTo('fooseries'))
->will($this->returnValue(new PersistentToken('fooclass', 'foouser', 'fooseries', 'foovalue', new \DateTime())))
;
$service->setTokenProvider($tokenProvider);
$returnedToken = $service->autoLogin($request);
$this->assertInstanceOf('Symfony\Component\Security\Authentication\Token\RememberMeToken', $returnedToken);
$this->assertInstanceOf('Symfony\Component\Security\Authentication\RememberMe\PersistentTokenInterface', $returnedToken->getPersistentToken());
$this->assertSame($user, $returnedToken->getUser());
$this->assertEquals('fookey', $returnedToken->getKey());
}
public function testLogout()
{
$service = $this->getService(null, array('name' => 'foo', 'path' => '/foo', 'domain' => 'foodomain.foo'));
$request = new Request();
$request->cookies->set('foo', $this->encodeCookie(array('fooseries', 'foovalue')));
$response = new Response();
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface');
$tokenProvider = $this->getMock('Symfony\Component\Security\Authentication\RememberMe\TokenProviderInterface');
$tokenProvider
->expects($this->once())
->method('deleteTokenBySeries')
->with($this->equalTo('fooseries'))
->will($this->returnValue(null))
;
$service->setTokenProvider($tokenProvider);
$this->assertFalse($response->headers->hasCookie('foo'));
$service->logout($request, $response, $token);
$cookie = $response->headers->getCookie('foo');
$this->assertTrue($cookie->isCleared());
$this->assertEquals('/foo', $cookie->getPath());
$this->assertEquals('foodomain.foo', $cookie->getDomain());
}
public function testLogoutSimplyIgnoresNonSetRequestCookie()
{
$service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null));
$request = new Request;
$response = new Response;
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface');
$tokenProvider = $this->getMock('Symfony\Component\Security\Authentication\RememberMe\TokenProviderInterface');
$tokenProvider
->expects($this->never())
->method('deleteTokenBySeries')
;
$service->setTokenProvider($tokenProvider);
$this->assertFalse($response->headers->hasCookie('foo'));
$service->logout($request, $response, $token);
$cookie = $response->headers->getCookie('foo');
$this->assertTrue($cookie->isCleared());
$this->assertNull($cookie->getPath());
$this->assertNull($cookie->getDomain());
}
public function testLogoutSimplyIgnoresInvalidCookie()
{
$service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null));
$request = new Request;
$request->cookies->set('foo', 'somefoovalue');
$response = new Response;
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface');
$tokenProvider = $this->getMock('Symfony\Component\Security\Authentication\RememberMe\TokenProviderInterface');
$tokenProvider
->expects($this->never())
->method('deleteTokenBySeries')
;
$service->setTokenProvider($tokenProvider);
$this->assertFalse($response->headers->hasCookie('foo'));
$service->logout($request, $response, $token);
$this->assertTrue($response->headers->getCookie('foo')->isCleared());
}
public function testLoginFail()
{
$service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null));
$request = new Request();
$response = new Response();
$this->assertFalse($response->headers->hasCookie('foo'));
$service->loginFail($request, $response);
$this->assertTrue($response->headers->getCookie('foo')->isCleared());
}
public function testLoginSuccessRenewsRememberMeTokenWhenUsedForLogin()
{
$service = $this->getService(null, array('name' => 'foo', 'domain' => 'myfoodomain.foo', 'path' => '/foo/path', 'secure' => true, 'httponly' => true, 'lifetime' => 3600));
$request = new Request;
$response = new Response;
$user = $this->getMock('Symfony\Component\Security\User\AccountInterface');
$user
->expects($this->once())
->method('getRoles')
->will($this->returnValue(array('ROLE_FOO')))
;
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\RememberMeToken', array(), array($user, 'fookey', 'fookey'));
$token
->expects($this->once())
->method('getPersistentToken')
->will($this->returnValue(new PersistentToken('fooclass', 'foouser', 'fooseries', 'foovalue', new \DateTime())))
;
$tokenProvider = $this->getMock('Symfony\Component\Security\Authentication\RememberMe\TokenProviderInterface');
$tokenProvider
->expects($this->once())
->method('updateToken')
->with($this->equalTo('fooseries'))
->will($this->returnValue(null))
;
$service->setTokenProvider($tokenProvider);
$this->assertFalse($response->headers->hasCookie('foo'));
$service->loginSuccess($request, $response, $token);
$cookie = $response->headers->getCookie('foo');
$this->assertFalse($cookie->isCleared());
$this->assertTrue($cookie->isSecure());
$this->assertTrue($cookie->isHttponly());
$this->assertTrue($cookie->getExpire() > time() + 3590 && $cookie->getExpire() < time() + 3610);
$this->assertEquals('myfoodomain.foo', $cookie->getDomain());
$this->assertEquals('/foo/path', $cookie->getPath());
}
/**
* @expectedException RuntimeException
* @expectedMessage RememberMeToken must contain a PersistentTokenInterface implementation when used as login.
*/
public function testLoginSuccessThrowsExceptionWhenRememberMeTokenDoesNotContainPersistentTokenImplementation()
{
$service = $this->getService(null, array('always_remember_me' => true, 'name' => 'foo'));
$request = new Request;
$response = new Response;
$user = $this->getMock('Symfony\Component\Security\User\AccountInterface');
$user
->expects($this->once())
->method('getRoles')
->will($this->returnValue(array('ROLE_FOO')))
;
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\RememberMeToken', array(), array($user, 'fookey', 'fookey'));
$token
->expects($this->once())
->method('getPersistentToken')
->will($this->returnValue(null))
;
$service->loginSuccess($request, $response, $token);
}
public function testLoginSuccessSetsCookieWhenLoggedInWithNonRememberMeTokenInterfaceImplementation()
{
$service = $this->getService(null, array('name' => 'foo', 'domain' => 'myfoodomain.foo', 'path' => '/foo/path', 'secure' => true, 'httponly' => true, 'lifetime' => 3600, 'always_remember_me' => true));
$request = new Request;
$response = new Response;
$account = $this->getMock('Symfony\Component\Security\User\AccountInterface');
$account
->expects($this->once())
->method('getUsername')
->will($this->returnValue('foo'))
;
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface');
$token
->expects($this->any())
->method('getUser')
->will($this->returnValue($account))
;
$tokenProvider = $this->getMock('Symfony\Component\Security\Authentication\RememberMe\TokenProviderInterface');
$tokenProvider
->expects($this->once())
->method('createNewToken')
;
$service->setTokenProvider($tokenProvider);
$this->assertFalse($response->headers->hasCookie('foo'));
$service->loginSuccess($request, $response, $token);
$cookie = $response->headers->getCookie('foo');
$this->assertFalse($cookie->isCleared());
$this->assertTrue($cookie->isSecure());
$this->assertTrue($cookie->isHttponly());
$this->assertTrue($cookie->getExpire() > time() + 3590 && $cookie->getExpire() < time() + 3610);
$this->assertEquals('myfoodomain.foo', $cookie->getDomain());
$this->assertEquals('/foo/path', $cookie->getPath());
}
protected function encodeCookie(array $parts)
{
$service = $this->getService();
$r = new \ReflectionMethod($service, 'encodeCookie');
$r->setAccessible(true);
return $r->invoke($service, $parts);
}
protected function getService($userProvider = null, $options = array(), $logger = null)
{
if (null === $userProvider) {
$userProvider = $this->getProvider();
}
return new PersistentTokenBasedRememberMeServices(array($userProvider), 'fookey', 'fookey', $options, $logger);
}
protected function getProvider()
{
$provider = $this->getMock('Symfony\Component\Security\User\UserProviderInterface');
$provider
->expects($this->any())
->method('supportsClass')
->will($this->returnValue(true))
;
return $provider;
}
}

View File

@ -0,0 +1,231 @@
<?php
namespace Symfony\Tests\Component\HttpKernel\Security\RememberMe;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class RememberMeServicesTest extends \PHPUnit_Framework_TestCase
{
public function testAutoLoginReturnsNullWhenNoCookie()
{
$service = $this->getService(null, array('name' => 'foo'));
$this->assertNull($service->autoLogin(new Request()));
}
/**
* @expectedException \RuntimeException
* @expectedMessage processAutoLoginCookie() must return a TokenInterface implementation.
*/
public function testAutoLoginThrowsExceptionWhenImplementationDoesNotReturnTokenInterface()
{
$service = $this->getService(null, array('name' => 'foo'));
$request = new Request;
$request->cookies->set('foo', 'foo');
$service
->expects($this->once())
->method('processAutoLoginCookie')
->will($this->returnValue(null))
;
$service->autoLogin($request);
}
public function testAutoLogin()
{
$service = $this->getService(null, array('name' => 'foo'));
$request = new Request();
$request->cookies->set('foo', 'foo');
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface');
$service
->expects($this->once())
->method('processAutoLoginCookie')
->will($this->returnValue($token))
;
$returnedToken = $service->autoLogin($request);
$this->assertSame($token, $returnedToken);
}
public function testLogout()
{
$service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null));
$request = new Request();
$response = new Response();
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface');
$this->assertFalse($response->headers->hasCookie('foo'));
$service->logout($request, $response, $token);
$this->assertTrue($response->headers->getCookie('foo')->isCleared());
}
public function testLoginFail()
{
$service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null));
$request = new Request();
$response = new Response();
$this->assertFalse($response->headers->hasCookie('foo'));
$service->loginFail($request, $response);
$this->assertTrue($response->headers->getCookie('foo')->isCleared());
}
public function testLoginSuccessIsNotProcessedWhenTokenDoesNotContainAccountInterfaceImplementation()
{
$service = $this->getService(null, array('name' => 'foo', 'always_remember_me' => true));
$request = new Request;
$response = new Response;
$account = $this->getMock('Symfony\Component\Security\User\AccountInterface');
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface');
$token
->expects($this->once())
->method('getUser')
->will($this->returnValue('foo'))
;
$service
->expects($this->never())
->method('onLoginSuccess')
;
$this->assertFalse($request->request->has('foo'));
$service->loginSuccess($request, $response, $token);
}
public function testLoginSuccessIsNotProcessedWhenRememberMeIsNotRequested()
{
$service = $this->getService(null, array('name' => 'foo', 'always_remember_me' => false, 'remember_me_parameter' => 'foo'));
$request = new Request;
$response = new Response;
$account = $this->getMock('Symfony\Component\Security\User\AccountInterface');
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface');
$token
->expects($this->once())
->method('getUser')
->will($this->returnValue($account))
;
$service
->expects($this->never())
->method('onLoginSuccess')
->will($this->returnValue(null))
;
$this->assertFalse($request->request->has('foo'));
$service->loginSuccess($request, $response, $token);
}
public function testLoginSuccessWhenRememberMeAlwaysIsTrue()
{
$service = $this->getService(null, array('name' => 'foo', 'always_remember_me' => true));
$request = new Request;
$response = new Response;
$account = $this->getMock('Symfony\Component\Security\User\AccountInterface');
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface');
$token
->expects($this->once())
->method('getUser')
->will($this->returnValue($account))
;
$service
->expects($this->once())
->method('onLoginSuccess')
->will($this->returnValue(null))
;
$service->loginSuccess($request, $response, $token);
}
/**
* @dataProvider getPositiveRememberMeParameterValues
*/
public function testLoginSuccessWhenRememberMeParameterIsPositive($value)
{
$service = $this->getService(null, array('name' => 'foo', 'always_remember_me' => false, 'remember_me_parameter' => 'foo'));
$request = new Request;
$request->request->set('foo', $value);
$response = new Response;
$account = $this->getMock('Symfony\Component\Security\User\AccountInterface');
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface');
$token
->expects($this->once())
->method('getUser')
->will($this->returnValue($account))
;
$service
->expects($this->once())
->method('onLoginSuccess')
->will($this->returnValue(true))
;
$service->loginSuccess($request, $response, $token);
}
public function getPositiveRememberMeParameterValues()
{
return array(
array('true'),
array('1'),
array('on'),
array('yes'),
);
}
public function testLoginSuccessRenewsRememberMeCookie()
{
$service = $this->getService();
$token = $this->getMock(
'Symfony\Component\Security\Authentication\Token\RememberMeToken',
array(),
array(),
'NonFunctionalRememberMeTokenMockClass',
false
);
$service
->expects($this->once())
->method('onLoginSuccess')
->will($this->returnValue(null))
;
$service->loginSuccess(new Request(), new Response(), $token);
}
protected function getService($userProvider = null, $options = array(), $logger = null)
{
if (null === $userProvider) {
$userProvider = $this->getProvider();
}
return $this->getMockForAbstractClass('Symfony\Component\HttpKernel\Security\RememberMe\RememberMeServices', array(
array($userProvider), 'fookey', 'fookey', $options, $logger
));
}
protected function getProvider()
{
$provider = $this->getMock('Symfony\Component\Security\User\UserProviderInterface');
$provider
->expects($this->any())
->method('supportsClass')
->will($this->returnValue(true))
;
return $provider;
}
}

View File

@ -0,0 +1,297 @@
<?php
namespace Symfony\Tests\Component\HttpKernel\Security\RememberMe;
use Symfony\Component\Security\Authentication\Token\RememberMeToken;
use Symfony\Component\Security\Authentication\Token\Token;
use Symfony\Component\Security\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Authentication\RememberMe\PersistentToken;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Security\RememberMe\TokenBasedRememberMeServices;
use Symfony\Component\Security\Exception\TokenNotFoundException;
use Symfony\Component\Security\Exception\CookieTheftException;
class TokenBasedRememberMeServicesTest extends \PHPUnit_Framework_TestCase
{
public function testAutoLoginReturnsNullWhenNoCookie()
{
$service = $this->getService(null, array('name' => 'foo'));
$this->assertNull($service->autoLogin(new Request()));
}
/**
* @expectedException Symfony\Component\Security\Exception\AuthenticationException
* @expectedMessage The cookie is invalid.
*/
public function testAutoLoginThrowsExceptionOnInvalidCookie()
{
$service = $this->getService(null, array('name' => 'foo', 'always_remember_me' => false, 'remember_me_parameter' => 'foo'));
$request = new Request;
$request->request->set('foo', 'true');
$request->cookies->set('foo', 'foo');
$service->autoLogin($request);
}
/**
* @expectedException Symfony\Component\Security\Exception\UsernameNotFoundException
*/
public function testAutoLoginThrowsExceptionOnNonExistentUser()
{
$userProvider = $this->getProvider();
$service = $this->getService($userProvider, array('name' => 'foo', 'always_remember_me' => true, 'lifetime' => 3600));
$request = new Request;
$request->cookies->set('foo', $this->getCookie('fooclass', 'foouser', time()+3600, 'foopass'));
$userProvider
->expects($this->once())
->method('loadUserByUsername')
->will($this->throwException(new UsernameNotFoundException('user not found')))
;
$service->autoLogin($request);
}
/**
* @expectedException Symfony\Component\Security\Exception\AuthenticationException
* @expectedMessage The cookie's hash is invalid.
*/
public function testAutoLoginDoesNotAcceptCookieWithInvalidHash()
{
$userProvider = $this->getProvider();
$service = $this->getService($userProvider, array('name' => 'foo', 'always_remember_me' => true, 'lifetime' => 3600));
$request = new Request;
$request->cookies->set('foo', base64_encode('class:'.base64_encode('foouser').':123456789:fooHash'));
$user = $this->getMock('Symfony\Component\Security\User\AccountInterface');
$user
->expects($this->once())
->method('getPassword')
->will($this->returnValue('foopass'))
;
$userProvider
->expects($this->once())
->method('loadUserByUsername')
->with($this->equalTo('foouser'))
->will($this->returnValue($user))
;
$service->autoLogin($request);
}
/**
* @expectedException Symfony\Component\Security\Exception\AuthenticationException
* @expectedMessage The cookie has expired.
*/
public function testAutoLoginDoesNotAcceptAnExpiredCookie()
{
$userProvider = $this->getProvider();
$service = $this->getService($userProvider, array('name' => 'foo', 'always_remember_me' => true, 'lifetime' => 3600));
$request = new Request;
$request->cookies->set('foo', $this->getCookie('fooclass', 'foouser', time() - 1, 'foopass'));
$user = $this->getMock('Symfony\Component\Security\User\AccountInterface');
$user
->expects($this->once())
->method('getPassword')
->will($this->returnValue('foopass'))
;
$userProvider
->expects($this->once())
->method('loadUserByUsername')
->with($this->equalTo('foouser'))
->will($this->returnValue($user))
;
$service->autoLogin($request);
}
public function testAutoLogin()
{
$user = $this->getMock('Symfony\Component\Security\User\AccountInterface');
$user
->expects($this->once())
->method('getRoles')
->will($this->returnValue(array('ROLE_FOO')))
;
$user
->expects($this->once())
->method('getPassword')
->will($this->returnValue('foopass'))
;
$userProvider = $this->getProvider();
$userProvider
->expects($this->once())
->method('loadUserByUsername')
->with($this->equalTo('foouser'))
->will($this->returnValue($user))
;
$service = $this->getService($userProvider, array('name' => 'foo', 'always_remember_me' => true, 'lifetime' => 3600));
$request = new Request;
$request->cookies->set('foo', $this->getCookie('fooclass', 'foouser', time()+3600, 'foopass'));
$returnedToken = $service->autoLogin($request);
$this->assertInstanceOf('Symfony\Component\Security\Authentication\Token\RememberMeToken', $returnedToken);
$this->assertSame($user, $returnedToken->getUser());
$this->assertEquals('fookey', $returnedToken->getKey());
}
public function testLogout()
{
$service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null));
$request = new Request();
$response = new Response();
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface');
$this->assertFalse($response->headers->hasCookie('foo'));
$service->logout($request, $response, $token);
$cookie = $response->headers->getCookie('foo');
$this->assertTrue($cookie->isCleared());
$this->assertNull($cookie->getPath());
$this->assertNull($cookie->getDomain());
}
public function testLoginFail()
{
$service = $this->getService(null, array('name' => 'foo', 'path' => '/foo', 'domain' => 'foodomain.foo'));
$request = new Request();
$response = new Response();
$this->assertFalse($response->headers->hasCookie('foo'));
$service->loginFail($request, $response);
$cookie = $response->headers->getCookie('foo');
$this->assertTrue($cookie->isCleared());
$this->assertEquals('/foo', $cookie->getPath());
$this->assertEquals('foodomain.foo', $cookie->getDomain());
}
public function testLoginSuccessDoesNotRenewRememberMeToken()
{
$service = $this->getService(null, array('name' => 'foo', 'domain' => 'myfoodomain.foo', 'path' => '/foo/path', 'secure' => true, 'httponly' => true, 'lifetime' => 3600));
$request = new Request;
$response = new Response;
$user = $this->getMock('Symfony\Component\Security\User\AccountInterface');
$user
->expects($this->once())
->method('getRoles')
->will($this->returnValue(array('ROLE_FOO')))
;
$token = new RememberMeToken($user, 'fookey', 'foo');
$this->assertFalse($response->headers->hasCookie('foo'));
$service->loginSuccess($request, $response, $token);
$this->assertFalse($response->headers->hasCookie('foo'));
}
public function testLoginSuccessIgnoresTokensWhichDoNotContainAnAccountInterfaceImplementation()
{
$service = $this->getService(null, array('name' => 'foo', 'always_remember_me' => true));
$request = new Request;
$response = new Response;
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface');
$token
->expects($this->once())
->method('getUser')
->will($this->returnValue('foo'))
;
$this->assertFalse($response->headers->hasCookie('foo'));
$service->loginSuccess($request, $response, $token);
$this->assertFalse($response->headers->hasCookie('foo'));
}
public function testLoginSuccess()
{
$service = $this->getService(null, array('name' => 'foo', 'domain' => 'myfoodomain.foo', 'path' => '/foo/path', 'secure' => true, 'httponly' => true, 'lifetime' => 3600, 'always_remember_me' => true));
$request = new Request;
$response = new Response;
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface');
$user = $this->getMock('Symfony\Component\Security\User\AccountInterface');
$user
->expects($this->once())
->method('getPassword')
->will($this->returnValue('foopass'))
;
$user
->expects($this->once())
->method('getUsername')
->will($this->returnValue('foouser'))
;
$token
->expects($this->atLeastOnce())
->method('getUser')
->will($this->returnValue($user))
;
$this->assertFalse($response->headers->hasCookie('foo'));
$service->loginSuccess($request, $response, $token);
$cookie = $response->headers->getCookie('foo');
$this->assertFalse($cookie->isCleared());
$this->assertTrue($cookie->isSecure());
$this->assertTrue($cookie->isHttponly());
$this->assertTrue($cookie->getExpire() > time() + 3590 && $cookie->getExpire() < time() + 3610);
$this->assertEquals('myfoodomain.foo', $cookie->getDomain());
$this->assertEquals('/foo/path', $cookie->getPath());
}
protected function getCookie($class, $username, $expires, $password)
{
$service = $this->getService();
$r = new \ReflectionMethod($service, 'generateCookieValue');
$r->setAccessible(true);
return $r->invoke($service, $class, $username, $expires, $password);
}
protected function encodeCookie(array $parts)
{
$service = $this->getService();
$r = new \ReflectionMethod($service, 'encodeCookie');
$r->setAccessible(true);
return $r->invoke($service, $parts);
}
protected function getService($userProvider = null, $options = array(), $logger = null)
{
if (null === $userProvider) {
$userProvider = $this->getProvider();
}
$service = new TokenBasedRememberMeServices(array($userProvider), 'fookey', 'fookey', $options, $logger);
return $service;
}
protected function getProvider()
{
$provider = $this->getMock('Symfony\Component\Security\User\UserProviderInterface');
$provider
->expects($this->any())
->method('supportsClass')
->will($this->returnValue(true))
;
return $provider;
}
}

View File

@ -25,27 +25,27 @@ class AclProviderBenchmarkTest extends \PHPUnit_Framework_TestCase
protected $insertOidAncestorStmt;
protected $insertOidStmt;
protected $insertEntryStmt;
public function testFindAcls()
{
// $this->generateTestData();
// get some random test object identities from the database
$oids = array();
$stmt = $this->con->executeQuery("SELECT object_identifier, class_type FROM acl_object_identities o INNER JOIN acl_classes c ON c.id = o.class_id ORDER BY RAND() LIMIT 25");
foreach ($stmt->fetchAll() as $oid) {
$oids[] = new ObjectIdentity($oid['object_identifier'], $oid['class_type']);
}
$provider = $this->getProvider();
$start = microtime(true);
$provider->findAcls($oids);
$time = microtime(true) - $start;
echo "Total Time: ".$time."s\n";
}
protected function setUp()
{
// comment the following line, and run only this test, if you need to benchmark
@ -58,12 +58,12 @@ class AclProviderBenchmarkTest extends \PHPUnit_Framework_TestCase
'dbname' => 'testdb',
));
}
protected function tearDown()
{
$this->con = null;
}
/**
* This generates a huge amount of test data to be used mainly for benchmarking
* purposes, not so much for testing. That's why it's not called by default.
@ -73,7 +73,7 @@ class AclProviderBenchmarkTest extends \PHPUnit_Framework_TestCase
$sm = $this->con->getSchemaManager();
$sm->dropAndCreateDatabase('testdb');
$this->con->exec("USE testdb");
// import the schema
$schema = new Schema($options = $this->getOptions());
foreach ($schema->toSql($this->con->getDatabasePlatform()) as $sql) {
@ -86,49 +86,49 @@ class AclProviderBenchmarkTest extends \PHPUnit_Framework_TestCase
$this->insertOidStmt = $this->con->prepare('INSERT INTO acl_object_identities (id, class_id, object_identifier, parent_object_identity_id, entries_inheriting) VALUES (?, ?, ?, ?, ?)');
$this->insertEntryStmt = $this->con->prepare('INSERT INTO acl_entries (id, class_id, object_identity_id, field_name, ace_order, security_identity_id, mask, granting, granting_strategy, audit_success, audit_failure) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
$this->insertOidAncestorStmt = $this->con->prepare('INSERT INTO acl_object_identity_ancestors (object_identity_id, ancestor_id) VALUES (?, ?)');
for ($i=0; $i<40000; $i++) {
$this->generateAclHierarchy();
}
}
protected function generateAclHierarchy()
{
$rootId = $this->generateAcl($this->chooseClassId(), null, array());
$this->generateAclLevel(rand(1, 15), $rootId, array($rootId));
}
protected function generateAclLevel($depth, $parentId, $ancestors)
{
$level = count($ancestors);
for ($i=0,$t=rand(1, 10); $i<$t; $i++) {
$id = $this->generateAcl($this->chooseClassId(), $parentId, $ancestors);
if ($level < $depth) {
$this->generateAclLevel($depth, $id, array_merge($ancestors, array($id)));
}
}
}
protected function chooseClassId()
{
static $id = 1000;
if ($id === 1000 || ($id < 1500 && rand(0, 1))) {
$this->insertClassStmt->execute(array($id, $this->getRandomString(rand(20, 100), 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\\_')));
$id += 1;
return $id-1;
}
return rand(1000, $id-1);
return $id-1;
} else {
return rand(1000, $id-1);
}
}
protected function generateAcl($classId, $parentId, $ancestors)
{
static $id = 1000;
$this->insertOidStmt->execute(array(
$id,
$classId,
@ -136,57 +136,57 @@ class AclProviderBenchmarkTest extends \PHPUnit_Framework_TestCase
$parentId,
rand(0, 1),
));
$this->insertOidAncestorStmt->execute(array($id, $id));
foreach ($ancestors as $ancestor) {
$this->insertOidAncestorStmt->execute(array($id, $ancestor));
}
$this->generateAces($classId, $id);
$id += 1;
return $id-1;
}
protected function chooseSid()
{
static $id = 1000;
if ($id === 1000 || ($id < 11000 && rand(0, 1))) {
$this->insertSidStmt->execute(array(
$id,
$this->getRandomString(rand(5, 30)),
$id,
$this->getRandomString(rand(5, 30)),
rand(0, 1)
));
$id += 1;
return $id-1;
}
return rand(1000, $id-1);
return $id-1;
} else {
return rand(1000, $id-1);
}
}
protected function generateAces($classId, $objectId)
{
static $id = 1000;
$sids = array();
$fieldOrder = array();
for ($i=0; $i<=30; $i++) {
$fieldName = rand(0, 1) ? null : $this->getRandomString(rand(10, 20));
do {
$sid = $this->chooseSid();
}
while (array_key_exists($sid, $sids) && in_array($fieldName, $sids[$sid], true));
$fieldOrder[$fieldName] = array_key_exists($fieldName, $fieldOrder) ? $fieldOrder[$fieldName]+1 : 0;
if (!isset($sids[$sid])) {
$sids[$sid] = array();
}
$sids[$sid][] = $fieldName;
$strategy = rand(0, 2);
if ($strategy === 0) {
$strategy = PermissionGrantingStrategy::ALL;
@ -195,7 +195,7 @@ class AclProviderBenchmarkTest extends \PHPUnit_Framework_TestCase
} else {
$strategy = PermissionGrantingStrategy::EQUAL;
}
// id, cid, oid, field, order, sid, mask, granting, strategy, a success, a failure
$this->insertEntryStmt->execute(array(
$id,
@ -210,36 +210,36 @@ class AclProviderBenchmarkTest extends \PHPUnit_Framework_TestCase
rand(0, 1),
rand(0, 1),
));
$id += 1;
}
}
protected function generateMask()
{
$i = rand(1, 30);
$mask = 0;
while ($i <= 30) {
$mask |= 1 << rand(0, 30);
$i++;
}
return $mask;
}
protected function getRandomString($length, $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')
{
$s = '';
$cLength = strlen($chars);
while (strlen($s) < $length) {
$s .= $chars[mt_rand(0, $cLength-1)];
}
return $s;
}
protected function getOptions()
{
return array(
@ -249,15 +249,15 @@ class AclProviderBenchmarkTest extends \PHPUnit_Framework_TestCase
'sid_table_name' => 'acl_security_identities',
'entry_table_name' => 'acl_entries',
);
}
}
protected function getStrategy()
{
return new PermissionGrantingStrategy();
}
protected function getProvider()
{
return new AclProvider($this->con, $this->getStrategy(), $this->getOptions());
}
}
}

View File

@ -24,17 +24,37 @@ class SecurityIdentityRetrievalStrategyTest extends \PHPUnit_Framework_TestCase
{
$strategy = $this->getStrategy($roles, $authenticationStatus);
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface');
if ('anonymous' === $authenticationStatus) {
$token = $this->getMockBuilder('Symfony\Component\Security\Authentication\Token\AnonymousToken')
->disableOriginalConstructor()
->getMock();
} else {
$class = '';
if (is_string($user)) {
$class = 'MyCustomTokenImpl';
}
$token = $this->getMockBuilder('Symfony\Component\Security\Authentication\Token\TokenInterface')
->setMockClassName($class)
->getMock();
}
$token
->expects($this->once())
->method('getRoles')
->will($this->returnValue(array('foo')))
;
$token
->expects($this->once())
->method('getUser')
->will($this->returnValue($user))
;
if ('anonymous' === $authenticationStatus) {
$token
->expects($this->never())
->method('getUser')
;
} else {
$token
->expects($this->once())
->method('getUser')
->will($this->returnValue($user))
;
}
$extractedSids = $strategy->getSecurityIdentities($token);
@ -60,6 +80,20 @@ class SecurityIdentityRetrievalStrategyTest extends \PHPUnit_Framework_TestCase
new RoleSecurityIdentity('IS_AUTHENTICATED_REMEMBERED'),
new RoleSecurityIdentity('IS_AUTHENTICATED_ANONYMOUSLY'),
)),
array('johannes', array('ROLE_FOO'), 'fullFledged', array(
new UserSecurityIdentity('johannes', 'MyCustomTokenImpl'),
new RoleSecurityIdentity('ROLE_FOO'),
new RoleSecurityIdentity('IS_AUTHENTICATED_FULLY'),
new RoleSecurityIdentity('IS_AUTHENTICATED_REMEMBERED'),
new RoleSecurityIdentity('IS_AUTHENTICATED_ANONYMOUSLY'),
)),
array(new CustomUserImpl('johannes'), array('ROLE_FOO'), 'fullFledged', array(
new UserSecurityIdentity('johannes', 'Symfony\Tests\Component\Security\Acl\Domain\CustomUserImpl'),
new RoleSecurityIdentity('ROLE_FOO'),
new RoleSecurityIdentity('IS_AUTHENTICATED_FULLY'),
new RoleSecurityIdentity('IS_AUTHENTICATED_REMEMBERED'),
new RoleSecurityIdentity('IS_AUTHENTICATED_ANONYMOUSLY'),
)),
array($this->getAccount('foo', 'FooBarUser'), array('ROLE_FOO'), 'rememberMe', array(
new UserSecurityIdentity('foo', 'FooBarUser'),
new RoleSecurityIdentity('ROLE_FOO'),
@ -77,11 +111,12 @@ class SecurityIdentityRetrievalStrategyTest extends \PHPUnit_Framework_TestCase
{
$account = $this->getMock('Symfony\Component\Security\User\AccountInterface', array(), array(), $class);
$account
->expects($this->once())
->method('__toString')
->expects($this->any())
->method('getUsername')
->will($this->returnValue($username))
;
return $account;
}
@ -145,4 +180,19 @@ class SecurityIdentityRetrievalStrategyTest extends \PHPUnit_Framework_TestCase
return new SecurityIdentityRetrievalStrategy($roleHierarchy, $trustResolver);
}
}
class CustomUserImpl
{
protected $name;
public function __construct($name)
{
$this->name = $name;
}
public function __toString()
{
return $this->name;
}
}

View File

@ -29,22 +29,27 @@ class UserSecurityIdentityTest extends \PHPUnit_Framework_TestCase
*/
public function testEquals($id1, $id2, $equal)
{
if ($equal) {
$this->assertTrue($id1->equals($id2));
} else {
$this->assertFalse($id1->equals($id2));
}
$this->assertSame($equal, $id1->equals($id2));
}
public function getCompareData()
{
$account = $this->getMock('Symfony\Component\Security\User\AccountInterface');
$account = $this->getMockBuilder('Symfony\Component\Security\User\AccountInterface')
->setMockClassName('USI_AccountImpl')
->getMock();
$account
->expects($this->once())
->method('__toString')
->expects($this->any())
->method('getUsername')
->will($this->returnValue('foo'))
;
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface');
$token
->expects($this->any())
->method('getUser')
->will($this->returnValue($account))
;
return array(
array(new UserSecurityIdentity('foo', 'Foo'), new UserSecurityIdentity('foo', 'Foo'), true),
array(new UserSecurityIdentity('foo', 'Bar'), new UserSecurityIdentity('foo', 'Foo'), false),
@ -52,6 +57,8 @@ class UserSecurityIdentityTest extends \PHPUnit_Framework_TestCase
array(new UserSecurityIdentity('foo', 'Foo'), UserSecurityIdentity::fromAccount($account), false),
array(new UserSecurityIdentity('bla', 'Foo'), new UserSecurityIdentity('blub', 'Foo'), false),
array(new UserSecurityIdentity('foo', 'Foo'), new RoleSecurityIdentity('foo'), false),
array(new UserSecurityIdentity('foo', 'Foo'), UserSecurityIdentity::fromToken($token), false),
array(new UserSecurityIdentity('foo', 'USI_AccountImpl'), UserSecurityIdentity::fromToken($token), true),
);
}
}

View File

@ -105,14 +105,14 @@ class AuthenticationProviderManagerTest extends \PHPUnit_Framework_TestCase
public function testEraseCredentialFlag()
{
$manager = new AuthenticationProviderManager(array(
$this->getAuthenticationProvider(true, $token = new UsernamePasswordToken('foo', 'bar')),
$this->getAuthenticationProvider(true, $token = new UsernamePasswordToken('foo', 'bar', 'key')),
));
$token = $manager->authenticate($this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface'));
$this->assertEquals('', $token->getCredentials());
$manager = new AuthenticationProviderManager(array(
$this->getAuthenticationProvider(true, $token = new UsernamePasswordToken('foo', 'bar')),
$this->getAuthenticationProvider(true, $token = new UsernamePasswordToken('foo', 'bar', 'key')),
), false);
$token = $manager->authenticate($this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface'));

View File

@ -42,7 +42,7 @@ class DaoAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
->will($this->throwException($this->getMock('Symfony\Component\Security\Exception\UsernameNotFoundException', null, array(), '', false)))
;
$provider = new DaoAuthenticationProvider($userProvider, $this->getMock('Symfony\Component\Security\User\AccountCheckerInterface'), $this->getMock('Symfony\Component\Security\Encoder\EncoderFactoryInterface'));
$provider = new DaoAuthenticationProvider($userProvider, $this->getMock('Symfony\Component\Security\User\AccountCheckerInterface'), 'key', $this->getMock('Symfony\Component\Security\Encoder\EncoderFactoryInterface'));
$method = new \ReflectionMethod($provider, 'retrieveUser');
$method->setAccessible(true);
@ -60,7 +60,7 @@ class DaoAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
->will($this->throwException($this->getMock('RuntimeException', null, array(), '', false)))
;
$provider = new DaoAuthenticationProvider($userProvider, $this->getMock('Symfony\Component\Security\User\AccountCheckerInterface'), $this->getMock('Symfony\Component\Security\Encoder\EncoderFactoryInterface'));
$provider = new DaoAuthenticationProvider($userProvider, $this->getMock('Symfony\Component\Security\User\AccountCheckerInterface'), 'key', $this->getMock('Symfony\Component\Security\Encoder\EncoderFactoryInterface'));
$method = new \ReflectionMethod($provider, 'retrieveUser');
$method->setAccessible(true);
@ -81,7 +81,7 @@ class DaoAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue($user))
;
$provider = new DaoAuthenticationProvider($userProvider, $this->getMock('Symfony\Component\Security\User\AccountCheckerInterface'), $this->getMock('Symfony\Component\Security\Encoder\EncoderFactoryInterface'));
$provider = new DaoAuthenticationProvider($userProvider, $this->getMock('Symfony\Component\Security\User\AccountCheckerInterface'), 'key', $this->getMock('Symfony\Component\Security\Encoder\EncoderFactoryInterface'));
$reflection = new \ReflectionMethod($provider, 'retrieveUser');
$reflection->setAccessible(true);
$result = $reflection->invoke($provider, null, $token);
@ -99,7 +99,7 @@ class DaoAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue($user))
;
$provider = new DaoAuthenticationProvider($userProvider, $this->getMock('Symfony\Component\Security\User\AccountCheckerInterface'), $this->getMock('Symfony\Component\Security\Encoder\EncoderFactoryInterface'));
$provider = new DaoAuthenticationProvider($userProvider, $this->getMock('Symfony\Component\Security\User\AccountCheckerInterface'), 'key', $this->getMock('Symfony\Component\Security\Encoder\EncoderFactoryInterface'));
$method = new \ReflectionMethod($provider, 'retrieveUser');
$method->setAccessible(true);
@ -224,7 +224,14 @@ class DaoAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
protected function getSupportedToken()
{
return $this->getMock('Symfony\Component\Security\Authentication\Token\UsernamePasswordToken', array('getCredentials', 'getUser'), array(), '', false);
$mock = $this->getMock('Symfony\Component\Security\Authentication\Token\UsernamePasswordToken', array('getCredentials', 'getUser'), array(), '', false);
$mock
->expects($this->any())
->method('getProviderKey')
->will($this->returnValue('key'))
;
return $mock;
}
protected function getProvider($user = false, $userChecker = false, $passwordEncoder = null)
@ -252,6 +259,6 @@ class DaoAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue($passwordEncoder))
;
return new DaoAuthenticationProvider($userProvider, $userChecker, $encoderFactory);
return new DaoAuthenticationProvider($userProvider, $userChecker, 'key', $encoderFactory);
}
}

View File

@ -21,6 +21,17 @@ class PreAuthenticatedAuthenticationProviderTest extends \PHPUnit_Framework_Test
$this->assertTrue($provider->supports($this->getSupportedToken()));
$this->assertFalse($provider->supports($this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface')));
$token = $this->getMockBuilder('Symfony\Component\Security\Authentication\Token\PreAuthenticatedToken')
->disableOriginalConstructor()
->getMock()
;
$token
->expects($this->once())
->method('getProviderKey')
->will($this->returnValue('foo'))
;
$this->assertFalse($provider->supports($token));
}
public function testAuthenticateWhenTokenIsNotSupported()
@ -71,7 +82,7 @@ class PreAuthenticatedAuthenticationProviderTest extends \PHPUnit_Framework_Test
protected function getSupportedToken($user = false, $credentials = false)
{
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\PreAuthenticatedToken', array('getUser', 'getCredentials'), array(), '', false);
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\PreAuthenticatedToken', array('getUser', 'getCredentials', 'getProviderKey'), array(), '', false);
if (false !== $user) {
$token->expects($this->once())
->method('getUser')
@ -85,6 +96,12 @@ class PreAuthenticatedAuthenticationProviderTest extends \PHPUnit_Framework_Test
;
}
$token
->expects($this->any())
->method('getProviderKey')
->will($this->returnValue('key'))
;
return $token;
}
@ -102,6 +119,6 @@ class PreAuthenticatedAuthenticationProviderTest extends \PHPUnit_Framework_Test
$userChecker = $this->getMock('Symfony\Component\Security\User\AccountCheckerInterface');
}
return new PreAuthenticatedAuthenticationProvider($userProvider, $userChecker);
return new PreAuthenticatedAuthenticationProvider($userProvider, $userChecker, 'key');
}
}

View File

@ -0,0 +1,124 @@
<?php
namespace Symfony\Tests\Component\Security\Authentication\Provider;
use Symfony\Component\Security\Authentication\Provider\RememberMeAuthenticationProvider;
use Symfony\Component\Security\Authentication\Token\RememberMeToken;
use Symfony\Component\Security\Role\Role;
class RememberMeAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
{
public function testSupports()
{
$provider = $this->getProvider();
$this->assertTrue($provider->supports($this->getSupportedToken()));
$this->assertFalse($provider->supports($this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface')));
}
public function testAuthenticateWhenTokenIsNotSupported()
{
$provider = $this->getProvider();
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface');
$this->assertNull($provider->authenticate($token));
}
/**
* @expectedException Symfony\Component\Security\Exception\BadCredentialsException
*/
public function testAuthenticateWhenKeysDoNotMatch()
{
$provider = $this->getProvider(null, 'key1');
$token = $this->getSupportedToken(null, 'key2');
$provider->authenticate($token);
}
/**
* @expectedException Symfony\Component\Security\Exception\CredentialsExpiredException
*/
public function testAuthenticateWhenPreChecksFails()
{
$userChecker = $this->getMock('Symfony\Component\Security\User\AccountCheckerInterface');
$userChecker->expects($this->once())
->method('checkPreAuth')
->will($this->throwException($this->getMock('Symfony\Component\Security\Exception\CredentialsExpiredException', null, array(), '', false)))
;
$provider = $this->getProvider($userChecker);
$provider->authenticate($this->getSupportedToken());
}
/**
* @expectedException Symfony\Component\Security\Exception\AccountExpiredException
*/
public function testAuthenticateWhenPostChecksFails()
{
$userChecker = $this->getMock('Symfony\Component\Security\User\AccountCheckerInterface');
$userChecker->expects($this->once())
->method('checkPostAuth')
->will($this->throwException($this->getMock('Symfony\Component\Security\Exception\AccountExpiredException', null, array(), '', false)))
;
$provider = $this->getProvider($userChecker);
$provider->authenticate($this->getSupportedToken());
}
public function testAuthenticate()
{
$user = $this->getMock('Symfony\Component\Security\User\AccountInterface');
$user->expects($this->once())
->method('getRoles')
->will($this->returnValue(array('ROLE_FOO')))
;
$provider = $this->getProvider();
$token = $this->getSupportedToken($user);
$token
->expects($this->once())
->method('getCredentials')
->will($this->returnValue('foo'))
;
$authToken = $provider->authenticate($token);
$this->assertInstanceOf('Symfony\Component\Security\Authentication\Token\RememberMeToken', $authToken);
$this->assertSame($user, $authToken->getUser());
$this->assertEquals(array(new Role('ROLE_FOO')), $authToken->getRoles());
$this->assertEquals('foo', $authToken->getCredentials());
}
protected function getSupportedToken($user = null, $key = 'test')
{
if (null === $user) {
$user = $this->getMock('Symfony\Component\Security\User\AccountInterface');
$user
->expects($this->any())
->method('getRoles')
->will($this->returnValue(array()))
;
}
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\RememberMeToken', array('getCredentials', 'getProviderKey'), array($user, 'foo', $key));
$token
->expects($this->once())
->method('getProviderKey')
->will($this->returnValue('foo'))
;
return $token;
}
protected function getProvider($userChecker = null, $key = 'test')
{
if (null === $userChecker) {
$userChecker = $this->getMock('Symfony\Component\Security\User\AccountCheckerInterface');
}
return new RememberMeAuthenticationProvider($userChecker, $key, 'foo');
}
}

View File

@ -161,7 +161,14 @@ class UserAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
protected function getSupportedToken()
{
return $this->getMock('Symfony\Component\Security\Authentication\Token\UsernamePasswordToken', array('getCredentials'), array(), '', false);
$mock = $this->getMock('Symfony\Component\Security\Authentication\Token\UsernamePasswordToken', array('getCredentials', 'getProviderKey'), array(), '', false);
$mock
->expects($this->any())
->method('getProviderKey')
->will($this->returnValue('key'))
;
return $mock;
}
protected function getProvider($userChecker = false, $hide = true)
@ -170,6 +177,6 @@ class UserAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
$userChecker = $this->getMock('Symfony\Component\Security\User\AccountCheckerInterface');
}
return $this->getMockForAbstractClass('Symfony\Component\Security\Authentication\Provider\UserAuthenticationProvider', array($userChecker, $hide));
return $this->getMockForAbstractClass('Symfony\Component\Security\Authentication\Provider\UserAuthenticationProvider', array($userChecker, 'key', $hide));
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace Symfony\Tests\Component\Security\Authentication\RememberMe;
use Symfony\Component\Security\Authentication\RememberMe\PersistentToken;
use Symfony\Component\Security\Authentication\RememberMe\InMemoryTokenProvider;
class InMemoryTokenProviderTest extends \PHPUnit_Framework_TestCase
{
public function testCreateNewToken()
{
$provider = new InMemoryTokenProvider();
$token = new PersistentToken('foo', 'foo', 'foo', 'foo', new \DateTime());
$provider->createNewToken($token);
$this->assertSame($provider->loadTokenBySeries('foo'), $token);
}
/**
* @expectedException Symfony\Component\Security\Exception\TokenNotFoundException
*/
public function testLoadTokenBySeriesThrowsNotFoundException()
{
$provider = new InMemoryTokenProvider();
$provider->loadTokenBySeries('foo');
}
public function testUpdateToken()
{
$provider = new InMemoryTokenProvider();
$token = new PersistentToken('foo', 'foo', 'foo', 'foo', new \DateTime());
$provider->createNewToken($token);
$provider->updateToken('foo', 'newFoo', $lastUsed = new \DateTime());
$token = $provider->loadTokenBySeries('foo');
$this->assertEquals('newFoo', $token->getTokenValue());
$this->assertSame($token->getLastUsed(), $lastUsed);
}
/**
* @expectedException Symfony\Component\Security\Exception\TokenNotFoundException
*/
public function testDeleteToken()
{
$provider = new InMemoryTokenProvider();
$token = new PersistentToken('foo', 'foo', 'foo', 'foo', new \DateTime());
$provider->createNewToken($token);
$provider->deleteTokenBySeries('foo');
$provider->loadTokenBySeries('foo');
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace Symfony\Tests\Component\Security\Authentication\RememberMe;
use Symfony\Component\Security\Authentication\RememberMe\PersistentToken;
class PersistentTokenTest extends \PHPUnit_Framework_TestCase
{
public function testConstructor()
{
$lastUsed = new \DateTime();
$token = new PersistentToken('fooclass', 'fooname', 'fooseries', 'footokenvalue', $lastUsed);
$this->assertEquals('fooclass', $token->getClass());
$this->assertEquals('fooname', $token->getUsername());
$this->assertEquals('fooseries', $token->getSeries());
$this->assertEquals('footokenvalue', $token->getTokenValue());
$this->assertSame($lastUsed, $token->getLastUsed());
}
}

View File

@ -18,29 +18,30 @@ class PreAuthenticatedTokenTest extends \PHPUnit_Framework_TestCase
{
public function testConstructor()
{
$token = new PreAuthenticatedToken('foo', 'bar');
$token = new PreAuthenticatedToken('foo', 'bar', 'key');
$this->assertFalse($token->isAuthenticated());
$token = new PreAuthenticatedToken('foo', 'bar', array('ROLE_FOO'));
$token = new PreAuthenticatedToken('foo', 'bar', 'key', array('ROLE_FOO'));
$this->assertTrue($token->isAuthenticated());
$this->assertEquals(array(new Role('ROLE_FOO')), $token->getRoles());
$this->assertEquals('key', $token->getProviderKey());
}
public function testGetCredentials()
{
$token = new PreAuthenticatedToken('foo', 'bar');
$token = new PreAuthenticatedToken('foo', 'bar', 'key');
$this->assertEquals('bar', $token->getCredentials());
}
public function testGetUser()
{
$token = new PreAuthenticatedToken('foo', 'bar');
$token = new PreAuthenticatedToken('foo', 'bar', 'key');
$this->assertEquals('foo', $token->getUser());
}
public function testEraseCredentials()
{
$token = new PreAuthenticatedToken('foo', 'bar');
$token = new PreAuthenticatedToken('foo', 'bar', 'key');
$token->eraseCredentials();
$this->assertEquals('', $token->getCredentials());
}

View File

@ -0,0 +1,84 @@
<?php
namespace Symfony\Tests\Component\Security\Authentication\Token;
use Symfony\Component\Security\Authentication\Token\RememberMeToken;
use Symfony\Component\Security\Role\Role;
class RememberMeTokenTest extends \PHPUnit_Framework_TestCase
{
public function testConstructor()
{
$user = $this->getUser();
$token = new RememberMeToken($user, 'fookey', 'foo');
$this->assertEquals('fookey', $token->getProviderKey());
$this->assertEquals('foo', $token->getKey());
$this->assertEquals(array(new Role('ROLE_FOO')), $token->getRoles());
$this->assertSame($user, $token->getUser());
$this->assertTrue($token->isAuthenticated());
}
/**
* @expectedException \InvalidArgumentException
*/
public function testConstructorKeyCannotBeNull()
{
new RememberMeToken(
$this->getUser(),
null,
null
);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testConstructorKeyCannotBeEmptyString()
{
new RememberMeToken(
$this->getUser(),
'',
''
);
}
/**
* @expectedException PHPUnit_Framework_Error
* @dataProvider getUserArguments
*/
public function testConstructorUserCannotBeNull($user)
{
new RememberMeToken($user, 'foo', 'foo');
}
public function getUserArguments()
{
return array(
array(null),
array('foo'),
);
}
public function testPersistentToken()
{
$token = new RememberMeToken($this->getUser(), 'fookey', 'foo');
$persistentToken = $this->getMock('Symfony\Component\Security\Authentication\RememberMe\PersistentTokenInterface');
$this->assertNull($token->getPersistentToken());
$token->setPersistentToken($persistentToken);
$this->assertSame($persistentToken, $token->getPersistentToken());
}
protected function getUser($roles = array('ROLE_FOO'))
{
$user = $this->getMock('Symfony\Component\Security\User\AccountInterface');
$user
->expects($this->once())
->method('getRoles')
->will($this->returnValue($roles))
;
return $user;
}
}

View File

@ -18,12 +18,13 @@ class UsernamePasswordTokenTest extends \PHPUnit_Framework_TestCase
{
public function testConstructor()
{
$token = new UsernamePasswordToken('foo', 'bar');
$token = new UsernamePasswordToken('foo', 'bar', 'key');
$this->assertFalse($token->isAuthenticated());
$token = new UsernamePasswordToken('foo', 'bar', array('ROLE_FOO'));
$token = new UsernamePasswordToken('foo', 'bar', 'key', array('ROLE_FOO'));
$this->assertEquals(array(new Role('ROLE_FOO')), $token->getRoles());
$this->assertTrue($token->isAuthenticated());
$this->assertEquals('key', $token->getProviderKey());
}
/**
@ -31,20 +32,20 @@ class UsernamePasswordTokenTest extends \PHPUnit_Framework_TestCase
*/
public function testSetAuthenticatedToTrue()
{
$token = new UsernamePasswordToken('foo', 'bar');
$token = new UsernamePasswordToken('foo', 'bar', 'key');
$token->setAuthenticated(true);
}
public function testSetAuthenticatedToFalse()
{
$token = new UsernamePasswordToken('foo', 'bar');
$token = new UsernamePasswordToken('foo', 'bar', 'key');
$token->setAuthenticated(false);
$this->assertFalse($token->isAuthenticated());
}
public function testEraseCredentials()
{
$token = new UsernamePasswordToken('foo', 'bar');
$token = new UsernamePasswordToken('foo', 'bar', 'key');
$token->eraseCredentials();
$this->assertEquals('', $token->getCredentials());
}

View File

@ -11,13 +11,14 @@
namespace Symfony\Tests\Component\Security;
use Symfony\Component\Security\Authentication\AuthenticationProviderManager;
use Symfony\Component\Security\SecurityContext;
class SecurityContextTest extends \PHPUnit_Framework_TestCase
{
public function testIsAuthenticated()
{
$context = new SecurityContext();
$context = new SecurityContext($this->getMock('Symfony\Component\Security\Authentication\AuthenticationManagerInterface'));
$this->assertFalse($context->isAuthenticated());
@ -34,7 +35,7 @@ class SecurityContextTest extends \PHPUnit_Framework_TestCase
public function testGetUser()
{
$context = new SecurityContext();
$context = new SecurityContext($this->getMock('Symfony\Component\Security\Authentication\AuthenticationManagerInterface'));
$this->assertNull($context->getUser());
@ -44,33 +45,64 @@ class SecurityContextTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('foo', $context->getUser());
}
public function testVoteAuthenticatesTokenIfNecessary()
{
$authManager = $this->getMock('Symfony\Component\Security\Authentication\AuthenticationManagerInterface');
$decisionManager = $this->getMock('Symfony\Component\Security\Authorization\AccessDecisionManagerInterface');
$context = new SecurityContext($authManager, $decisionManager);
$context->setToken($token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface'));
$authManager
->expects($this->once())
->method('authenticate')
->with($this->equalTo($token))
->will($this->returnValue($newToken = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface')))
;
$decisionManager
->expects($this->once())
->method('decide')
->will($this->returnValue(true))
;
$this->assertTrue($context->vote('foo'));
$this->assertSame($newToken, $context->getToken());
}
public function testVote()
{
$context = new SecurityContext();
$context = new SecurityContext($this->getMock('Symfony\Component\Security\Authentication\AuthenticationManagerInterface'));
$this->assertFalse($context->vote('ROLE_FOO'));
$context->setToken($token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface'));
$this->assertFalse($context->vote('ROLE_FOO'));
$manager = $this->getMock('Symfony\Component\Security\Authorization\AccessDecisionManager');
$manager = $this->getMock('Symfony\Component\Security\Authorization\AccessDecisionManagerInterface');
$manager->expects($this->once())->method('decide')->will($this->returnValue(false));
$context = new SecurityContext($manager);
$context = new SecurityContext($this->getMock('Symfony\Component\Security\Authentication\AuthenticationManagerInterface'), $manager);
$context->setToken($token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface'));
$token
->expects($this->once())
->method('isAuthenticated')
->will($this->returnValue(true))
;
$this->assertFalse($context->vote('ROLE_FOO'));
$manager = $this->getMock('Symfony\Component\Security\Authorization\AccessDecisionManager');
$manager = $this->getMock('Symfony\Component\Security\Authorization\AccessDecisionManagerInterface');
$manager->expects($this->once())->method('decide')->will($this->returnValue(true));
$context = new SecurityContext($manager);
$context = new SecurityContext($this->getMock('Symfony\Component\Security\Authentication\AuthenticationManagerInterface'), $manager);
$context->setToken($token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface'));
$token
->expects($this->once())
->method('isAuthenticated')
->will($this->returnValue(true))
;
$this->assertTrue($context->vote('ROLE_FOO'));
}
public function testGetSetToken()
{
$context = new SecurityContext();
$context = new SecurityContext($this->getMock('Symfony\Component\Security\Authentication\AuthenticationManagerInterface'));
$this->assertNull($context->getToken());
$context->setToken($token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface'));

View File

@ -121,7 +121,7 @@ class UserTest extends \PHPUnit_Framework_TestCase
{
$user = new User('fabien', 'superpass');
$user->eraseCredentials();
$this->assertNull($user->getPassword());
$this->assertEquals('superpass', $user->getPassword());
}
/**