Commit d1d45410 authored by Fabien Potencier's avatar Fabien Potencier

merged branch fabpot/security (PR #356)

Commits
-------

18868114 tweaked some docs
6a0f05dd tweaked docs
43134580 updated vendors
12867093 moved security to the dev requirements
320a268e updated the changelog
2b711bc0 added support for the Symfony Security component

Discussion
----------

added support for the Symfony Security component

Some few things are not (yet) configurable, but this extension should cover most common needs and then some more. It is actually as powerful as the support we have in the Symfony full-stack framework.

---------------------------------------------------------------------------

by davedevelopment at 2012-06-13T08:30:42Z

This is awesome. Not only can I throw away my sketchy implementation, I can see all the things I did wrong! Cheers @fabpot!
parents aee53c94 18868114
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
"symfony/routing": "2.1.*" "symfony/routing": "2.1.*"
}, },
"require-dev": { "require-dev": {
"symfony/security": "2.1.*",
"symfony/form": "2.1.*", "symfony/form": "2.1.*",
"monolog/monolog": ">=1.0.0", "monolog/monolog": ">=1.0.0",
"symfony/browser-kit": "2.1.*", "symfony/browser-kit": "2.1.*",
......
{ {
"hash": "2159a9aea3c462e2837553e85846d0ac", "hash": "cb84b3fe6b1c0f5846880d387eb21ead",
"packages": [ "packages": [
{ {
"package": "pimple/pimple", "package": "pimple/pimple",
...@@ -61,13 +61,13 @@ ...@@ -61,13 +61,13 @@
{ {
"package": "doctrine/common", "package": "doctrine/common",
"version": "dev-master", "version": "dev-master",
"alias-pretty-version": "2.3.x-dev", "source-reference": "80838882abc04270fb9bc5812da4ab64e2ee3f88"
"alias-version": "2.3.9999999.9999999-dev"
}, },
{ {
"package": "doctrine/common", "package": "doctrine/common",
"version": "dev-master", "version": "dev-master",
"source-reference": "80838882abc04270fb9bc5812da4ab64e2ee3f88" "alias-pretty-version": "2.3.x-dev",
"alias-version": "2.3.9999999.9999999-dev"
}, },
{ {
"package": "doctrine/dbal", "package": "doctrine/dbal",
...@@ -81,35 +81,35 @@ ...@@ -81,35 +81,35 @@
{ {
"package": "swiftmailer/swiftmailer", "package": "swiftmailer/swiftmailer",
"version": "dev-master", "version": "dev-master",
"alias-pretty-version": "4.1.x-dev", "source-reference": "d33d54cc8a081b0b85734744936ede1ba230dd64"
"alias-version": "4.1.9999999.9999999-dev"
}, },
{ {
"package": "swiftmailer/swiftmailer", "package": "swiftmailer/swiftmailer",
"version": "dev-master", "version": "dev-master",
"source-reference": "d33d54cc8a081b0b85734744936ede1ba230dd64" "alias-pretty-version": "4.1.x-dev",
"alias-version": "4.1.9999999.9999999-dev"
}, },
{ {
"package": "symfony/browser-kit", "package": "symfony/browser-kit",
"version": "dev-master", "version": "dev-master",
"source-reference": "6d1864547be92e51972a416fae9460b8be4afe0e" "alias-pretty-version": "2.1.x-dev",
"alias-version": "2.1.9999999.9999999-dev"
}, },
{ {
"package": "symfony/browser-kit", "package": "symfony/browser-kit",
"version": "dev-master", "version": "dev-master",
"alias-pretty-version": "2.1.x-dev", "source-reference": "6d1864547be92e51972a416fae9460b8be4afe0e"
"alias-version": "2.1.9999999.9999999-dev"
}, },
{ {
"package": "symfony/css-selector", "package": "symfony/css-selector",
"version": "dev-master", "version": "dev-master",
"alias-pretty-version": "2.1.x-dev", "source-reference": "d0a98b37fbb57188766fd7c7d757354397ee6ead"
"alias-version": "2.1.9999999.9999999-dev"
}, },
{ {
"package": "symfony/css-selector", "package": "symfony/css-selector",
"version": "dev-master", "version": "dev-master",
"source-reference": "d0a98b37fbb57188766fd7c7d757354397ee6ead" "alias-pretty-version": "2.1.x-dev",
"alias-version": "2.1.9999999.9999999-dev"
}, },
{ {
"package": "symfony/dom-crawler", "package": "symfony/dom-crawler",
...@@ -136,13 +136,13 @@ ...@@ -136,13 +136,13 @@
{ {
"package": "symfony/form", "package": "symfony/form",
"version": "dev-master", "version": "dev-master",
"source-reference": "e9068070fab8919f63e1a4e6313325082f4a1aa2" "alias-pretty-version": "2.1.x-dev",
"alias-version": "2.1.9999999.9999999-dev"
}, },
{ {
"package": "symfony/form", "package": "symfony/form",
"version": "dev-master", "version": "dev-master",
"alias-pretty-version": "2.1.x-dev", "source-reference": "e9068070fab8919f63e1a4e6313325082f4a1aa2"
"alias-version": "2.1.9999999.9999999-dev"
}, },
{ {
"package": "symfony/locale", "package": "symfony/locale",
...@@ -180,31 +180,36 @@ ...@@ -180,31 +180,36 @@
{ {
"package": "symfony/process", "package": "symfony/process",
"version": "dev-master", "version": "dev-master",
"source-reference": "f4f101fc7c1adb8b157058dcc1715f28f1d53208" "alias-pretty-version": "2.1.x-dev",
"alias-version": "2.1.9999999.9999999-dev"
}, },
{ {
"package": "symfony/process", "package": "symfony/process",
"version": "dev-master", "version": "dev-master",
"alias-pretty-version": "2.1.x-dev", "source-reference": "f4f101fc7c1adb8b157058dcc1715f28f1d53208"
"alias-version": "2.1.9999999.9999999-dev"
}, },
{ {
"package": "symfony/translation", "package": "symfony/security",
"version": "dev-master", "version": "dev-master",
"source-reference": "db3e85934353a130d743b2ddd53dd678c8ebca12" "source-reference": "cfbb58936b3b9e9b5c31d191ed8056acd2932eb8"
}, },
{ {
"package": "symfony/translation", "package": "symfony/security",
"version": "dev-master", "version": "dev-master",
"alias-pretty-version": "2.1.x-dev", "alias-pretty-version": "2.1.x-dev",
"alias-version": "2.1.9999999.9999999-dev" "alias-version": "2.1.9999999.9999999-dev"
}, },
{ {
"package": "symfony/twig-bridge", "package": "symfony/translation",
"version": "dev-master", "version": "dev-master",
"alias-pretty-version": "2.1.x-dev", "alias-pretty-version": "2.1.x-dev",
"alias-version": "2.1.9999999.9999999-dev" "alias-version": "2.1.9999999.9999999-dev"
}, },
{
"package": "symfony/translation",
"version": "dev-master",
"source-reference": "db3e85934353a130d743b2ddd53dd678c8ebca12"
},
{ {
"package": "symfony/twig-bridge", "package": "symfony/twig-bridge",
"version": "dev-master", "version": "dev-master",
...@@ -230,19 +235,13 @@ ...@@ -230,19 +235,13 @@
{ {
"package": "twig/twig", "package": "twig/twig",
"version": "dev-master", "version": "dev-master",
"alias-pretty-version": "1.8.x-dev", "source-reference": "ca33207bb22fe6365d13bdaf034f936e30b53560"
"alias-version": "1.8.9999999.9999999-dev"
}, },
{ {
"package": "twig/twig", "package": "twig/twig",
"version": "dev-master", "version": "dev-master",
"alias-pretty-version": "1.8.x-dev", "alias-pretty-version": "1.8.x-dev",
"alias-version": "1.8.9999999.9999999-dev" "alias-version": "1.8.9999999.9999999-dev"
},
{
"package": "twig/twig",
"version": "dev-master",
"source-reference": "ca33207bb22fe6365d13bdaf034f936e30b53560"
} }
], ],
"aliases": [ "aliases": [
......
...@@ -3,6 +3,8 @@ Changelog ...@@ -3,6 +3,8 @@ Changelog
This changelog references all backward incompatibilities as we introduce them: This changelog references all backward incompatibilities as we introduce them:
* **2012-06-13**: Added an extension for the Symfony Security component
* **2012-05-31**: Made the ``BrowserKit``, ``CssSelector``, ``DomCrawler``, * **2012-05-31**: Made the ``BrowserKit``, ``CssSelector``, ``DomCrawler``,
``Finder`` and ``Process`` components optional dependencies. Projects that ``Finder`` and ``Process`` components optional dependencies. Projects that
depend on them (e.g. through functional tests) should add those dependencies depend on them (e.g. through functional tests) should add those dependencies
......
This diff is collapsed.
...@@ -614,7 +614,7 @@ class Application extends \Pimple implements HttpKernelInterface, EventSubscribe ...@@ -614,7 +614,7 @@ class Application extends \Pimple implements HttpKernelInterface, EventSubscribe
), ),
KernelEvents::CONTROLLER => 'onKernelController', KernelEvents::CONTROLLER => 'onKernelController',
KernelEvents::RESPONSE => 'onKernelResponse', KernelEvents::RESPONSE => 'onKernelResponse',
KernelEvents::EXCEPTION => 'onKernelException', KernelEvents::EXCEPTION => array('onKernelException', -10),
KernelEvents::TERMINATE => 'onKernelTerminate', KernelEvents::TERMINATE => 'onKernelTerminate',
KernelEvents::VIEW => array('onKernelView', -10), KernelEvents::VIEW => array('onKernelView', -10),
); );
......
This diff is collapsed.
...@@ -17,6 +17,7 @@ use Silex\ServiceProviderInterface; ...@@ -17,6 +17,7 @@ use Silex\ServiceProviderInterface;
use Symfony\Bridge\Twig\Extension\RoutingExtension as TwigRoutingExtension; use Symfony\Bridge\Twig\Extension\RoutingExtension as TwigRoutingExtension;
use Symfony\Bridge\Twig\Extension\TranslationExtension as TwigTranslationExtension; use Symfony\Bridge\Twig\Extension\TranslationExtension as TwigTranslationExtension;
use Symfony\Bridge\Twig\Extension\FormExtension as TwigFormExtension; use Symfony\Bridge\Twig\Extension\FormExtension as TwigFormExtension;
use Symfony\Bridge\Twig\Extension\SecurityExtension as TwigSecurityExtension;
/** /**
* Twig Provider. * Twig Provider.
...@@ -54,6 +55,10 @@ class TwigServiceProvider implements ServiceProviderInterface ...@@ -54,6 +55,10 @@ class TwigServiceProvider implements ServiceProviderInterface
$twig->addExtension(new TwigTranslationExtension($app['translator'])); $twig->addExtension(new TwigTranslationExtension($app['translator']));
} }
if (isset($app['security.context'])) {
$twig->addExtension(new TwigSecurityExtension($app['security.context']));
}
if (isset($app['form.factory'])) { if (isset($app['form.factory'])) {
if (!isset($app['twig.form.templates'])) { if (!isset($app['twig.form.templates'])) {
$app['twig.form.templates'] = array('form_div_layout.html.twig'); $app['twig.form.templates'] = array('form_div_layout.html.twig');
......
<?php
/*
* This file is part of the Silex framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Silex\Tests\Provider;
use Silex\Application;
use Silex\WebTestCase;
use Silex\Provider\SecurityServiceProvider;
use Silex\Provider\SessionServiceProvider;
use Symfony\Component\HttpFoundation\Request;
/**
* SecurityServiceProvider
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SecurityServiceProviderTest extends WebTestCase
{
public function setUp()
{
if (!is_dir(__DIR__.'/../../../../vendor/symfony/security')) {
$this->markTestSkipped('Security dependency was not installed.');
}
parent::setUp();
}
public function test()
{
$app = $this->app;
$client = $this->createClient();
$client->request('get', '/');
$this->assertEquals('ANONYMOUS', $client->getResponse()->getContent());
$client->request('post', '/login_check', array('_username' => 'fabien', '_password' => 'bar'));
$this->assertEquals('Bad credentials', $app['security.last_error']($client->getRequest()));
// hack to re-close the session as the previous assertions re-opens it
$client->getRequest()->getSession()->save();
$client->request('post', '/login_check', array('_username' => 'fabien', '_password' => 'foo'));
$this->assertEquals('', $app['security.last_error']($client->getRequest()));
$client->getRequest()->getSession()->save();
$this->assertEquals(302, $client->getResponse()->getStatusCode());
$this->assertEquals('http://localhost/', $client->getResponse()->headers->get('Location'));
$client->request('get', '/');
$this->assertEquals('fabienAUTHENTICATED', $client->getResponse()->getContent());
$client->request('get', '/admin');
$this->assertEquals(403, $client->getResponse()->getStatusCode());
$client->request('get', '/logout');
$this->assertEquals(302, $client->getResponse()->getStatusCode());
$this->assertEquals('http://localhost/', $client->getResponse()->headers->get('Location'));
$client->request('get', '/');
$this->assertEquals('ANONYMOUS', $client->getResponse()->getContent());
$client->request('get', '/admin');
$this->assertEquals(302, $client->getResponse()->getStatusCode());
$this->assertEquals('http://localhost/login', $client->getResponse()->headers->get('Location'));
$client->request('post', '/login_check', array('_username' => 'admin', '_password' => 'foo'));
$this->assertEquals('', $app['security.last_error']($client->getRequest()));
$client->getRequest()->getSession()->save();
$this->assertEquals(302, $client->getResponse()->getStatusCode());
$this->assertEquals('http://localhost/admin', $client->getResponse()->headers->get('Location'));
$client->request('get', '/');
$this->assertEquals('adminAUTHENTICATEDADMIN', $client->getResponse()->getContent());
$client->request('get', '/admin');
$this->assertEquals('admin', $client->getResponse()->getContent());
}
public function createApplication()
{
$app = new Application();
$app->register(new SessionServiceProvider());
$app->register(new SecurityServiceProvider(), array(
'security.firewalls' => array(
'login' => array(
'pattern' => '^/login$',
),
'default' => array(
'pattern' => '^.*$',
'anonymous' => true,
'form' => true,
'logout' => true,
'users' => array(
// password is foo
'fabien' => array('ROLE_USER', '5FZ2Z8QIkA7UTZ4BYkoC+GsReLf569mSKDsfods6LYQ8t+a8EW9oaircfMpmaLbPBh4FOBiiFyLfuZmTSUwzZg=='),
'admin' => array('ROLE_ADMIN', '5FZ2Z8QIkA7UTZ4BYkoC+GsReLf569mSKDsfods6LYQ8t+a8EW9oaircfMpmaLbPBh4FOBiiFyLfuZmTSUwzZg=='),
),
),
),
'security.access_rules' => array(
array('^/admin', 'ROLE_ADMIN'),
),
'security.role_hierarchy' => array(
'ROLE_ADMIN' => array('ROLE_USER'),
),
));
$app->get('/login', function(Request $request) use ($app) {
$app['session']->start();
return $app['security.last_error']($request);
});
$app->get('/', function() use ($app) {
$user = $app['security.context']->getToken()->getUser();
$content = is_object($user) ? $user->getUsername() : 'ANONYMOUS';
if ($app['security.context']->isGranted('IS_AUTHENTICATED_FULLY')) {
$content .= 'AUTHENTICATED';
}
if ($app['security.context']->isGranted('ROLE_ADMIN')) {
$content .= 'ADMIN';
}
return $content;
});
$app->get('/admin', function() use ($app) {
return 'admin';
});
$app['session.test'] = true;
return $app;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment