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,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%'