Actualización

This commit is contained in:
Xes
2025-04-10 12:24:57 +02:00
parent 8969cc929d
commit 45420b6f0d
39760 changed files with 4303286 additions and 0 deletions

View File

@@ -0,0 +1,200 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\DataCollector;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\SecurityBundle\DataCollector\SecurityDataCollector;
use Symfony\Bundle\SecurityBundle\Security\FirewallConfig;
use Symfony\Bundle\SecurityBundle\Security\FirewallMap;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Security\Core\Role\RoleHierarchy;
use Symfony\Component\Security\Http\FirewallMapInterface;
class SecurityDataCollectorTest extends TestCase
{
public function testCollectWhenSecurityIsDisabled()
{
$collector = new SecurityDataCollector();
$collector->collect($this->getRequest(), $this->getResponse());
$this->assertSame('security', $collector->getName());
$this->assertFalse($collector->isEnabled());
$this->assertFalse($collector->isAuthenticated());
$this->assertNull($collector->getTokenClass());
$this->assertFalse($collector->supportsRoleHierarchy());
$this->assertCount(0, $collector->getRoles());
$this->assertCount(0, $collector->getInheritedRoles());
$this->assertEmpty($collector->getUser());
$this->assertNull($collector->getFirewall());
}
public function testCollectWhenAuthenticationTokenIsNull()
{
$tokenStorage = new TokenStorage();
$collector = new SecurityDataCollector($tokenStorage, $this->getRoleHierarchy());
$collector->collect($this->getRequest(), $this->getResponse());
$this->assertTrue($collector->isEnabled());
$this->assertFalse($collector->isAuthenticated());
$this->assertNull($collector->getTokenClass());
$this->assertTrue($collector->supportsRoleHierarchy());
$this->assertCount(0, $collector->getRoles());
$this->assertCount(0, $collector->getInheritedRoles());
$this->assertEmpty($collector->getUser());
$this->assertNull($collector->getFirewall());
}
/** @dataProvider provideRoles */
public function testCollectAuthenticationTokenAndRoles(array $roles, array $normalizedRoles, array $inheritedRoles)
{
$tokenStorage = new TokenStorage();
$tokenStorage->setToken(new UsernamePasswordToken('hhamon', 'P4$$w0rD', 'provider', $roles));
$collector = new SecurityDataCollector($tokenStorage, $this->getRoleHierarchy());
$collector->collect($this->getRequest(), $this->getResponse());
$this->assertTrue($collector->isEnabled());
$this->assertTrue($collector->isAuthenticated());
$this->assertSame('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken', $collector->getTokenClass());
$this->assertTrue($collector->supportsRoleHierarchy());
$this->assertSame($normalizedRoles, $collector->getRoles()->getRawData()[1]);
if ($inheritedRoles) {
$this->assertSame($inheritedRoles, $collector->getInheritedRoles()->getRawData()[1]);
} else {
$this->assertSame($inheritedRoles, $collector->getInheritedRoles()->getRawData()[0][0]);
}
$this->assertSame('hhamon', $collector->getUser());
}
public function testGetFirewall()
{
$firewallConfig = new FirewallConfig('dummy', 'security.request_matcher.dummy', 'security.user_checker.dummy');
$request = $this->getRequest();
$firewallMap = $this
->getMockBuilder(FirewallMap::class)
->disableOriginalConstructor()
->getMock();
$firewallMap
->expects($this->once())
->method('getFirewallConfig')
->with($request)
->willReturn($firewallConfig);
$collector = new SecurityDataCollector(null, null, null, null, $firewallMap);
$collector->collect($request, $this->getResponse());
$collected = $collector->getFirewall();
$this->assertSame($firewallConfig->getName(), $collected['name']);
$this->assertSame($firewallConfig->allowsAnonymous(), $collected['allows_anonymous']);
$this->assertSame($firewallConfig->getRequestMatcher(), $collected['request_matcher']);
$this->assertSame($firewallConfig->isSecurityEnabled(), $collected['security_enabled']);
$this->assertSame($firewallConfig->isStateless(), $collected['stateless']);
$this->assertSame($firewallConfig->getProvider(), $collected['provider']);
$this->assertSame($firewallConfig->getContext(), $collected['context']);
$this->assertSame($firewallConfig->getEntryPoint(), $collected['entry_point']);
$this->assertSame($firewallConfig->getAccessDeniedHandler(), $collected['access_denied_handler']);
$this->assertSame($firewallConfig->getAccessDeniedUrl(), $collected['access_denied_url']);
$this->assertSame($firewallConfig->getUserChecker(), $collected['user_checker']);
$this->assertSame($firewallConfig->getListeners(), $collected['listeners']->getRawData()[0][0]);
}
public function testGetFirewallReturnsNull()
{
$request = $this->getRequest();
$response = $this->getResponse();
// Don't inject any firewall map
$collector = new SecurityDataCollector();
$collector->collect($request, $response);
$this->assertNull($collector->getFirewall());
// Inject an instance that is not context aware
$firewallMap = $this
->getMockBuilder(FirewallMapInterface::class)
->disableOriginalConstructor()
->getMock();
$collector = new SecurityDataCollector(null, null, null, null, $firewallMap);
$collector->collect($request, $response);
$this->assertNull($collector->getFirewall());
// Null config
$firewallMap = $this
->getMockBuilder(FirewallMap::class)
->disableOriginalConstructor()
->getMock();
$collector = new SecurityDataCollector(null, null, null, null, $firewallMap);
$collector->collect($request, $response);
$this->assertNull($collector->getFirewall());
}
public function provideRoles()
{
return array(
// Basic roles
array(
array('ROLE_USER'),
array('ROLE_USER'),
array(),
),
array(
array(new Role('ROLE_USER')),
array('ROLE_USER'),
array(),
),
// Inherited roles
array(
array('ROLE_ADMIN'),
array('ROLE_ADMIN'),
array('ROLE_USER', 'ROLE_ALLOWED_TO_SWITCH'),
),
array(
array(new Role('ROLE_ADMIN')),
array('ROLE_ADMIN'),
array('ROLE_USER', 'ROLE_ALLOWED_TO_SWITCH'),
),
array(
array('ROLE_ADMIN', 'ROLE_OPERATOR'),
array('ROLE_ADMIN', 'ROLE_OPERATOR'),
array('ROLE_USER', 'ROLE_ALLOWED_TO_SWITCH'),
),
);
}
private function getRoleHierarchy()
{
return new RoleHierarchy(array(
'ROLE_ADMIN' => array('ROLE_USER', 'ROLE_ALLOWED_TO_SWITCH'),
'ROLE_OPERATOR' => array('ROLE_USER'),
));
}
private function getRequest()
{
return $this
->getMockBuilder('Symfony\Component\HttpFoundation\Request')
->disableOriginalConstructor()
->getMock();
}
private function getResponse()
{
return $this
->getMockBuilder('Symfony\Component\HttpFoundation\Response')
->disableOriginalConstructor()
->getMock();
}
}

View File

@@ -0,0 +1,68 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\DependencyInjection\Compiler;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler\AddSecurityVotersPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
class AddSecurityVotersPassTest extends TestCase
{
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\LogicException
*/
public function testNoVoters()
{
$container = new ContainerBuilder();
$container
->register('security.access.decision_manager', 'Symfony\Component\Security\Core\Authorization\AccessDecisionManager')
->addArgument(array())
;
$compilerPass = new AddSecurityVotersPass();
$compilerPass->process($container);
}
public function testThatSecurityVotersAreProcessedInPriorityOrder()
{
$container = new ContainerBuilder();
$container
->register('security.access.decision_manager', 'Symfony\Component\Security\Core\Authorization\AccessDecisionManager')
->addArgument(array())
;
$container
->register('no_prio_service')
->addTag('security.voter')
;
$container
->register('lowest_prio_service')
->addTag('security.voter', array('priority' => 100))
;
$container
->register('highest_prio_service')
->addTag('security.voter', array('priority' => 200))
;
$container
->register('zero_prio_service')
->addTag('security.voter', array('priority' => 0))
;
$compilerPass = new AddSecurityVotersPass();
$compilerPass->process($container);
$calls = $container->getDefinition('security.access.decision_manager')->getMethodCalls();
$refs = $calls[0][1][0];
$this->assertEquals(new Reference('highest_prio_service'), $refs[0]);
$this->assertEquals(new Reference('lowest_prio_service'), $refs[1]);
$this->assertCount(4, $refs);
}
}

View File

@@ -0,0 +1,131 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\DependencyInjection\Compiler;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\FrameworkExtension;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler\AddSessionDomainConstraintPass;
use Symfony\Bundle\SecurityBundle\DependencyInjection\SecurityExtension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpFoundation\Request;
class AddSessionDomainConstraintPassTest extends TestCase
{
public function testSessionCookie()
{
$container = $this->createContainer(array('cookie_domain' => '.symfony.com.', 'cookie_secure' => true));
$utils = $container->get('security.http_utils');
$request = Request::create('/', 'get');
$this->assertTrue($utils->createRedirectResponse($request, 'https://symfony.com/blog')->isRedirect('https://symfony.com/blog'));
$this->assertTrue($utils->createRedirectResponse($request, 'https://www.symfony.com/blog')->isRedirect('https://www.symfony.com/blog'));
$this->assertTrue($utils->createRedirectResponse($request, 'https://localhost/foo')->isRedirect('https://localhost/foo'));
$this->assertTrue($utils->createRedirectResponse($request, 'https://www.localhost/foo')->isRedirect('http://localhost/'));
$this->assertTrue($utils->createRedirectResponse($request, 'http://symfony.com/blog')->isRedirect('http://localhost/'));
$this->assertTrue($utils->createRedirectResponse($request, 'http://pirate.com/foo')->isRedirect('http://localhost/'));
}
public function testSessionNoDomain()
{
$container = $this->createContainer(array('cookie_secure' => true));
$utils = $container->get('security.http_utils');
$request = Request::create('/', 'get');
$this->assertTrue($utils->createRedirectResponse($request, 'https://symfony.com/blog')->isRedirect('http://localhost/'));
$this->assertTrue($utils->createRedirectResponse($request, 'https://www.symfony.com/blog')->isRedirect('http://localhost/'));
$this->assertTrue($utils->createRedirectResponse($request, 'https://localhost/foo')->isRedirect('https://localhost/foo'));
$this->assertTrue($utils->createRedirectResponse($request, 'https://www.localhost/foo')->isRedirect('http://localhost/'));
$this->assertTrue($utils->createRedirectResponse($request, 'http://symfony.com/blog')->isRedirect('http://localhost/'));
$this->assertTrue($utils->createRedirectResponse($request, 'http://pirate.com/foo')->isRedirect('http://localhost/'));
}
public function testSessionNoSecure()
{
$container = $this->createContainer(array('cookie_domain' => '.symfony.com.'));
$utils = $container->get('security.http_utils');
$request = Request::create('/', 'get');
$this->assertTrue($utils->createRedirectResponse($request, 'https://symfony.com/blog')->isRedirect('https://symfony.com/blog'));
$this->assertTrue($utils->createRedirectResponse($request, 'https://www.symfony.com/blog')->isRedirect('https://www.symfony.com/blog'));
$this->assertTrue($utils->createRedirectResponse($request, 'https://localhost/foo')->isRedirect('https://localhost/foo'));
$this->assertTrue($utils->createRedirectResponse($request, 'https://www.localhost/foo')->isRedirect('http://localhost/'));
$this->assertTrue($utils->createRedirectResponse($request, 'http://symfony.com/blog')->isRedirect('http://symfony.com/blog'));
$this->assertTrue($utils->createRedirectResponse($request, 'http://pirate.com/foo')->isRedirect('http://localhost/'));
}
public function testSessionNoSecureAndNoDomain()
{
$container = $this->createContainer(array());
$utils = $container->get('security.http_utils');
$request = Request::create('/', 'get');
$this->assertTrue($utils->createRedirectResponse($request, 'https://symfony.com/blog')->isRedirect('http://localhost/'));
$this->assertTrue($utils->createRedirectResponse($request, 'https://www.symfony.com/blog')->isRedirect('http://localhost/'));
$this->assertTrue($utils->createRedirectResponse($request, 'https://localhost/foo')->isRedirect('https://localhost/foo'));
$this->assertTrue($utils->createRedirectResponse($request, 'http://localhost/foo')->isRedirect('http://localhost/foo'));
$this->assertTrue($utils->createRedirectResponse($request, 'https://www.localhost/foo')->isRedirect('http://localhost/'));
$this->assertTrue($utils->createRedirectResponse($request, 'http://symfony.com/blog')->isRedirect('http://localhost/'));
$this->assertTrue($utils->createRedirectResponse($request, 'http://pirate.com/foo')->isRedirect('http://localhost/'));
}
public function testNoSession()
{
$container = $this->createContainer(null);
$utils = $container->get('security.http_utils');
$request = Request::create('/', 'get');
$this->assertTrue($utils->createRedirectResponse($request, 'https://symfony.com/blog')->isRedirect('https://symfony.com/blog'));
$this->assertTrue($utils->createRedirectResponse($request, 'https://www.symfony.com/blog')->isRedirect('https://www.symfony.com/blog'));
$this->assertTrue($utils->createRedirectResponse($request, 'https://localhost/foo')->isRedirect('https://localhost/foo'));
$this->assertTrue($utils->createRedirectResponse($request, 'https://www.localhost/foo')->isRedirect('https://www.localhost/foo'));
$this->assertTrue($utils->createRedirectResponse($request, 'http://symfony.com/blog')->isRedirect('http://symfony.com/blog'));
$this->assertTrue($utils->createRedirectResponse($request, 'http://pirate.com/foo')->isRedirect('http://pirate.com/foo'));
}
private function createContainer($sessionStorageOptions)
{
$container = new ContainerBuilder();
$container->setParameter('kernel.cache_dir', __DIR__);
$container->setParameter('kernel.charset', 'UTF-8');
$container->setParameter('kernel.container_class', 'cc');
$container->setParameter('kernel.debug', true);
$container->setParameter('kernel.root_dir', __DIR__);
$container->setParameter('kernel.secret', __DIR__);
if (null !== $sessionStorageOptions) {
$container->setParameter('session.storage.options', $sessionStorageOptions);
}
$container->setParameter('request_listener.http_port', 80);
$container->setParameter('request_listener.https_port', 443);
$config = array(
'security' => array(
'providers' => array('some_provider' => array('id' => 'foo')),
'firewalls' => array('some_firewall' => array('security' => false)),
),
);
$ext = new FrameworkExtension();
$ext->load(array(), $container);
$ext = new SecurityExtension();
$ext->load($config, $container);
(new AddSessionDomainConstraintPass())->process($container);
return $container;
}
}

View File

@@ -0,0 +1,359 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Bundle\SecurityBundle\SecurityBundle;
use Symfony\Bundle\SecurityBundle\DependencyInjection\SecurityExtension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
abstract class CompleteConfigurationTest extends TestCase
{
private static $containerCache = array();
abstract protected function getLoader(ContainerBuilder $container);
abstract protected function getFileExtension();
public function testRolesHierarchy()
{
$container = $this->getContainer('container1');
$this->assertEquals(array(
'ROLE_ADMIN' => array('ROLE_USER'),
'ROLE_SUPER_ADMIN' => array('ROLE_USER', 'ROLE_ADMIN', 'ROLE_ALLOWED_TO_SWITCH'),
'ROLE_REMOTE' => array('ROLE_USER', 'ROLE_ADMIN'),
), $container->getParameter('security.role_hierarchy.roles'));
}
public function testUserProviders()
{
$container = $this->getContainer('container1');
$providers = array_values(array_filter($container->getServiceIds(), function ($key) { return 0 === strpos($key, 'security.user.provider.concrete'); }));
$expectedProviders = array(
'security.user.provider.concrete.default',
'security.user.provider.concrete.default_foo',
'security.user.provider.concrete.digest',
'security.user.provider.concrete.digest_foo',
'security.user.provider.concrete.basic',
'security.user.provider.concrete.basic_foo',
'security.user.provider.concrete.basic_bar',
'security.user.provider.concrete.service',
'security.user.provider.concrete.chain',
);
$this->assertEquals(array(), array_diff($expectedProviders, $providers));
$this->assertEquals(array(), array_diff($providers, $expectedProviders));
// chain provider
$this->assertEquals(array(array(
new Reference('security.user.provider.concrete.service'),
new Reference('security.user.provider.concrete.basic'),
)), $container->getDefinition('security.user.provider.concrete.chain')->getArguments());
}
public function testFirewalls()
{
$container = $this->getContainer('container1');
$arguments = $container->getDefinition('security.firewall.map')->getArguments();
$listeners = array();
$configs = array();
foreach (array_keys($arguments[1]) as $contextId) {
$contextDef = $container->getDefinition($contextId);
$arguments = $contextDef->getArguments();
$listeners[] = array_map('strval', $arguments['index_0']);
$configDef = $container->getDefinition((string) $arguments['index_2']);
$configs[] = array_values($configDef->getArguments());
}
$this->assertEquals(array(
array(
'simple',
'security.user_checker',
'security.request_matcher.707b20193d4cb9f2718114abcbebb32af48f948484fc166a03482f49bf14f25e271f72c7',
false,
),
array(
'secure',
'security.user_checker',
null,
true,
true,
'security.user.provider.concrete.default',
null,
'security.authentication.form_entry_point.secure',
null,
null,
array(
'logout',
'switch_user',
'x509',
'remote_user',
'form_login',
'http_basic',
'http_digest',
'remember_me',
'anonymous',
),
),
array(
'host',
'security.user_checker',
'security.request_matcher.dda8b565689ad8509623ee68fb2c639cd81cd4cb339d60edbaf7d67d30e6aa09bd8c63c3',
true,
false,
'security.user.provider.concrete.default',
'host',
'security.authentication.basic_entry_point.host',
null,
null,
array(
'http_basic',
'anonymous',
),
),
array(
'with_user_checker',
'app.user_checker',
null,
true,
false,
'security.user.provider.concrete.default',
'with_user_checker',
'security.authentication.basic_entry_point.with_user_checker',
null,
null,
array(
'http_basic',
'anonymous',
),
),
), $configs);
$this->assertEquals(array(
array(),
array(
'security.channel_listener',
'security.logout_listener.secure',
'security.authentication.listener.x509.secure',
'security.authentication.listener.remote_user.secure',
'security.authentication.listener.form.secure',
'security.authentication.listener.basic.secure',
'security.authentication.listener.digest.secure',
'security.authentication.listener.rememberme.secure',
'security.authentication.listener.anonymous.secure',
'security.authentication.switchuser_listener.secure',
'security.access_listener',
),
array(
'security.channel_listener',
'security.context_listener.0',
'security.authentication.listener.basic.host',
'security.authentication.listener.anonymous.host',
'security.access_listener',
),
array(
'security.channel_listener',
'security.context_listener.1',
'security.authentication.listener.basic.with_user_checker',
'security.authentication.listener.anonymous.with_user_checker',
'security.access_listener',
),
), $listeners);
}
public function testFirewallRequestMatchers()
{
$container = $this->getContainer('container1');
$arguments = $container->getDefinition('security.firewall.map')->getArguments();
$matchers = array();
foreach ($arguments[1] as $reference) {
if ($reference instanceof Reference) {
$definition = $container->getDefinition((string) $reference);
$matchers[] = $definition->getArguments();
}
}
$this->assertEquals(array(
array(
'/login',
),
array(
'/test',
'foo\\.example\\.org',
array('GET', 'POST'),
),
), $matchers);
}
public function testAccess()
{
$container = $this->getContainer('container1');
$rules = array();
foreach ($container->getDefinition('security.access_map')->getMethodCalls() as $call) {
if ($call[0] == 'add') {
$rules[] = array((string) $call[1][0], $call[1][1], $call[1][2]);
}
}
$matcherIds = array();
foreach ($rules as list($matcherId, $attributes, $channel)) {
$requestMatcher = $container->getDefinition($matcherId);
$this->assertFalse(isset($matcherIds[$matcherId]));
$matcherIds[$matcherId] = true;
$i = count($matcherIds);
if (1 === $i) {
$this->assertEquals(array('ROLE_USER'), $attributes);
$this->assertEquals('https', $channel);
$this->assertEquals(
array('/blog/524', null, array('GET', 'POST')),
$requestMatcher->getArguments()
);
} elseif (2 === $i) {
$this->assertEquals(array('IS_AUTHENTICATED_ANONYMOUSLY'), $attributes);
$this->assertNull($channel);
$this->assertEquals(
array('/blog/.*'),
$requestMatcher->getArguments()
);
} elseif (3 === $i) {
$this->assertEquals('IS_AUTHENTICATED_ANONYMOUSLY', $attributes[0]);
$expression = $container->getDefinition((string) $attributes[1])->getArgument(0);
$this->assertEquals("token.getUsername() matches '/^admin/'", $expression);
}
}
}
public function testMerge()
{
$container = $this->getContainer('merge');
$this->assertEquals(array(
'FOO' => array('MOO'),
'ADMIN' => array('USER'),
), $container->getParameter('security.role_hierarchy.roles'));
}
public function testEncoders()
{
$container = $this->getContainer('container1');
$this->assertEquals(array(array(
'JMS\FooBundle\Entity\User1' => array(
'class' => 'Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder',
'arguments' => array(false),
),
'JMS\FooBundle\Entity\User2' => array(
'algorithm' => 'sha1',
'encode_as_base64' => false,
'iterations' => 5,
'hash_algorithm' => 'sha512',
'key_length' => 40,
'ignore_case' => false,
'cost' => 13,
),
'JMS\FooBundle\Entity\User3' => array(
'algorithm' => 'md5',
'hash_algorithm' => 'sha512',
'key_length' => 40,
'ignore_case' => false,
'encode_as_base64' => true,
'iterations' => 5000,
'cost' => 13,
),
'JMS\FooBundle\Entity\User4' => new Reference('security.encoder.foo'),
'JMS\FooBundle\Entity\User5' => array(
'class' => 'Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder',
'arguments' => array('sha1', false, 5, 30),
),
'JMS\FooBundle\Entity\User6' => array(
'class' => 'Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder',
'arguments' => array(15),
),
)), $container->getDefinition('security.encoder_factory.generic')->getArguments());
}
public function testAcl()
{
$container = $this->getContainer('container1');
$this->assertTrue($container->hasDefinition('security.acl.dbal.provider'));
$this->assertEquals('security.acl.dbal.provider', (string) $container->getAlias('security.acl.provider'));
}
public function testCustomAclProvider()
{
$container = $this->getContainer('custom_acl_provider');
$this->assertFalse($container->hasDefinition('security.acl.dbal.provider'));
$this->assertEquals('foo', (string) $container->getAlias('security.acl.provider'));
}
public function testRememberMeThrowExceptionsDefault()
{
$container = $this->getContainer('container1');
$this->assertTrue($container->getDefinition('security.authentication.listener.rememberme.secure')->getArgument(5));
}
public function testRememberMeThrowExceptions()
{
$container = $this->getContainer('remember_me_options');
$service = $container->getDefinition('security.authentication.listener.rememberme.main');
$this->assertEquals('security.authentication.rememberme.services.persistent.main', $service->getArgument(1));
$this->assertFalse($service->getArgument(5));
}
public function testUserCheckerConfig()
{
$this->assertEquals('app.user_checker', $this->getContainer('container1')->getAlias('security.user_checker.with_user_checker'));
}
public function testUserCheckerConfigWithDefaultChecker()
{
$this->assertEquals('security.user_checker', $this->getContainer('container1')->getAlias('security.user_checker.host'));
}
public function testUserCheckerConfigWithNoCheckers()
{
$this->assertEquals('security.user_checker', $this->getContainer('container1')->getAlias('security.user_checker.secure'));
}
protected function getContainer($file)
{
$file = $file.'.'.$this->getFileExtension();
if (isset(self::$containerCache[$file])) {
return self::$containerCache[$file];
}
$container = new ContainerBuilder();
$security = new SecurityExtension();
$container->registerExtension($security);
$bundle = new SecurityBundle();
$bundle->build($container); // Attach all default factories
$this->getLoader($container)->load($file);
$container->getCompilerPassConfig()->setOptimizationPasses(array());
$container->getCompilerPassConfig()->setRemovingPasses(array());
$container->compile();
return self::$containerCache[$file] = $container;
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Symfony\Bundle\SecurityBundle\Tests\DependencyInjection\Fixtures\UserProvider;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\UserProviderFactoryInterface;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class DummyProvider implements UserProviderFactoryInterface
{
public function create(ContainerBuilder $container, $id, $config)
{
}
public function getKey()
{
return 'foo';
}
public function addConfiguration(NodeDefinition $node)
{
}
}

View File

@@ -0,0 +1,102 @@
<?php
$container->loadFromExtension('security', array(
'acl' => array(),
'encoders' => array(
'JMS\FooBundle\Entity\User1' => 'plaintext',
'JMS\FooBundle\Entity\User2' => array(
'algorithm' => 'sha1',
'encode_as_base64' => false,
'iterations' => 5,
),
'JMS\FooBundle\Entity\User3' => array(
'algorithm' => 'md5',
),
'JMS\FooBundle\Entity\User4' => array(
'id' => 'security.encoder.foo',
),
'JMS\FooBundle\Entity\User5' => array(
'algorithm' => 'pbkdf2',
'hash_algorithm' => 'sha1',
'encode_as_base64' => false,
'iterations' => 5,
'key_length' => 30,
),
'JMS\FooBundle\Entity\User6' => array(
'algorithm' => 'bcrypt',
'cost' => 15,
),
),
'providers' => array(
'default' => array(
'memory' => array(
'users' => array(
'foo' => array('password' => 'foo', 'roles' => 'ROLE_USER'),
),
),
),
'digest' => array(
'memory' => array(
'users' => array(
'foo' => array('password' => 'foo', 'roles' => 'ROLE_USER, ROLE_ADMIN'),
),
),
),
'basic' => array(
'memory' => array(
'users' => array(
'foo' => array('password' => '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', 'roles' => 'ROLE_SUPER_ADMIN'),
'bar' => array('password' => '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', 'roles' => array('ROLE_USER', 'ROLE_ADMIN')),
),
),
),
'service' => array(
'id' => 'user.manager',
),
'chain' => array(
'chain' => array(
'providers' => array('service', 'basic'),
),
),
),
'firewalls' => array(
'simple' => array('pattern' => '/login', 'security' => false),
'secure' => array('stateless' => true,
'http_basic' => true,
'http_digest' => array('secret' => 'TheSecret'),
'form_login' => true,
'anonymous' => true,
'switch_user' => true,
'x509' => true,
'remote_user' => true,
'logout' => true,
'remember_me' => array('secret' => 'TheSecret'),
'user_checker' => null,
),
'host' => array(
'pattern' => '/test',
'host' => 'foo\\.example\\.org',
'methods' => array('GET', 'POST'),
'anonymous' => true,
'http_basic' => true,
),
'with_user_checker' => array(
'user_checker' => 'app.user_checker',
'anonymous' => true,
'http_basic' => true,
),
),
'access_control' => array(
array('path' => '/blog/524', 'role' => 'ROLE_USER', 'requires_channel' => 'https', 'methods' => array('get', 'POST')),
array('path' => '/blog/.*', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY'),
array('path' => '/blog/524', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY', 'allow_if' => "token.getUsername() matches '/^admin/'"),
),
'role_hierarchy' => array(
'ROLE_ADMIN' => 'ROLE_USER',
'ROLE_SUPER_ADMIN' => array('ROLE_USER', 'ROLE_ADMIN', 'ROLE_ALLOWED_TO_SWITCH'),
'ROLE_REMOTE' => 'ROLE_USER,ROLE_ADMIN',
),
));

View File

@@ -0,0 +1,9 @@
<?php
$this->load('container1.php', $container);
$container->loadFromExtension('security', array(
'acl' => array(
'provider' => 'foo',
),
));

View File

@@ -0,0 +1,20 @@
<?php
$this->load('merge_import.php', $container);
$container->loadFromExtension('security', array(
'providers' => array(
'default' => array('id' => 'foo'),
),
'firewalls' => array(
'main' => array(
'form_login' => false,
'http_basic' => null,
),
),
'role_hierarchy' => array(
'FOO' => array('MOO'),
),
));

View File

@@ -0,0 +1,15 @@
<?php
$container->loadFromExtension('security', array(
'firewalls' => array(
'main' => array(
'form_login' => array(
'login_path' => '/login',
),
),
),
'role_hierarchy' => array(
'FOO' => 'BAR',
'ADMIN' => 'USER',
),
));

View File

@@ -0,0 +1,18 @@
<?php
$container->loadFromExtension('security', array(
'providers' => array(
'default' => array('id' => 'foo'),
),
'firewalls' => array(
'main' => array(
'form_login' => true,
'remember_me' => array(
'secret' => 'TheSecret',
'catch_exceptions' => false,
'token_provider' => 'token_provider_id',
),
),
),
));

View File

@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<srv:container xmlns="http://symfony.com/schema/dic/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:srv="http://symfony.com/schema/dic/services"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<config>
<acl />
<encoder class="JMS\FooBundle\Entity\User1" algorithm="plaintext" />
<encoder class="JMS\FooBundle\Entity\User2" algorithm="sha1" encode-as-base64="false" iterations="5" />
<encoder class="JMS\FooBundle\Entity\User3" algorithm="md5" />
<encoder class="JMS\FooBundle\Entity\User4" id="security.encoder.foo" />
<encoder class="JMS\FooBundle\Entity\User5" algorithm="pbkdf2" hash-algorithm="sha1" encode-as-base64="false" iterations="5" key-length="30" />
<encoder class="JMS\FooBundle\Entity\User6" algorithm="bcrypt" cost="15" />
<provider name="default">
<memory>
<user name="foo" password="foo" roles="ROLE_USER" />
</memory>
</provider>
<provider name="digest">
<memory>
<user name="foo" password="foo" roles="ROLE_USER, ROLE_ADMIN" />
</memory>
</provider>
<provider name="basic">
<memory>
<user name="foo" password="0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33" roles="ROLE_SUPER_ADMIN" />
<user name="bar" password="0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33" roles="ROLE_USER, ROLE_ADMIN" />
</memory>
</provider>
<provider name="service" id="user.manager" />
<provider name="chain">
<chain providers="service, basic" />
</provider>
<firewall name="simple" pattern="/login" security="false" />
<firewall name="secure" stateless="true">
<http-basic />
<http-digest secret="TheSecret" />
<form-login />
<anonymous />
<switch-user />
<x509 />
<remote-user />
<user-checker />
<logout />
<remember-me secret="TheSecret"/>
</firewall>
<firewall name="host" pattern="/test" host="foo\.example\.org" methods="GET,POST">
<anonymous />
<http-basic />
</firewall>
<firewall name="with_user_checker">
<anonymous />
<http-basic />
<user-checker>app.user_checker</user-checker>
</firewall>
<role id="ROLE_ADMIN">ROLE_USER</role>
<role id="ROLE_SUPER_ADMIN">ROLE_USER,ROLE_ADMIN,ROLE_ALLOWED_TO_SWITCH</role>
<role id="ROLE_REMOTE">ROLE_USER,ROLE_ADMIN</role>
<rule path="/blog/524" role="ROLE_USER" requires-channel="https" methods="get,POST" />
<rule role='IS_AUTHENTICATED_ANONYMOUSLY' path="/blog/.*" />
<rule role='IS_AUTHENTICATED_ANONYMOUSLY' allow-if="token.getUsername() matches '/^admin/'" path="/blog/524" />
</config>
</srv:container>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sec="http://symfony.com/schema/dic/security"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<imports>
<import resource="container1.xml"/>
</imports>
<sec:config>
<sec:acl provider="foo" />
</sec:config>
</container>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sec="http://symfony.com/schema/dic/security"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<imports>
<import resource="merge_import.xml"/>
</imports>
<sec:config>
<sec:provider name="default" id="foo" />
<sec:firewall name="main" form-login="false">
<sec:http-basic />
</sec:firewall>
<sec:role id="FOO" value="MOO" />
</sec:config>
</container>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<srv:container xmlns="http://symfony.com/schema/dic/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:srv="http://symfony.com/schema/dic/services"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<config>
<firewall name="main">
<form-login login-path="/login" />
</firewall>
<role id="FOO" value="BAR" />
<role id="ADMIN" value="USER" />
</config>
</srv:container>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sec="http://symfony.com/schema/dic/security"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<sec:config>
<sec:providers>
<sec:default id="foo"/>
</sec:providers>
<sec:firewall name="main">
<sec:form-login/>
<sec:remember-me secret="TheSecret" catch-exceptions="false" token-provider="token_provider_id" />
</sec:firewall>
</sec:config>
</container>

View File

@@ -0,0 +1,83 @@
security:
acl: ~
encoders:
JMS\FooBundle\Entity\User1: plaintext
JMS\FooBundle\Entity\User2:
algorithm: sha1
encode_as_base64: false
iterations: 5
JMS\FooBundle\Entity\User3:
algorithm: md5
JMS\FooBundle\Entity\User4:
id: security.encoder.foo
JMS\FooBundle\Entity\User5:
algorithm: pbkdf2
hash_algorithm: sha1
encode_as_base64: false
iterations: 5
key_length: 30
JMS\FooBundle\Entity\User6:
algorithm: bcrypt
cost: 15
providers:
default:
memory:
users:
foo: { password: foo, roles: ROLE_USER }
digest:
memory:
users:
foo: { password: foo, roles: 'ROLE_USER, ROLE_ADMIN' }
basic:
memory:
users:
foo: { password: 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33, roles: ROLE_SUPER_ADMIN }
bar: { password: 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33, roles: [ROLE_USER, ROLE_ADMIN] }
service:
id: user.manager
chain:
chain:
providers: [service, basic]
firewalls:
simple: { pattern: /login, security: false }
secure:
stateless: true
http_basic: true
http_digest:
secret: TheSecret
form_login: true
anonymous: true
switch_user: true
x509: true
remote_user: true
logout: true
remember_me:
secret: TheSecret
user_checker: ~
host:
pattern: /test
host: foo\.example\.org
methods: [GET,POST]
anonymous: true
http_basic: true
with_user_checker:
anonymous: ~
http_basic: ~
user_checker: app.user_checker
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
ROLE_REMOTE: ROLE_USER,ROLE_ADMIN
access_control:
- { path: /blog/524, role: ROLE_USER, requires_channel: https, methods: [get, POST]}
-
path: /blog/.*
role: IS_AUTHENTICATED_ANONYMOUSLY
- { path: /blog/524, role: IS_AUTHENTICATED_ANONYMOUSLY, allow_if: "token.getUsername() matches '/^admin/'" }

View File

@@ -0,0 +1,6 @@
imports:
- { resource: container1.yml }
security:
acl:
provider: foo

View File

@@ -0,0 +1,14 @@
imports:
- { resource: merge_import.yml }
security:
providers:
default: { id: foo }
firewalls:
main:
form_login: false
http_basic: ~
role_hierarchy:
FOO: [MOO]

View File

@@ -0,0 +1,9 @@
security:
firewalls:
main:
form_login:
login_path: /login
role_hierarchy:
FOO: BAR
ADMIN: USER

View File

@@ -0,0 +1,12 @@
security:
providers:
default:
id: foo
firewalls:
main:
form_login: true
remember_me:
secret: TheSecret
catch_exceptions: false
token_provider: token_provider_id

View File

@@ -0,0 +1,121 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\SecurityBundle\DependencyInjection\MainConfiguration;
use Symfony\Component\Config\Definition\Processor;
class MainConfigurationTest extends TestCase
{
/**
* The minimal, required config needed to not have any required validation
* issues.
*
* @var array
*/
protected static $minimalConfig = array(
'providers' => array(
'stub' => array(
'id' => 'foo',
),
),
'firewalls' => array(
'stub' => array(),
),
);
/**
* @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
*/
public function testNoConfigForProvider()
{
$config = array(
'providers' => array(
'stub' => array(),
),
);
$processor = new Processor();
$configuration = new MainConfiguration(array(), array());
$processor->processConfiguration($configuration, array($config));
}
/**
* @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
*/
public function testManyConfigForProvider()
{
$config = array(
'providers' => array(
'stub' => array(
'id' => 'foo',
'chain' => array(),
),
),
);
$processor = new Processor();
$configuration = new MainConfiguration(array(), array());
$processor->processConfiguration($configuration, array($config));
}
public function testCsrfAliases()
{
$config = array(
'firewalls' => array(
'stub' => array(
'logout' => array(
'csrf_token_generator' => 'a_token_generator',
'csrf_token_id' => 'a_token_id',
),
),
),
);
$config = array_merge(static::$minimalConfig, $config);
$processor = new Processor();
$configuration = new MainConfiguration(array(), array());
$processedConfig = $processor->processConfiguration($configuration, array($config));
$this->assertTrue(isset($processedConfig['firewalls']['stub']['logout']['csrf_token_generator']));
$this->assertEquals('a_token_generator', $processedConfig['firewalls']['stub']['logout']['csrf_token_generator']);
$this->assertTrue(isset($processedConfig['firewalls']['stub']['logout']['csrf_token_id']));
$this->assertEquals('a_token_id', $processedConfig['firewalls']['stub']['logout']['csrf_token_id']);
}
public function testDefaultUserCheckers()
{
$processor = new Processor();
$configuration = new MainConfiguration(array(), array());
$processedConfig = $processor->processConfiguration($configuration, array(static::$minimalConfig));
$this->assertEquals('security.user_checker', $processedConfig['firewalls']['stub']['user_checker']);
}
public function testUserCheckers()
{
$config = array(
'firewalls' => array(
'stub' => array(
'user_checker' => 'app.henk_checker',
),
),
);
$config = array_merge(static::$minimalConfig, $config);
$processor = new Processor();
$configuration = new MainConfiguration(array(), array());
$processedConfig = $processor->processConfiguration($configuration, array($config));
$this->assertEquals('app.henk_checker', $processedConfig['firewalls']['stub']['user_checker']);
}
}

View File

@@ -0,0 +1,29 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
use Symfony\Component\Config\FileLocator;
class PhpCompleteConfigurationTest extends CompleteConfigurationTest
{
protected function getLoader(ContainerBuilder $container)
{
return new PhpFileLoader($container, new FileLocator(__DIR__.'/Fixtures/php'));
}
protected function getFileExtension()
{
return 'php';
}
}

View File

@@ -0,0 +1,157 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\DependencyInjection\Security\Factory;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class AbstractFactoryTest extends TestCase
{
public function testCreate()
{
list($container, $authProviderId, $listenerId, $entryPointId) = $this->callFactory('foo', array(
'use_forward' => true,
'failure_path' => '/foo',
'success_handler' => 'custom_success_handler',
'failure_handler' => 'custom_failure_handler',
'remember_me' => true,
), 'user_provider', 'entry_point');
// auth provider
$this->assertEquals('auth_provider', $authProviderId);
// listener
$this->assertEquals('abstract_listener.foo', $listenerId);
$this->assertTrue($container->hasDefinition('abstract_listener.foo'));
$definition = $container->getDefinition('abstract_listener.foo');
$this->assertEquals(array(
'index_4' => 'foo',
'index_5' => new Reference('security.authentication.success_handler.foo.abstract_factory'),
'index_6' => new Reference('security.authentication.failure_handler.foo.abstract_factory'),
'index_7' => array(
'use_forward' => true,
),
), $definition->getArguments());
// entry point
$this->assertEquals('entry_point', $entryPointId, '->create() does not change the default entry point.');
}
/**
* @dataProvider getFailureHandlers
*/
public function testDefaultFailureHandler($serviceId, $defaultHandlerInjection)
{
$options = array(
'remember_me' => true,
'login_path' => '/bar',
);
if ($serviceId) {
$options['failure_handler'] = $serviceId;
}
list($container, $authProviderId, $listenerId, $entryPointId) = $this->callFactory('foo', $options, 'user_provider', 'entry_point');
$definition = $container->getDefinition('abstract_listener.foo');
$arguments = $definition->getArguments();
$this->assertEquals(new Reference('security.authentication.failure_handler.foo.abstract_factory'), $arguments['index_6']);
$failureHandler = $container->findDefinition((string) $arguments['index_6']);
$methodCalls = $failureHandler->getMethodCalls();
if ($defaultHandlerInjection) {
$this->assertEquals('setOptions', $methodCalls[0][0]);
$this->assertEquals(array('login_path' => '/bar'), $methodCalls[0][1][0]);
} else {
$this->assertCount(0, $methodCalls);
}
}
public function getFailureHandlers()
{
return array(
array(null, true),
array('custom_failure_handler', false),
);
}
/**
* @dataProvider getSuccessHandlers
*/
public function testDefaultSuccessHandler($serviceId, $defaultHandlerInjection)
{
$options = array(
'remember_me' => true,
'default_target_path' => '/bar',
);
if ($serviceId) {
$options['success_handler'] = $serviceId;
}
list($container, $authProviderId, $listenerId, $entryPointId) = $this->callFactory('foo', $options, 'user_provider', 'entry_point');
$definition = $container->getDefinition('abstract_listener.foo');
$arguments = $definition->getArguments();
$this->assertEquals(new Reference('security.authentication.success_handler.foo.abstract_factory'), $arguments['index_5']);
$successHandler = $container->findDefinition((string) $arguments['index_5']);
$methodCalls = $successHandler->getMethodCalls();
if ($defaultHandlerInjection) {
$this->assertEquals('setOptions', $methodCalls[0][0]);
$this->assertEquals(array('default_target_path' => '/bar'), $methodCalls[0][1][0]);
$this->assertEquals('setProviderKey', $methodCalls[1][0]);
$this->assertEquals(array('foo'), $methodCalls[1][1]);
} else {
$this->assertCount(0, $methodCalls);
}
}
public function getSuccessHandlers()
{
return array(
array(null, true),
array('custom_success_handler', false),
);
}
protected function callFactory($id, $config, $userProviderId, $defaultEntryPointId)
{
$factory = $this->getMockForAbstractClass('Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AbstractFactory', array());
$factory
->expects($this->once())
->method('createAuthProvider')
->will($this->returnValue('auth_provider'))
;
$factory
->expects($this->atLeastOnce())
->method('getListenerId')
->will($this->returnValue('abstract_listener'))
;
$factory
->expects($this->any())
->method('getKey')
->will($this->returnValue('abstract_factory'))
;
$container = new ContainerBuilder();
$container->register('auth_provider');
$container->register('custom_success_handler');
$container->register('custom_failure_handler');
list($authProviderId, $listenerId, $entryPointId) = $factory->create($container, $id, $config, $userProviderId, $defaultEntryPointId);
return array($container, $authProviderId, $listenerId, $entryPointId);
}
}

View File

@@ -0,0 +1,182 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\DependencyInjection\Security\Factory;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\GuardAuthenticationFactory;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
class GuardAuthenticationFactoryTest extends TestCase
{
/**
* @dataProvider getValidConfigurationTests
*/
public function testAddValidConfiguration(array $inputConfig, array $expectedConfig)
{
$factory = new GuardAuthenticationFactory();
$nodeDefinition = new ArrayNodeDefinition('guard');
$factory->addConfiguration($nodeDefinition);
$node = $nodeDefinition->getNode();
$normalizedConfig = $node->normalize($inputConfig);
$finalizedConfig = $node->finalize($normalizedConfig);
$this->assertEquals($expectedConfig, $finalizedConfig);
}
/**
* @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
* @dataProvider getInvalidConfigurationTests
*/
public function testAddInvalidConfiguration(array $inputConfig)
{
$factory = new GuardAuthenticationFactory();
$nodeDefinition = new ArrayNodeDefinition('guard');
$factory->addConfiguration($nodeDefinition);
$node = $nodeDefinition->getNode();
$normalizedConfig = $node->normalize($inputConfig);
// will validate and throw an exception on invalid
$node->finalize($normalizedConfig);
}
public function getValidConfigurationTests()
{
$tests = array();
// completely basic
$tests[] = array(
array(
'authenticators' => array('authenticator1', 'authenticator2'),
'provider' => 'some_provider',
'entry_point' => 'the_entry_point',
),
array(
'authenticators' => array('authenticator1', 'authenticator2'),
'provider' => 'some_provider',
'entry_point' => 'the_entry_point',
),
);
// testing xml config fix: authenticator -> authenticators
$tests[] = array(
array(
'authenticator' => array('authenticator1', 'authenticator2'),
),
array(
'authenticators' => array('authenticator1', 'authenticator2'),
'entry_point' => null,
),
);
return $tests;
}
public function getInvalidConfigurationTests()
{
$tests = array();
// testing not empty
$tests[] = array(
array('authenticators' => array()),
);
return $tests;
}
public function testBasicCreate()
{
// simple configuration
$config = array(
'authenticators' => array('authenticator123'),
'entry_point' => null,
);
list($container, $entryPointId) = $this->executeCreate($config, null);
$this->assertEquals('authenticator123', $entryPointId);
$providerDefinition = $container->getDefinition('security.authentication.provider.guard.my_firewall');
$this->assertEquals(array(
'index_0' => array(new Reference('authenticator123')),
'index_1' => new Reference('my_user_provider'),
'index_2' => 'my_firewall',
'index_3' => new Reference('security.user_checker.my_firewall'),
), $providerDefinition->getArguments());
$listenerDefinition = $container->getDefinition('security.authentication.listener.guard.my_firewall');
$this->assertEquals('my_firewall', $listenerDefinition->getArgument(2));
$this->assertEquals(array(new Reference('authenticator123')), $listenerDefinition->getArgument(3));
}
public function testExistingDefaultEntryPointUsed()
{
// any existing default entry point is used
$config = array(
'authenticators' => array('authenticator123'),
'entry_point' => null,
);
list(, $entryPointId) = $this->executeCreate($config, 'some_default_entry_point');
$this->assertEquals('some_default_entry_point', $entryPointId);
}
/**
* @expectedException \LogicException
*/
public function testCannotOverrideDefaultEntryPoint()
{
// any existing default entry point is used
$config = array(
'authenticators' => array('authenticator123'),
'entry_point' => 'authenticator123',
);
$this->executeCreate($config, 'some_default_entry_point');
}
/**
* @expectedException \LogicException
*/
public function testMultipleAuthenticatorsRequiresEntryPoint()
{
// any existing default entry point is used
$config = array(
'authenticators' => array('authenticator123', 'authenticatorABC'),
'entry_point' => null,
);
$this->executeCreate($config, null);
}
public function testCreateWithEntryPoint()
{
// any existing default entry point is used
$config = array(
'authenticators' => array('authenticator123', 'authenticatorABC'),
'entry_point' => 'authenticatorABC',
);
list($container, $entryPointId) = $this->executeCreate($config, null);
$this->assertEquals('authenticatorABC', $entryPointId);
}
private function executeCreate(array $config, $defaultEntryPointId)
{
$container = new ContainerBuilder();
$container->register('security.authentication.provider.guard');
$container->register('security.authentication.listener.guard');
$id = 'my_firewall';
$userProviderId = 'my_user_provider';
$factory = new GuardAuthenticationFactory();
list($providerId, $listenerId, $entryPointId) = $factory->create($container, $id, $config, $userProviderId, $defaultEntryPointId);
return array($container, $entryPointId);
}
}

View File

@@ -0,0 +1,144 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\SecurityBundle\DependencyInjection\SecurityExtension;
use Symfony\Bundle\SecurityBundle\SecurityBundle;
use Symfony\Bundle\SecurityBundle\Tests\DependencyInjection\Fixtures\UserProvider\DummyProvider;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class SecurityExtensionTest extends TestCase
{
/**
* @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
* @expectedExceptionMessage The check_path "/some_area/login_check" for login method "form_login" is not matched by the firewall pattern "/secured_area/.*".
*/
public function testInvalidCheckPath()
{
$container = $this->getRawContainer();
$container->loadFromExtension('security', array(
'providers' => array(
'default' => array('id' => 'foo'),
),
'firewalls' => array(
'some_firewall' => array(
'pattern' => '/secured_area/.*',
'form_login' => array(
'check_path' => '/some_area/login_check',
),
),
),
));
$container->compile();
}
/**
* @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
* @expectedExceptionMessage No authentication listener registered for firewall "some_firewall"
*/
public function testFirewallWithoutAuthenticationListener()
{
$container = $this->getRawContainer();
$container->loadFromExtension('security', array(
'providers' => array(
'default' => array('id' => 'foo'),
),
'firewalls' => array(
'some_firewall' => array(
'pattern' => '/.*',
),
),
));
$container->compile();
}
/**
* @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
* @expectedExceptionMessage Unable to create definition for "security.user.provider.concrete.my_foo" user provider
*/
public function testFirewallWithInvalidUserProvider()
{
$container = $this->getRawContainer();
$extension = $container->getExtension('security');
$extension->addUserProviderFactory(new DummyProvider());
$container->loadFromExtension('security', array(
'providers' => array(
'my_foo' => array('foo' => array()),
),
'firewalls' => array(
'some_firewall' => array(
'pattern' => '/.*',
'http_basic' => array(),
),
),
));
$container->compile();
}
public function testDisableRoleHierarchyVoter()
{
$container = $this->getRawContainer();
$container->loadFromExtension('security', array(
'providers' => array(
'default' => array('id' => 'foo'),
),
'role_hierarchy' => null,
'firewalls' => array(
'some_firewall' => array(
'pattern' => '/.*',
'http_basic' => null,
),
),
));
$container->compile();
$this->assertFalse($container->hasDefinition('security.access.role_hierarchy_voter'));
}
protected function getRawContainer()
{
$container = new ContainerBuilder();
$security = new SecurityExtension();
$container->registerExtension($security);
$bundle = new SecurityBundle();
$bundle->build($container);
$container->getCompilerPassConfig()->setOptimizationPasses(array());
$container->getCompilerPassConfig()->setRemovingPasses(array());
return $container;
}
protected function getContainer()
{
$container = $this->getRawContainer();
$container->compile();
return $container;
}
}

View File

@@ -0,0 +1,29 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\Config\FileLocator;
class XmlCompleteConfigurationTest extends CompleteConfigurationTest
{
protected function getLoader(ContainerBuilder $container)
{
return new XmlFileLoader($container, new FileLocator(__DIR__.'/Fixtures/xml'));
}
protected function getFileExtension()
{
return 'xml';
}
}

View File

@@ -0,0 +1,29 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\Config\FileLocator;
class YamlCompleteConfigurationTest extends CompleteConfigurationTest
{
protected function getLoader(ContainerBuilder $container)
{
return new YamlFileLoader($container, new FileLocator(__DIR__.'/Fixtures/yml'));
}
protected function getFileExtension()
{
return 'yml';
}
}

View File

@@ -0,0 +1,23 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
class AuthenticationCommencingTest extends WebTestCase
{
public function testAuthenticationIsCommencingIfAccessDeniedExceptionIsWrapped()
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => 'config.yml'));
$client->request('GET', '/secure-but-not-covered-by-access-control');
$this->assertRedirect($client->getResponse(), '/login');
}
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AclBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
/**
* @author Kévin Dunglas <kevin@les-tilleuls.coop>
*/
class AclBundle extends Bundle
{
}

View File

@@ -0,0 +1,22 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AclBundle\Entity;
/**
* Car.
*
* @author Kévin Dunglas <kevin@les-tilleuls.coop>
*/
class Car
{
public $id;
}

View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\CsrfFormLoginBundle\Controller;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
class LoginController implements ContainerAwareInterface
{
use ContainerAwareTrait;
public function loginAction()
{
$form = $this->container->get('form.factory')->create('Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\CsrfFormLoginBundle\Form\UserLoginType');
return $this->container->get('templating')->renderResponse('CsrfFormLoginBundle:Login:login.html.twig', array(
'form' => $form->createView(),
));
}
public function afterLoginAction()
{
return $this->container->get('templating')->renderResponse('CsrfFormLoginBundle:Login:after_login.html.twig');
}
public function loginCheckAction()
{
return new Response('', 400);
}
public function secureAction()
{
throw new \Exception('Wrapper', 0, new \Exception('Another Wrapper', 0, new AccessDeniedException()));
}
}

View File

@@ -0,0 +1,18 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\CsrfFormLoginBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class CsrfFormLoginBundle extends Bundle
{
}

View File

@@ -0,0 +1,87 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\CsrfFormLoginBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Security;
/**
* Form type for use with the Security component's form-based authentication
* listener.
*
* @author Henrik Bjornskov <henrik@bjrnskov.dk>
* @author Jeremy Mikola <jmikola@gmail.com>
*/
class UserLoginType extends AbstractType
{
private $requestStack;
public function __construct(RequestStack $requestStack)
{
$this->requestStack = $requestStack;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('username', 'Symfony\Component\Form\Extension\Core\Type\TextType')
->add('password', 'Symfony\Component\Form\Extension\Core\Type\PasswordType')
->add('_target_path', 'Symfony\Component\Form\Extension\Core\Type\HiddenType')
;
$request = $this->requestStack->getCurrentRequest();
/* Note: since the Security component's form login listener intercepts
* the POST request, this form will never really be bound to the
* request; however, we can match the expected behavior by checking the
* session for an authentication error and last username.
*/
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($request) {
if ($request->attributes->has(Security::AUTHENTICATION_ERROR)) {
$error = $request->attributes->get(Security::AUTHENTICATION_ERROR);
} else {
$error = $request->getSession()->get(Security::AUTHENTICATION_ERROR);
}
if ($error) {
$event->getForm()->addError(new FormError($error->getMessage()));
}
$event->setData(array_replace((array) $event->getData(), array(
'username' => $request->getSession()->get(Security::LAST_USERNAME),
)));
});
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
/* Note: the form's csrf_token_id must correspond to that for the form login
* listener in order for the CSRF token to validate successfully.
*/
$resolver->setDefaults(array(
'csrf_token_id' => 'authenticate',
));
}
}

View File

@@ -0,0 +1,30 @@
form_login:
path: /login
defaults: { _controller: CsrfFormLoginBundle:Login:login }
form_login_check:
path: /login_check
defaults: { _controller: CsrfFormLoginBundle:Login:loginCheck }
form_login_homepage:
path: /
defaults: { _controller: CsrfFormLoginBundle:Login:afterLogin }
form_login_custom_target_path:
path: /foo
defaults: { _controller: CsrfFormLoginBundle:Login:afterLogin }
form_login_default_target_path:
path: /profile
defaults: { _controller: CsrfFormLoginBundle:Login:afterLogin }
form_login_redirect_to_protected_resource_after_login:
path: /protected-resource
defaults: { _controller: CsrfFormLoginBundle:Login:afterLogin }
form_logout:
path: /logout_path
form_secure_action:
path: /secure-but-not-covered-by-access-control
defaults: { _controller: CsrfFormLoginBundle:Login:secure }

View File

@@ -0,0 +1,8 @@
{% extends "::base.html.twig" %}
{% block body %}
Hello {{ app.user.username }}!<br /><br />
You're browsing to path "{{ app.request.pathInfo }}".<br /><br />
<a href="{{ logout_path('default') }}">Log out</a>.
<a href="{{ logout_url('default') }}">Log out</a>.
{% endblock %}

View File

@@ -0,0 +1,12 @@
{% extends "::base.html.twig" %}
{% block body %}
<form action="{{ path('form_login_check') }}" method="post">
{{ form_widget(form) }}
{# Note: ensure the submit name does not conflict with the form's name or it may clobber field data #}
<input type="submit" name="login" />
</form>
{% endblock %}

View File

@@ -0,0 +1,26 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FirewallEntryPointBundle\DependencyInjection;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
class FirewallEntryPointExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.xml');
}
}

View File

@@ -0,0 +1,18 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FirewallEntryPointBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class FirewallEntryPointBundle extends Bundle
{
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="firewall_entry_point.entry_point.stub"
class="Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FirewallEntryPointBundle\Security\EntryPointStub"
/>
</services>
</container>

View File

@@ -0,0 +1,27 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FirewallEntryPointBundle\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
class EntryPointStub implements AuthenticationEntryPointInterface
{
const RESPONSE_TEXT = '2be8e651259189d841a19eecdf37e771e2431741';
public function start(Request $request, AuthenticationException $authException = null)
{
return new Response(self::RESPONSE_TEXT);
}
}

View File

@@ -0,0 +1,64 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FormLoginBundle\Controller;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class LocalizedController implements ContainerAwareInterface
{
use ContainerAwareTrait;
public function loginAction(Request $request)
{
// get the login error if there is one
if ($request->attributes->has(Security::AUTHENTICATION_ERROR)) {
$error = $request->attributes->get(Security::AUTHENTICATION_ERROR);
} else {
$error = $request->getSession()->get(Security::AUTHENTICATION_ERROR);
}
return $this->container->get('templating')->renderResponse('FormLoginBundle:Localized:login.html.twig', array(
// last username entered by the user
'last_username' => $request->getSession()->get(Security::LAST_USERNAME),
'error' => $error,
));
}
public function loginCheckAction()
{
throw new \RuntimeException('loginCheckAction() should never be called.');
}
public function logoutAction()
{
throw new \RuntimeException('logoutAction() should never be called.');
}
public function secureAction()
{
throw new \RuntimeException('secureAction() should never be called.');
}
public function profileAction()
{
return new Response('Profile');
}
public function homepageAction()
{
return new Response('Homepage');
}
}

View File

@@ -0,0 +1,56 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FormLoginBundle\Controller;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
class LoginController implements ContainerAwareInterface
{
use ContainerAwareTrait;
public function loginAction(Request $request, UserInterface $user = null)
{
// get the login error if there is one
if ($request->attributes->has(Security::AUTHENTICATION_ERROR)) {
$error = $request->attributes->get(Security::AUTHENTICATION_ERROR);
} else {
$error = $request->getSession()->get(Security::AUTHENTICATION_ERROR);
}
return $this->container->get('templating')->renderResponse('FormLoginBundle:Login:login.html.twig', array(
// last username entered by the user
'last_username' => $request->getSession()->get(Security::LAST_USERNAME),
'error' => $error,
));
}
public function afterLoginAction(UserInterface $user)
{
return $this->container->get('templating')->renderResponse('FormLoginBundle:Login:after_login.html.twig', array('user' => $user));
}
public function loginCheckAction()
{
return new Response('', 400);
}
public function secureAction()
{
throw new \Exception('Wrapper', 0, new \Exception('Another Wrapper', 0, new AccessDeniedException()));
}
}

View File

@@ -0,0 +1,27 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FormLoginBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
class FormLoginExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$container
->register('localized_form_failure_handler', 'Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FormLoginBundle\Security\LocalizedFormFailureHandler')
->addArgument(new Reference('router'))
;
}
}

View File

@@ -0,0 +1,18 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FormLoginBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class FormLoginBundle extends Bundle
{
}

View File

@@ -0,0 +1,29 @@
localized_login_path:
path: /{_locale}/login
defaults: { _controller: FormLoginBundle:Localized:login }
requirements: { _locale: "^[a-z]{2}$" }
localized_check_path:
path: /{_locale}/login_check
defaults: { _controller: FormLoginBundle:Localized:loginCheck }
requirements: { _locale: "^[a-z]{2}$" }
localized_default_target_path:
path: /{_locale}/profile
defaults: { _controller: FormLoginBundle:Localized:profile }
requirements: { _locale: "^[a-z]{2}$" }
localized_logout_path:
path: /{_locale}/logout
defaults: { _controller: FormLoginBundle:Localized:logout }
requirements: { _locale: "^[a-z]{2}$" }
localized_logout_target_path:
path: /{_locale}/
defaults: { _controller: FormLoginBundle:Localized:homepage }
requirements: { _locale: "^[a-z]{2}$" }
localized_secure_path:
path: /{_locale}/secure/
defaults: { _controller: FormLoginBundle:Localized:secure }
requirements: { _locale: "^[a-z]{2}$" }

View File

@@ -0,0 +1,42 @@
form_login:
path: /login
defaults: { _controller: FormLoginBundle:Login:login }
form_login_check:
path: /login_check
defaults: { _controller: FormLoginBundle:Login:loginCheck }
form_login_homepage:
path: /
defaults: { _controller: FormLoginBundle:Login:afterLogin }
form_login_custom_target_path:
path: /foo
defaults: { _controller: FormLoginBundle:Login:afterLogin }
form_login_default_target_path:
path: /profile
defaults: { _controller: FormLoginBundle:Login:afterLogin }
form_login_redirect_to_protected_resource_after_login:
path: /protected_resource
defaults: { _controller: FormLoginBundle:Login:afterLogin }
highly_protected_resource:
path: /highly_protected_resource
secured-by-one-ip:
path: /secured-by-one-ip
secured-by-two-ips:
path: /secured-by-two-ips
form_logout:
path: /logout_path
form_secure_action:
path: /secure-but-not-covered-by-access-control
defaults: { _controller: FormLoginBundle:Login:secure }
protected-via-expression:
path: /protected-via-expression

View File

@@ -0,0 +1,21 @@
{% extends "::base.html.twig" %}
{% block body %}
{% if error %}
<div>{{ error.message }}</div>
{% endif %}
<form action="{{ path('localized_check_path') }}" method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="_username" value="{{ last_username }}" />
<label for="password">Password:</label>
<input type="password" id="password" name="_password" />
<input type="hidden" name="_target_path" value="" />
<input type="submit" name="login" />
</form>
{% endblock %}

View File

@@ -0,0 +1,16 @@
{% extends "::base.html.twig" %}
{% block body %}
Hello {{ user.username }}!<br /><br />
You're browsing to path "{{ app.request.pathInfo }}".
<a href="{{ logout_path('default') }}">Log out</a>.
<a href="{{ logout_url('default') }}">Log out</a>.
<a href="{{ logout_path('second_area') }}">Log out</a>.
<a href="{{ logout_url('second_area') }}">Log out</a>.
<a href="{{ logout_path() }}">Log out</a>.
<a href="{{ logout_url() }}">Log out</a>.
{% endblock %}

View File

@@ -0,0 +1,21 @@
{% extends "::base.html.twig" %}
{% block body %}
{% if error %}
<div>{{ error.message }}</div>
{% endif %}
<form action="{{ path('form_login_check') }}" method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="_username" value="{{ last_username }}" />
<label for="password">Password:</label>
<input type="password" id="password" name="_password" />
<input type="hidden" name="_target_path" value="" />
<input type="submit" name="login" />
</form>
{% endblock %}

View File

@@ -0,0 +1,34 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FormLoginBundle\Security;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
class LocalizedFormFailureHandler implements AuthenticationFailureHandlerInterface
{
private $router;
public function __construct(RouterInterface $router)
{
$this->router = $router;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
return new RedirectResponse($this->router->generate('localized_login_path', array(), UrlGeneratorInterface::ABSOLUTE_URL));
}
}

View File

@@ -0,0 +1,111 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
class CsrfFormLoginTest extends WebTestCase
{
/**
* @dataProvider getConfigs
*/
public function testFormLoginAndLogoutWithCsrfTokens($config)
{
$client = $this->createClient(array('test_case' => 'CsrfFormLogin', 'root_config' => $config));
$form = $client->request('GET', '/login')->selectButton('login')->form();
$form['user_login[username]'] = 'johannes';
$form['user_login[password]'] = 'test';
$client->submit($form);
$this->assertRedirect($client->getResponse(), '/profile');
$crawler = $client->followRedirect();
$text = $crawler->text();
$this->assertContains('Hello johannes!', $text);
$this->assertContains('You\'re browsing to path "/profile".', $text);
$logoutLinks = $crawler->selectLink('Log out')->links();
$this->assertCount(2, $logoutLinks);
$this->assertContains('_csrf_token=', $logoutLinks[0]->getUri());
$this->assertSame($logoutLinks[0]->getUri(), $logoutLinks[1]->getUri());
$client->click($logoutLinks[0]);
$this->assertRedirect($client->getResponse(), '/');
}
/**
* @dataProvider getConfigs
*/
public function testFormLoginWithInvalidCsrfToken($config)
{
$client = $this->createClient(array('test_case' => 'CsrfFormLogin', 'root_config' => $config));
$form = $client->request('GET', '/login')->selectButton('login')->form();
$form['user_login[_token]'] = '';
$client->submit($form);
$this->assertRedirect($client->getResponse(), '/login');
$text = $client->followRedirect()->text();
$this->assertContains('Invalid CSRF token.', $text);
}
/**
* @dataProvider getConfigs
*/
public function testFormLoginWithCustomTargetPath($config)
{
$client = $this->createClient(array('test_case' => 'CsrfFormLogin', 'root_config' => $config));
$form = $client->request('GET', '/login')->selectButton('login')->form();
$form['user_login[username]'] = 'johannes';
$form['user_login[password]'] = 'test';
$form['user_login[_target_path]'] = '/foo';
$client->submit($form);
$this->assertRedirect($client->getResponse(), '/foo');
$text = $client->followRedirect()->text();
$this->assertContains('Hello johannes!', $text);
$this->assertContains('You\'re browsing to path "/foo".', $text);
}
/**
* @dataProvider getConfigs
*/
public function testFormLoginRedirectsToProtectedResourceAfterLogin($config)
{
$client = $this->createClient(array('test_case' => 'CsrfFormLogin', 'root_config' => $config));
$client->request('GET', '/protected-resource');
$this->assertRedirect($client->getResponse(), '/login');
$form = $client->followRedirect()->selectButton('login')->form();
$form['user_login[username]'] = 'johannes';
$form['user_login[password]'] = 'test';
$client->submit($form);
$this->assertRedirect($client->getResponse(), '/protected-resource');
$text = $client->followRedirect()->text();
$this->assertContains('Hello johannes!', $text);
$this->assertContains('You\'re browsing to path "/protected-resource".', $text);
}
public function getConfigs()
{
return array(
array('config.yml'),
array('routes_as_path.yml'),
);
}
}

View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FirewallEntryPointBundle\Security\EntryPointStub;
class FirewallEntryPointTest extends WebTestCase
{
public function testItUsesTheConfiguredEntryPointWhenUsingUnknownCredentials()
{
$client = $this->createClient(array('test_case' => 'FirewallEntryPoint'));
$client->request('GET', '/secure/resource', array(), array(), array(
'PHP_AUTH_USER' => 'unknown',
'PHP_AUTH_PW' => 'credentials',
));
$this->assertEquals(
EntryPointStub::RESPONSE_TEXT,
$client->getResponse()->getContent(),
"Custom entry point wasn't started"
);
}
public function testItUsesTheConfiguredEntryPointFromTheExceptionListenerWithFormLoginAndNoCredentials()
{
$client = $this->createClient(array('test_case' => 'FirewallEntryPoint', 'root_config' => 'config_form_login.yml'));
$client->request('GET', '/secure/resource');
$this->assertEquals(
EntryPointStub::RESPONSE_TEXT,
$client->getResponse()->getContent(),
"Custom entry point wasn't started"
);
}
}

View File

@@ -0,0 +1,116 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
class FormLoginTest extends WebTestCase
{
/**
* @dataProvider getConfigs
*/
public function testFormLogin($config)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config));
$form = $client->request('GET', '/login')->selectButton('login')->form();
$form['_username'] = 'johannes';
$form['_password'] = 'test';
$client->submit($form);
$this->assertRedirect($client->getResponse(), '/profile');
$text = $client->followRedirect()->text();
$this->assertContains('Hello johannes!', $text);
$this->assertContains('You\'re browsing to path "/profile".', $text);
}
/**
* @dataProvider getConfigs
*/
public function testFormLogout($config)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config));
$form = $client->request('GET', '/login')->selectButton('login')->form();
$form['_username'] = 'johannes';
$form['_password'] = 'test';
$client->submit($form);
$this->assertRedirect($client->getResponse(), '/profile');
$crawler = $client->followRedirect();
$text = $crawler->text();
$this->assertContains('Hello johannes!', $text);
$this->assertContains('You\'re browsing to path "/profile".', $text);
$logoutLinks = $crawler->selectLink('Log out')->links();
$this->assertCount(6, $logoutLinks);
$this->assertSame($logoutLinks[0]->getUri(), $logoutLinks[1]->getUri());
$this->assertSame($logoutLinks[2]->getUri(), $logoutLinks[3]->getUri());
$this->assertSame($logoutLinks[4]->getUri(), $logoutLinks[5]->getUri());
$this->assertNotSame($logoutLinks[0]->getUri(), $logoutLinks[2]->getUri());
$this->assertNotSame($logoutLinks[1]->getUri(), $logoutLinks[3]->getUri());
$this->assertSame($logoutLinks[0]->getUri(), $logoutLinks[4]->getUri());
$this->assertSame($logoutLinks[1]->getUri(), $logoutLinks[5]->getUri());
}
/**
* @dataProvider getConfigs
*/
public function testFormLoginWithCustomTargetPath($config)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config));
$form = $client->request('GET', '/login')->selectButton('login')->form();
$form['_username'] = 'johannes';
$form['_password'] = 'test';
$form['_target_path'] = '/foo';
$client->submit($form);
$this->assertRedirect($client->getResponse(), '/foo');
$text = $client->followRedirect()->text();
$this->assertContains('Hello johannes!', $text);
$this->assertContains('You\'re browsing to path "/foo".', $text);
}
/**
* @dataProvider getConfigs
*/
public function testFormLoginRedirectsToProtectedResourceAfterLogin($config)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config));
$client->request('GET', '/protected_resource');
$this->assertRedirect($client->getResponse(), '/login');
$form = $client->followRedirect()->selectButton('login')->form();
$form['_username'] = 'johannes';
$form['_password'] = 'test';
$client->submit($form);
$this->assertRedirect($client->getResponse(), '/protected_resource');
$text = $client->followRedirect()->text();
$this->assertContains('Hello johannes!', $text);
$this->assertContains('You\'re browsing to path "/protected_resource".', $text);
}
public function getConfigs()
{
return array(
array('config.yml'),
array('routes_as_path.yml'),
);
}
}

View File

@@ -0,0 +1,79 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
class LocalizedRoutesAsPathTest extends WebTestCase
{
/**
* @dataProvider getLocales
*/
public function testLoginLogoutProcedure($locale)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => 'localized_routes.yml'));
$crawler = $client->request('GET', '/'.$locale.'/login');
$form = $crawler->selectButton('login')->form();
$form['_username'] = 'johannes';
$form['_password'] = 'test';
$client->submit($form);
$this->assertRedirect($client->getResponse(), '/'.$locale.'/profile');
$this->assertEquals('Profile', $client->followRedirect()->text());
$client->request('GET', '/'.$locale.'/logout');
$this->assertRedirect($client->getResponse(), '/'.$locale.'/');
$this->assertEquals('Homepage', $client->followRedirect()->text());
}
/**
* @dataProvider getLocales
*/
public function testLoginFailureWithLocalizedFailurePath($locale)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => 'localized_form_failure_handler.yml'));
$crawler = $client->request('GET', '/'.$locale.'/login');
$form = $crawler->selectButton('login')->form();
$form['_username'] = 'johannes';
$form['_password'] = 'foobar';
$client->submit($form);
$this->assertRedirect($client->getResponse(), '/'.$locale.'/login');
}
/**
* @dataProvider getLocales
*/
public function testAccessRestrictedResource($locale)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => 'localized_routes.yml'));
$client->request('GET', '/'.$locale.'/secure/');
$this->assertRedirect($client->getResponse(), '/'.$locale.'/login');
}
/**
* @dataProvider getLocales
*/
public function testAccessRestrictedResourceWithForward($locale)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => 'localized_routes_with_forward.yml'));
$crawler = $client->request('GET', '/'.$locale.'/secure/');
$this->assertCount(1, $crawler->selectButton('login'), (string) $client->getResponse());
}
public function getLocales()
{
return array(array('en'), array('de'));
}
}

View File

@@ -0,0 +1,119 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
class SecurityRoutingIntegrationTest extends WebTestCase
{
/**
* @dataProvider getConfigs
*/
public function testRoutingErrorIsNotExposedForProtectedResourceWhenAnonymous($config)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config));
$client->request('GET', '/protected_resource');
$this->assertRedirect($client->getResponse(), '/login');
}
/**
* @dataProvider getConfigs
*/
public function testRoutingErrorIsExposedWhenNotProtected($config)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config));
$client->request('GET', '/unprotected_resource');
$this->assertEquals(404, $client->getResponse()->getStatusCode(), (string) $client->getResponse());
}
/**
* @dataProvider getConfigs
*/
public function testRoutingErrorIsNotExposedForProtectedResourceWhenLoggedInWithInsufficientRights($config)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config));
$form = $client->request('GET', '/login')->selectButton('login')->form();
$form['_username'] = 'johannes';
$form['_password'] = 'test';
$client->submit($form);
$client->request('GET', '/highly_protected_resource');
$this->assertNotEquals(404, $client->getResponse()->getStatusCode());
}
/**
* @dataProvider getConfigs
*/
public function testSecurityConfigurationForSingleIPAddress($config)
{
$allowedClient = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config), array('REMOTE_ADDR' => '10.10.10.10'));
$barredClient = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config), array('REMOTE_ADDR' => '10.10.20.10'));
$this->assertAllowed($allowedClient, '/secured-by-one-ip');
$this->assertRestricted($barredClient, '/secured-by-one-ip');
}
/**
* @dataProvider getConfigs
*/
public function testSecurityConfigurationForMultipleIPAddresses($config)
{
$allowedClientA = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config), array('REMOTE_ADDR' => '1.1.1.1'));
$allowedClientB = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config), array('REMOTE_ADDR' => '2.2.2.2'));
$barredClient = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config), array('REMOTE_ADDR' => '192.168.1.1'));
$this->assertAllowed($allowedClientA, '/secured-by-two-ips');
$this->assertAllowed($allowedClientB, '/secured-by-two-ips');
$this->assertRestricted($barredClient, '/secured-by-two-ips');
}
/**
* @dataProvider getConfigs
*/
public function testSecurityConfigurationForExpression($config)
{
$allowedClient = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config), array('HTTP_USER_AGENT' => 'Firefox 1.0'));
$this->assertAllowed($allowedClient, '/protected-via-expression');
$barredClient = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config), array());
$this->assertRestricted($barredClient, '/protected-via-expression');
$allowedClient = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config), array());
$allowedClient->request('GET', '/protected-via-expression');
$form = $allowedClient->followRedirect()->selectButton('login')->form();
$form['_username'] = 'johannes';
$form['_password'] = 'test';
$allowedClient->submit($form);
$this->assertRedirect($allowedClient->getResponse(), '/protected-via-expression');
$this->assertAllowed($allowedClient, '/protected-via-expression');
}
private function assertAllowed($client, $path)
{
$client->request('GET', $path);
$this->assertEquals(404, $client->getResponse()->getStatusCode());
}
private function assertRestricted($client, $path)
{
$client->request('GET', $path);
$this->assertEquals(302, $client->getResponse()->getStatusCode());
}
public function getConfigs()
{
return array(array('config.yml'), array('routes_as_path.yml'));
}
}

View File

@@ -0,0 +1,178 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\SecurityBundle\Command\InitAclCommand;
use Symfony\Bundle\SecurityBundle\Command\SetAclCommand;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
use Symfony\Component\Security\Acl\Exception\NoAceFoundException;
use Symfony\Component\Security\Acl\Permission\BasicPermissionMap;
/**
* Tests SetAclCommand.
*
* @author Kévin Dunglas <kevin@les-tilleuls.coop>
* @requires extension pdo_sqlite
*/
class SetAclCommandTest extends WebTestCase
{
const OBJECT_CLASS = 'Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AclBundle\Entity\Car';
const SECURITY_CLASS = 'Symfony\Component\Security\Core\User\User';
public function testSetAclUser()
{
$objectId = 1;
$securityUsername1 = 'kevin';
$securityUsername2 = 'anne';
$grantedPermission1 = 'VIEW';
$grantedPermission2 = 'EDIT';
$application = $this->getApplication();
$application->add(new SetAclCommand());
$setAclCommand = $application->find('acl:set');
$setAclCommandTester = new CommandTester($setAclCommand);
$setAclCommandTester->execute(array(
'command' => 'acl:set',
'arguments' => array($grantedPermission1, $grantedPermission2, sprintf('%s:%s', self::OBJECT_CLASS, $objectId)),
'--user' => array(sprintf('%s:%s', self::SECURITY_CLASS, $securityUsername1), sprintf('%s:%s', self::SECURITY_CLASS, $securityUsername2)),
));
$objectIdentity = new ObjectIdentity($objectId, self::OBJECT_CLASS);
$securityIdentity1 = new UserSecurityIdentity($securityUsername1, self::SECURITY_CLASS);
$securityIdentity2 = new UserSecurityIdentity($securityUsername2, self::SECURITY_CLASS);
$permissionMap = new BasicPermissionMap();
/** @var \Symfony\Component\Security\Acl\Model\AclProviderInterface $aclProvider */
$aclProvider = $application->getKernel()->getContainer()->get('security.acl.provider');
$acl = $aclProvider->findAcl($objectIdentity, array($securityIdentity1));
$this->assertTrue($acl->isGranted($permissionMap->getMasks($grantedPermission1, null), array($securityIdentity1)));
$this->assertTrue($acl->isGranted($permissionMap->getMasks($grantedPermission1, null), array($securityIdentity2)));
$this->assertTrue($acl->isGranted($permissionMap->getMasks($grantedPermission2, null), array($securityIdentity2)));
try {
$acl->isGranted($permissionMap->getMasks('OWNER', null), array($securityIdentity1));
$this->fail('NoAceFoundException not throwed');
} catch (NoAceFoundException $e) {
}
try {
$acl->isGranted($permissionMap->getMasks('OPERATOR', null), array($securityIdentity2));
$this->fail('NoAceFoundException not throwed');
} catch (NoAceFoundException $e) {
}
}
public function testSetAclRole()
{
$objectId = 1;
$securityUsername = 'kevin';
$grantedPermission = 'VIEW';
$role = 'ROLE_ADMIN';
$application = $this->getApplication();
$application->add(new SetAclCommand());
$setAclCommand = $application->find('acl:set');
$setAclCommandTester = new CommandTester($setAclCommand);
$setAclCommandTester->execute(array(
'command' => 'acl:set',
'arguments' => array($grantedPermission, sprintf('%s:%s', str_replace('\\', '/', self::OBJECT_CLASS), $objectId)),
'--role' => array($role),
));
$objectIdentity = new ObjectIdentity($objectId, self::OBJECT_CLASS);
$userSecurityIdentity = new UserSecurityIdentity($securityUsername, self::SECURITY_CLASS);
$roleSecurityIdentity = new RoleSecurityIdentity($role);
$permissionMap = new BasicPermissionMap();
/** @var \Symfony\Component\Security\Acl\Model\AclProviderInterface $aclProvider */
$aclProvider = $application->getKernel()->getContainer()->get('security.acl.provider');
$acl = $aclProvider->findAcl($objectIdentity, array($roleSecurityIdentity, $userSecurityIdentity));
$this->assertTrue($acl->isGranted($permissionMap->getMasks($grantedPermission, null), array($roleSecurityIdentity)));
$this->assertTrue($acl->isGranted($permissionMap->getMasks($grantedPermission, null), array($roleSecurityIdentity)));
try {
$acl->isGranted($permissionMap->getMasks('VIEW', null), array($userSecurityIdentity));
$this->fail('NoAceFoundException not throwed');
} catch (NoAceFoundException $e) {
}
try {
$acl->isGranted($permissionMap->getMasks('OPERATOR', null), array($userSecurityIdentity));
$this->fail('NoAceFoundException not throwed');
} catch (NoAceFoundException $e) {
}
}
public function testSetAclClassScope()
{
$objectId = 1;
$grantedPermission = 'VIEW';
$role = 'ROLE_USER';
$application = $this->getApplication();
$application->add(new SetAclCommand());
$setAclCommand = $application->find('acl:set');
$setAclCommandTester = new CommandTester($setAclCommand);
$setAclCommandTester->execute(array(
'command' => 'acl:set',
'arguments' => array($grantedPermission, sprintf('%s:%s', self::OBJECT_CLASS, $objectId)),
'--class-scope' => true,
'--role' => array($role),
));
$objectIdentity1 = new ObjectIdentity($objectId, self::OBJECT_CLASS);
$objectIdentity2 = new ObjectIdentity(2, self::OBJECT_CLASS);
$roleSecurityIdentity = new RoleSecurityIdentity($role);
$permissionMap = new BasicPermissionMap();
/** @var \Symfony\Component\Security\Acl\Model\AclProviderInterface $aclProvider */
$aclProvider = $application->getKernel()->getContainer()->get('security.acl.provider');
$acl1 = $aclProvider->findAcl($objectIdentity1, array($roleSecurityIdentity));
$this->assertTrue($acl1->isGranted($permissionMap->getMasks($grantedPermission, null), array($roleSecurityIdentity)));
$acl2 = $aclProvider->createAcl($objectIdentity2);
$this->assertTrue($acl2->isGranted($permissionMap->getMasks($grantedPermission, null), array($roleSecurityIdentity)));
}
private function getApplication()
{
$kernel = $this->createKernel(array('test_case' => 'Acl'));
$kernel->boot();
$application = new Application($kernel);
$application->add(new InitAclCommand());
$initAclCommand = $application->find('init:acl');
$initAclCommandTester = new CommandTester($initAclCommand);
$initAclCommandTester->execute(array('command' => 'init:acl'));
return $application;
}
}

View File

@@ -0,0 +1,73 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
class SwitchUserTest extends WebTestCase
{
/**
* @dataProvider getTestParameters
*/
public function testSwitchUser($originalUser, $targetUser, $expectedUser, $expectedStatus)
{
$client = $this->createAuthenticatedClient($originalUser);
$client->request('GET', '/profile?_switch_user='.$targetUser);
$this->assertEquals($expectedStatus, $client->getResponse()->getStatusCode());
$this->assertEquals($expectedUser, $client->getProfile()->getCollector('security')->getUser());
}
public function testSwitchedUserCannotSwitchToOther()
{
$client = $this->createAuthenticatedClient('user_can_switch');
$client->request('GET', '/profile?_switch_user=user_cannot_switch_1');
$client->request('GET', '/profile?_switch_user=user_cannot_switch_2');
$this->assertEquals(500, $client->getResponse()->getStatusCode());
$this->assertEquals('user_cannot_switch_1', $client->getProfile()->getCollector('security')->getUser());
}
public function testSwitchedUserExit()
{
$client = $this->createAuthenticatedClient('user_can_switch');
$client->request('GET', '/profile?_switch_user=user_cannot_switch_1');
$client->request('GET', '/profile?_switch_user=_exit');
$this->assertEquals(200, $client->getResponse()->getStatusCode());
$this->assertEquals('user_can_switch', $client->getProfile()->getCollector('security')->getUser());
}
public function getTestParameters()
{
return array(
'unauthorized_user_cannot_switch' => array('user_cannot_switch_1', 'user_cannot_switch_1', 'user_cannot_switch_1', 403),
'authorized_user_can_switch' => array('user_can_switch', 'user_cannot_switch_1', 'user_cannot_switch_1', 200),
'authorized_user_cannot_switch_to_non_existent' => array('user_can_switch', 'user_does_not_exist', 'user_can_switch', 500),
'authorized_user_can_switch_to_himself' => array('user_can_switch', 'user_can_switch', 'user_can_switch', 200),
);
}
protected function createAuthenticatedClient($username)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => 'switchuser.yml'));
$client->followRedirects(true);
$form = $client->request('GET', '/login')->selectButton('login')->form();
$form['_username'] = $username;
$form['_password'] = 'test';
$client->submit($form);
return $client;
}
}

View File

@@ -0,0 +1,164 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\SecurityBundle\Command\UserPasswordEncoderCommand;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder;
use Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder;
/**
* Tests UserPasswordEncoderCommand.
*
* @author Sarah Khalil <mkhalil.sarah@gmail.com>
*/
class UserPasswordEncoderCommandTest extends WebTestCase
{
private $passwordEncoderCommandTester;
public function testEncodePasswordEmptySalt()
{
$this->passwordEncoderCommandTester->execute(array(
'command' => 'security:encode-password',
'password' => 'password',
'user-class' => 'Symfony\Component\Security\Core\User\User',
'--empty-salt' => true,
), array('decorated' => false));
$expected = str_replace("\n", PHP_EOL, file_get_contents(__DIR__.'/app/PasswordEncode/emptysalt.txt'));
$this->assertEquals($expected, $this->passwordEncoderCommandTester->getDisplay());
}
public function testEncodeNoPasswordNoInteraction()
{
$statusCode = $this->passwordEncoderCommandTester->execute(array(
'command' => 'security:encode-password',
), array('interactive' => false));
$this->assertContains('[ERROR] The password must not be empty.', $this->passwordEncoderCommandTester->getDisplay());
$this->assertEquals($statusCode, 1);
}
public function testEncodePasswordBcrypt()
{
$this->passwordEncoderCommandTester->execute(array(
'command' => 'security:encode-password',
'password' => 'password',
'user-class' => 'Custom\Class\Bcrypt\User',
), array('interactive' => false));
$output = $this->passwordEncoderCommandTester->getDisplay();
$this->assertContains('Password encoding succeeded', $output);
$encoder = new BCryptPasswordEncoder(17);
preg_match('# Encoded password\s{1,}([\w+\/$.]+={0,2})\s+#', $output, $matches);
$hash = $matches[1];
$this->assertTrue($encoder->isPasswordValid($hash, 'password', null));
}
public function testEncodePasswordPbkdf2()
{
$this->passwordEncoderCommandTester->execute(array(
'command' => 'security:encode-password',
'password' => 'password',
'user-class' => 'Custom\Class\Pbkdf2\User',
), array('interactive' => false));
$output = $this->passwordEncoderCommandTester->getDisplay();
$this->assertContains('Password encoding succeeded', $output);
$encoder = new Pbkdf2PasswordEncoder('sha512', true, 1000);
preg_match('# Encoded password\s{1,}([\w+\/]+={0,2})\s+#', $output, $matches);
$hash = $matches[1];
preg_match('# Generated salt\s{1,}([\w+\/]+={0,2})\s+#', $output, $matches);
$salt = $matches[1];
$this->assertTrue($encoder->isPasswordValid($hash, 'password', $salt));
}
public function testEncodePasswordOutput()
{
$this->passwordEncoderCommandTester->execute(
array(
'command' => 'security:encode-password',
'password' => 'p@ssw0rd',
), array('interactive' => false)
);
$this->assertContains('Password encoding succeeded', $this->passwordEncoderCommandTester->getDisplay());
$this->assertContains(' Encoded password p@ssw0rd', $this->passwordEncoderCommandTester->getDisplay());
$this->assertContains(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay());
}
public function testEncodePasswordEmptySaltOutput()
{
$this->passwordEncoderCommandTester->execute(
array(
'command' => 'security:encode-password',
'password' => 'p@ssw0rd',
'--empty-salt' => true,
)
);
$this->assertContains('Password encoding succeeded', $this->passwordEncoderCommandTester->getDisplay());
$this->assertContains(' Encoded password p@ssw0rd', $this->passwordEncoderCommandTester->getDisplay());
$this->assertNotContains(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay());
}
public function testEncodePasswordBcryptOutput()
{
$this->passwordEncoderCommandTester->execute(
array(
'command' => 'security:encode-password',
'password' => 'p@ssw0rd',
'user-class' => 'Custom\Class\Bcrypt\User',
)
);
$this->assertNotContains(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay());
}
public function testEncodePasswordNoConfigForGivenUserClass()
{
if (method_exists($this, 'expectException')) {
$this->expectException('\RuntimeException');
$this->expectExceptionMessage('No encoder has been configured for account "Foo\Bar\User".');
} else {
$this->setExpectedException('\RuntimeException', 'No encoder has been configured for account "Foo\Bar\User".');
}
$this->passwordEncoderCommandTester->execute(array(
'command' => 'security:encode-password',
'password' => 'password',
'user-class' => 'Foo\Bar\User',
), array('interactive' => false));
}
protected function setUp()
{
putenv('COLUMNS='.(119 + strlen(PHP_EOL)));
$kernel = $this->createKernel(array('test_case' => 'PasswordEncode'));
$kernel->boot();
$application = new Application($kernel);
$application->add(new UserPasswordEncoderCommand());
$passwordEncoderCommand = $application->find('security:encode-password');
$this->passwordEncoderCommandTester = new CommandTester($passwordEncoderCommand);
}
protected function tearDown()
{
$this->passwordEncoderCommandTester = null;
}
}

View File

@@ -0,0 +1,73 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase as BaseWebTestCase;
use Symfony\Component\Filesystem\Filesystem;
class WebTestCase extends BaseWebTestCase
{
public static function assertRedirect($response, $location)
{
self::assertTrue($response->isRedirect(), 'Response is not a redirect, got status code: '.substr($response, 0, 2000));
self::assertEquals('http://localhost'.$location, $response->headers->get('Location'));
}
public static function setUpBeforeClass()
{
static::deleteTmpDir();
}
public static function tearDownAfterClass()
{
static::deleteTmpDir();
}
protected static function deleteTmpDir()
{
if (!file_exists($dir = sys_get_temp_dir().'/'.static::getVarDir())) {
return;
}
$fs = new Filesystem();
$fs->remove($dir);
}
protected static function getKernelClass()
{
require_once __DIR__.'/app/AppKernel.php';
return 'Symfony\Bundle\SecurityBundle\Tests\Functional\app\AppKernel';
}
protected static function createKernel(array $options = array())
{
$class = self::getKernelClass();
if (!isset($options['test_case'])) {
throw new \InvalidArgumentException('The option "test_case" must be set.');
}
return new $class(
static::getVarDir(),
$options['test_case'],
isset($options['root_config']) ? $options['root_config'] : 'config.yml',
isset($options['environment']) ? $options['environment'] : strtolower(static::getVarDir().$options['test_case']),
isset($options['debug']) ? $options['debug'] : true
);
}
protected static function getVarDir()
{
return substr(strrchr(get_called_class(), '\\'), 1);
}
}

View File

@@ -0,0 +1,17 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
return array(
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AclBundle\AclBundle(),
);

View File

@@ -0,0 +1,24 @@
imports:
- { resource: ./../config/framework.yml }
doctrine:
dbal:
driver: pdo_sqlite
memory: true
charset: UTF8
security:
firewalls:
test:
pattern: ^/
security: false
acl:
connection: default
encoders:
Symfony\Component\Security\Core\User\User: plaintext
providers:
in_memory:
memory:
users:
kevin: { password: test, roles: [ROLE_USER] }
anne: { password: test, roles: [ROLE_ADMIN]}

View File

@@ -0,0 +1,129 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\app;
// get the autoload file
$dir = __DIR__;
$lastDir = null;
while ($dir !== $lastDir) {
$lastDir = $dir;
if (is_file($dir.'/autoload.php')) {
require_once $dir.'/autoload.php';
break;
}
if (is_file($dir.'/autoload.php.dist')) {
require_once $dir.'/autoload.php.dist';
break;
}
if (file_exists($dir.'/vendor/autoload.php')) {
require_once $dir.'/vendor/autoload.php';
break;
}
$dir = dirname($dir);
}
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpKernel\Kernel;
/**
* App Test Kernel for functional tests.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class AppKernel extends Kernel
{
private $varDir;
private $testCase;
private $rootConfig;
public function __construct($varDir, $testCase, $rootConfig, $environment, $debug)
{
if (!is_dir(__DIR__.'/'.$testCase)) {
throw new \InvalidArgumentException(sprintf('The test case "%s" does not exist.', $testCase));
}
$this->varDir = $varDir;
$this->testCase = $testCase;
$fs = new Filesystem();
if (!$fs->isAbsolutePath($rootConfig) && !is_file($rootConfig = __DIR__.'/'.$testCase.'/'.$rootConfig)) {
throw new \InvalidArgumentException(sprintf('The root config "%s" does not exist.', $rootConfig));
}
$this->rootConfig = $rootConfig;
parent::__construct($environment, $debug);
}
/**
* {@inheritdoc}
*/
public function getName()
{
if (null === $this->name) {
$this->name = parent::getName().substr(md5($this->rootConfig), -16);
}
return $this->name;
}
public function registerBundles()
{
if (!is_file($filename = $this->getRootDir().'/'.$this->testCase.'/bundles.php')) {
throw new \RuntimeException(sprintf('The bundles file "%s" does not exist.', $filename));
}
return include $filename;
}
public function getRootDir()
{
return __DIR__;
}
public function getCacheDir()
{
return sys_get_temp_dir().'/'.$this->varDir.'/'.$this->testCase.'/cache/'.$this->environment;
}
public function getLogDir()
{
return sys_get_temp_dir().'/'.$this->varDir.'/'.$this->testCase.'/logs';
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load($this->rootConfig);
}
public function serialize()
{
return serialize(array($this->varDir, $this->testCase, $this->rootConfig, $this->getEnvironment(), $this->isDebug()));
}
public function unserialize($str)
{
$a = unserialize($str);
$this->__construct($a[0], $a[1], $a[2], $a[3], $a[4]);
}
protected function getKernelParameters()
{
$parameters = parent::getKernelParameters();
$parameters['kernel.test_case'] = $this->testCase;
return $parameters;
}
}

View File

@@ -0,0 +1,17 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
return array(
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle(),
new Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\CsrfFormLoginBundle\CsrfFormLoginBundle(),
);

View File

@@ -0,0 +1,47 @@
imports:
- { resource: ./../config/default.yml }
services:
csrf_form_login.form.type:
class: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\CsrfFormLoginBundle\Form\UserLoginType
arguments:
- '@request_stack'
tags:
- { name: form.type }
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
providers:
in_memory:
memory:
users:
johannes: { password: test, roles: [ROLE_USER] }
firewalls:
# This firewall doesn't make sense in combination with the rest of the
# configuration file, but it's here for testing purposes (do not use
# this file in a real world scenario though)
login_form:
pattern: ^/login$
security: false
default:
form_login:
check_path: /login_check
default_target_path: /profile
target_path_parameter: "user_login[_target_path]"
failure_path_parameter: "user_login[_failure_path]"
username_parameter: "user_login[username]"
password_parameter: "user_login[password]"
csrf_parameter: "user_login[_token]"
csrf_token_generator: security.csrf.token_manager
anonymous: ~
logout:
path: /logout_path
target: /
csrf_token_generator: security.csrf.token_manager
access_control:
- { path: .*, roles: IS_AUTHENTICATED_FULLY }

View File

@@ -0,0 +1,13 @@
imports:
- { resource: ./config.yml }
security:
firewalls:
default:
form_login:
login_path: form_login
check_path: form_login_check
default_target_path: form_login_default_target_path
logout:
path: form_logout
target: form_login_homepage

View File

@@ -0,0 +1,2 @@
_csrf_form_login_bundle:
resource: '@CsrfFormLoginBundle/Resources/config/routing.yml'

View File

@@ -0,0 +1,16 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
return array(
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
new Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FirewallEntryPointBundle\FirewallEntryPointBundle(),
);

View File

@@ -0,0 +1,32 @@
framework:
secret: test
router: { resource: "%kernel.root_dir%/%kernel.test_case%/routing.yml" }
validation: { enabled: true, enable_annotations: true }
csrf_protection: true
form: true
test: ~
default_locale: en
session:
storage_id: session.storage.mock_file
profiler: { only_exceptions: false }
services:
logger: { class: Psr\Log\NullLogger }
security:
firewalls:
secure:
pattern: ^/secure/
http_basic: { realm: "Secure Gateway API" }
entry_point: firewall_entry_point.entry_point.stub
default:
anonymous: ~
access_control:
- { path: ^/secure/, roles: ROLE_SECURE }
providers:
in_memory:
memory:
users:
john: { password: doe, roles: [ROLE_SECURE] }
encoders:
Symfony\Component\Security\Core\User\User: plaintext

View File

@@ -0,0 +1,9 @@
imports:
- { resource: ./config.yml }
security:
firewalls:
secure:
pattern: ^/
form_login:
check_path: /login_check

View File

@@ -0,0 +1,2 @@
secure_resource:
path: /secure/resource

View File

@@ -0,0 +1,15 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
return array(
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
);

View File

@@ -0,0 +1,27 @@
imports:
- { resource: ./../config/framework.yml }
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
Custom\Class\Bcrypt\User:
algorithm: bcrypt
cost: 10
Custom\Class\Pbkdf2\User:
algorithm: pbkdf2
hash_algorithm: sha512
encode_as_base64: true
iterations: 1000
Custom\Class\Test\User: test
providers:
in_memory:
memory:
users:
user: { password: userpass, roles: [ 'ROLE_USER' ] }
admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] }
firewalls:
test:
pattern: ^/
security: false

View File

@@ -0,0 +1,13 @@
Symfony Password Encoder Utility
================================
------------------ ------------------------------------------------------------------
Key Value
------------------ ------------------------------------------------------------------
Encoder used Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder
Encoded password password
------------------ ------------------------------------------------------------------
[OK] Password encoding succeeded

View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="{{ _charset }}" />
<title>{% block title %}Welcome!{% endblock %}</title>
{% block stylesheets %}{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
{% block javascripts %}{% endblock %}
</body>
</html>

View File

@@ -0,0 +1,22 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FormLoginBundle\FormLoginBundle;
use Symfony\Bundle\TwigBundle\TwigBundle;
use Symfony\Bundle\SecurityBundle\SecurityBundle;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
return array(
new FrameworkBundle(),
new SecurityBundle(),
new TwigBundle(),
new FormLoginBundle(),
);

View File

@@ -0,0 +1,44 @@
imports:
- { resource: ./../config/default.yml }
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
providers:
in_memory:
memory:
users:
johannes: { password: test, roles: [ROLE_USER] }
firewalls:
# This firewall doesn't make sense in combination with the rest of the
# configuration file, but it's here for testing purposes (do not use
# this file in a real world scenario though)
login_form:
pattern: ^/login$
security: false
default:
form_login:
check_path: /login_check
default_target_path: /profile
logout: ~
anonymous: ~
# This firewall is here just to check its the logout functionality
second_area:
http_basic: ~
anonymous: ~
logout:
target: /second/target
path: /second/logout
access_control:
- { path: ^/unprotected_resource$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/secure-but-not-covered-by-access-control$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/secured-by-one-ip$, ip: 10.10.10.10, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/secured-by-two-ips$, ips: [1.1.1.1, 2.2.2.2], roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/highly_protected_resource$, roles: IS_ADMIN }
- { path: ^/protected-via-expression$, allow_if: "(is_anonymous() and request.headers.get('user-agent') matches '/Firefox/i') or has_role('ROLE_USER')" }
- { path: .*, roles: IS_AUTHENTICATED_FULLY }

View File

@@ -0,0 +1,20 @@
imports:
- { resource: ./../config/default.yml }
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
providers:
in_memory:
memory:
users:
johannes: { password: test, roles: [ROLE_USER] }
firewalls:
default:
form_login:
login_path: localized_login_path
check_path: localized_check_path
failure_handler: localized_form_failure_handler
anonymous: ~

View File

@@ -0,0 +1,26 @@
imports:
- { resource: ./../config/default.yml }
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
providers:
in_memory:
memory:
users:
johannes: { password: test, roles: [ROLE_USER] }
firewalls:
default:
form_login:
login_path: localized_login_path
check_path: localized_check_path
default_target_path: localized_default_target_path
logout:
path: localized_logout_path
target: localized_logout_target_path
anonymous: ~
access_control:
- { path: '^/(?:[a-z]{2})/secure/.*', roles: ROLE_USER }

View File

@@ -0,0 +1,9 @@
imports:
- { resource: ./localized_routes.yml }
security:
firewalls:
default:
form_login:
use_forward: true
failure_forward: true

View File

@@ -0,0 +1,13 @@
imports:
- { resource: ./config.yml }
security:
firewalls:
default:
form_login:
login_path: form_login
check_path: form_login_check
default_target_path: form_login_default_target_path
logout:
path: form_logout
target: form_login_homepage

View File

@@ -0,0 +1,5 @@
_form_login_bundle:
resource: '@FormLoginBundle/Resources/config/routing.yml'
_form_login_localized:
resource: '@FormLoginBundle/Resources/config/localized_routing.yml'

View File

@@ -0,0 +1,14 @@
imports:
- { resource: ./config.yml }
security:
providers:
in_memory:
memory:
users:
user_can_switch: { password: test, roles: [ROLE_USER, ROLE_ALLOWED_TO_SWITCH] }
user_cannot_switch_1: { password: test, roles: [ROLE_USER] }
user_cannot_switch_2: { password: test, roles: [ROLE_USER] }
firewalls:
default:
switch_user: true

View File

@@ -0,0 +1,3 @@
imports:
- { resource: framework.yml }
- { resource: twig.yml }

View File

@@ -0,0 +1,15 @@
framework:
secret: test
router: { resource: "%kernel.root_dir%/%kernel.test_case%/routing.yml" }
validation: { enabled: true, enable_annotations: true }
assets: ~
csrf_protection: true
form: true
test: ~
default_locale: en
session:
storage_id: session.storage.mock_file
profiler: { only_exceptions: false }
services:
logger: { class: Psr\Log\NullLogger }

View File

@@ -0,0 +1,7 @@
framework:
templating: { engines: ['twig'] }
# Twig Configuration
twig:
debug: '%kernel.debug%'
strict_variables: '%kernel.debug%'

View File

@@ -0,0 +1,61 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Security;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\SecurityBundle\Security\FirewallConfig;
class FirewallConfigTest extends TestCase
{
public function testGetters()
{
$listeners = array('logout', 'remember_me', 'anonymous');
$options = array(
'request_matcher' => 'foo_request_matcher',
'security' => false,
'stateless' => false,
'provider' => 'foo_provider',
'context' => 'foo_context',
'entry_point' => 'foo_entry_point',
'access_denied_url' => 'foo_access_denied_url',
'access_denied_handler' => 'foo_access_denied_handler',
'user_checker' => 'foo_user_checker',
);
$config = new FirewallConfig(
'foo_firewall',
$options['user_checker'],
$options['request_matcher'],
$options['security'],
$options['stateless'],
$options['provider'],
$options['context'],
$options['entry_point'],
$options['access_denied_handler'],
$options['access_denied_url'],
$listeners
);
$this->assertSame('foo_firewall', $config->getName());
$this->assertSame($options['request_matcher'], $config->getRequestMatcher());
$this->assertSame($options['security'], $config->isSecurityEnabled());
$this->assertSame($options['stateless'], $config->isStateless());
$this->assertSame($options['provider'], $config->getProvider());
$this->assertSame($options['context'], $config->getContext());
$this->assertSame($options['entry_point'], $config->getEntryPoint());
$this->assertSame($options['access_denied_handler'], $config->getAccessDeniedHandler());
$this->assertSame($options['access_denied_url'], $config->getAccessDeniedUrl());
$this->assertSame($options['user_checker'], $config->getUserChecker());
$this->assertTrue($config->allowsAnonymous());
$this->assertSame($listeners, $config->getListeners());
}
}

View File

@@ -0,0 +1,43 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Security;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\SecurityBundle\Security\FirewallConfig;
use Symfony\Bundle\SecurityBundle\Security\FirewallContext;
use Symfony\Component\Security\Http\Firewall\ExceptionListener;
use Symfony\Component\Security\Http\Firewall\ListenerInterface;
class FirewallContextTest extends TestCase
{
public function testGetters()
{
$config = new FirewallConfig('main', 'user_checker', 'request_matcher');
$exceptionListener = $this
->getMockBuilder(ExceptionListener::class)
->disableOriginalConstructor()
->getMock();
$listeners = array(
$this
->getMockBuilder(ListenerInterface::class)
->disableOriginalConstructor()
->getMock(),
);
$context = new FirewallContext($listeners, $exceptionListener, $config);
$this->assertEquals(array($listeners, $exceptionListener), $context->getContext());
$this->assertEquals($config, $context->getConfig());
}
}

View File

@@ -0,0 +1,79 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Security;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\SecurityBundle\Security\FirewallContext;
use Symfony\Bundle\SecurityBundle\Security\FirewallMap;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
class FirewallMapTest extends TestCase
{
const ATTRIBUTE_FIREWALL_CONTEXT = '_firewall_context';
public function testGetListenersWithEmptyMap()
{
$request = new Request();
$map = array();
$container = $this->getMockBuilder(Container::class)->getMock();
$container->expects($this->never())->method('get');
$firewallMap = new FirewallMap($container, $map);
$this->assertEquals(array(array(), null), $firewallMap->getListeners($request));
$this->assertNull($firewallMap->getFirewallConfig($request));
$this->assertFalse($request->attributes->has(self::ATTRIBUTE_FIREWALL_CONTEXT));
}
public function testGetListenersWithInvalidParameter()
{
$request = new Request();
$request->attributes->set(self::ATTRIBUTE_FIREWALL_CONTEXT, 'foo');
$map = array();
$container = $this->getMockBuilder(Container::class)->getMock();
$container->expects($this->never())->method('get');
$firewallMap = new FirewallMap($container, $map);
$this->assertEquals(array(array(), null), $firewallMap->getListeners($request));
$this->assertNull($firewallMap->getFirewallConfig($request));
$this->assertFalse($request->attributes->has(self::ATTRIBUTE_FIREWALL_CONTEXT));
}
public function testGetListeners()
{
$request = new Request();
$firewallContext = $this->getMockBuilder(FirewallContext::class)->disableOriginalConstructor()->getMock();
$firewallContext->expects($this->once())->method('getConfig')->willReturn('CONFIG');
$firewallContext->expects($this->once())->method('getContext')->willReturn(array('LISTENERS', 'EXCEPTION LISTENER'));
$matcher = $this->getMockBuilder(RequestMatcherInterface::class)->getMock();
$matcher->expects($this->once())
->method('matches')
->with($request)
->willReturn(true);
$container = $this->getMockBuilder(Container::class)->getMock();
$container->expects($this->exactly(2))->method('get')->willReturn($firewallContext);
$firewallMap = new FirewallMap($container, array('security.firewall.map.context.foo' => $matcher));
$this->assertEquals(array('LISTENERS', 'EXCEPTION LISTENER'), $firewallMap->getListeners($request));
$this->assertEquals('CONFIG', $firewallMap->getFirewallConfig($request));
$this->assertEquals('security.firewall.map.context.foo', $request->attributes->get(self::ATTRIBUTE_FIREWALL_CONTEXT));
}
}

View File

@@ -0,0 +1,101 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\SecurityBundle\SecurityUserValueResolver;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\User\UserInterface;
class SecurityUserValueResolverTest extends TestCase
{
public function testResolveNoToken()
{
$tokenStorage = new TokenStorage();
$resolver = new SecurityUserValueResolver($tokenStorage);
$metadata = new ArgumentMetadata('foo', UserInterface::class, false, false, null);
$this->assertFalse($resolver->supports(Request::create('/'), $metadata));
}
public function testResolveNoUser()
{
$mock = $this->getMockBuilder(UserInterface::class)->getMock();
$token = $this->getMockBuilder(TokenInterface::class)->getMock();
$tokenStorage = new TokenStorage();
$tokenStorage->setToken($token);
$resolver = new SecurityUserValueResolver($tokenStorage);
$metadata = new ArgumentMetadata('foo', get_class($mock), false, false, null);
$this->assertFalse($resolver->supports(Request::create('/'), $metadata));
}
public function testResolveWrongType()
{
$tokenStorage = new TokenStorage();
$resolver = new SecurityUserValueResolver($tokenStorage);
$metadata = new ArgumentMetadata('foo', null, false, false, null);
$this->assertFalse($resolver->supports(Request::create('/'), $metadata));
}
public function testResolve()
{
$user = $this->getMockBuilder(UserInterface::class)->getMock();
$token = $this->getMockBuilder(TokenInterface::class)->getMock();
$token->expects($this->any())->method('getUser')->willReturn($user);
$tokenStorage = new TokenStorage();
$tokenStorage->setToken($token);
$resolver = new SecurityUserValueResolver($tokenStorage);
$metadata = new ArgumentMetadata('foo', UserInterface::class, false, false, null);
$this->assertTrue($resolver->supports(Request::create('/'), $metadata));
$this->assertSame(array($user), iterator_to_array($resolver->resolve(Request::create('/'), $metadata)));
}
public function testIntegration()
{
$user = $this->getMockBuilder(UserInterface::class)->getMock();
$token = $this->getMockBuilder(TokenInterface::class)->getMock();
$token->expects($this->any())->method('getUser')->willReturn($user);
$tokenStorage = new TokenStorage();
$tokenStorage->setToken($token);
$argumentResolver = new ArgumentResolver(null, array(new SecurityUserValueResolver($tokenStorage)));
$this->assertSame(array($user), $argumentResolver->getArguments(Request::create('/'), function (UserInterface $user) {}));
}
public function testIntegrationNoUser()
{
$token = $this->getMockBuilder(TokenInterface::class)->getMock();
$tokenStorage = new TokenStorage();
$tokenStorage->setToken($token);
$argumentResolver = new ArgumentResolver(null, array(new SecurityUserValueResolver($tokenStorage), new DefaultValueResolver()));
$this->assertSame(array(null), $argumentResolver->getArguments(Request::create('/'), function (UserInterface $user = null) {}));
}
}
abstract class DummyUser implements UserInterface
{
}
abstract class DummySubUser extends DummyUser
{
}