fixes several bugs

This commit is contained in:
Johannes Schmitt 2011-07-19 16:21:58 +02:00
parent a4f05ac7ab
commit f300edebe4
12 changed files with 138 additions and 34 deletions

View File

@ -77,6 +77,9 @@ RC4 to RC5
Session::getAttributes() -> Session::all() Session::getAttributes() -> Session::all()
Session::setAttributes() -> Session::replace() Session::setAttributes() -> Session::replace()
* {_locale} is not supported in paths in the access_control section anymore. You can
rewrite the paths using a regular expression such as "(?:[a-z]{2})".
RC3 to RC4 RC3 to RC4
---------- ----------

View File

@ -34,6 +34,11 @@ class LocalizedController extends ContainerAware
throw new \RuntimeException('logoutAction() should never be called.'); throw new \RuntimeException('logoutAction() should never be called.');
} }
public function secureAction()
{
throw new \RuntimeException('secureAction() should never be called.');
}
public function profileAction() public function profileAction()
{ {
return new Response('Profile'); return new Response('Profile');

View File

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

View File

@ -26,6 +26,30 @@ class LocalizedRoutesAsPathTest extends WebTestCase
$this->assertEquals('Homepage', $client->followRedirect()->text()); $this->assertEquals('Homepage', $client->followRedirect()->text());
} }
/**
* @dataProvider getLocales
*/
public function testAccessRestrictedResource($locale)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => 'localized_routes.yml'));
$client->insulate();
$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'));
$client->insulate();
$crawler = $client->request('GET', '/'.$locale.'/secure/');
$this->assertEquals(1, count($crawler->selectButton('login')), (string) $client->getResponse());
}
public function getLocales() public function getLocales()
{ {
return array(array('en'), array('de')); return array(array('en'), array('de'));

View File

@ -13,25 +13,37 @@ namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
class SecurityRoutingIntegrationTest extends WebTestCase class SecurityRoutingIntegrationTest extends WebTestCase
{ {
public function testRoutingErrorIsNotExposedForProtectedResourceWhenAnonymous() /**
* @dataProvider getConfigs
*/
public function testRoutingErrorIsNotExposedForProtectedResourceWhenAnonymous($config)
{ {
$client = $this->createClient(array('test_case' => 'StandardFormLogin')); $client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config));
$client->insulate();
$client->request('GET', '/protected_resource'); $client->request('GET', '/protected_resource');
$this->assertRedirect($client->getResponse(), '/login'); $this->assertRedirect($client->getResponse(), '/login');
} }
public function testRoutingErrorIsExposedWhenNotProtected() /**
* @dataProvider getConfigs
*/
public function testRoutingErrorIsExposedWhenNotProtected($config)
{ {
$client = $this->createClient(array('test_case' => 'StandardFormLogin')); $client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config));
$client->insulate();
$client->request('GET', '/unprotected_resource'); $client->request('GET', '/unprotected_resource');
$this->assertEquals(404, $client->getResponse()->getStatusCode()); $this->assertEquals(404, $client->getResponse()->getStatusCode(), (string) $client->getResponse());
} }
public function testRoutingErrorIsNotExposedForProtectedResourceWhenLoggedInWithInsufficientRights() /**
* @dataProvider getConfigs
*/
public function testRoutingErrorIsNotExposedForProtectedResourceWhenLoggedInWithInsufficientRights($config)
{ {
$client = $this->createClient(array('test_case' => 'StandardFormLogin')); $client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config));
$client->insulate();
$form = $client->request('GET', '/login')->selectButton('login')->form(); $form = $client->request('GET', '/login')->selectButton('login')->form();
$form['_username'] = 'johannes'; $form['_username'] = 'johannes';
@ -43,6 +55,11 @@ class SecurityRoutingIntegrationTest extends WebTestCase
$this->assertNotEquals(404, $client->getResponse()->getStatusCode()); $this->assertNotEquals(404, $client->getResponse()->getStatusCode());
} }
public function getConfigs()
{
return array(array('config.yml'), array('routes_as_path.yml'));
}
protected function setUp() protected function setUp()
{ {
parent::setUp(); parent::setUp();

View File

@ -18,7 +18,7 @@ class WebTestCase extends BaseWebTestCase
{ {
static public function assertRedirect($response, $location) static public function assertRedirect($response, $location)
{ {
self::assertTrue($response->isRedirect()); self::assertTrue($response->isRedirect(), 'Response is not a redirect, got status code: '.$response->getStatusCode());
self::assertEquals('http://localhost'.$location, $response->headers->get('Location')); self::assertEquals('http://localhost'.$location, $response->headers->get('Location'));
} }

View File

@ -19,4 +19,8 @@ security:
logout: logout:
path: localized_logout_path path: localized_logout_path
target: localized_logout_target_path target: localized_logout_target_path
anonymous: ~ 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

@ -100,11 +100,7 @@ class RequestMatcher implements RequestMatcherInterface
} }
if (null !== $this->path) { if (null !== $this->path) {
if (null !== $session = $request->getSession()) { $path = str_replace('#', '\\#', $this->path);
$path = strtr($this->path, array('{_locale}' => $session->getLocale(), '#' => '\\#'));
} else {
$path = str_replace('#', '\\#', $this->path);
}
if (!preg_match('#'.$path.'#', $request->getPathInfo())) { if (!preg_match('#'.$path.'#', $request->getPathInfo())) {
return false; return false;

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\Security\Http; namespace Symfony\Component\Security\Http;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\RouterInterface; use Symfony\Component\Routing\RouterInterface;
@ -45,22 +47,10 @@ class HttpUtils
*/ */
public function createRedirectResponse(Request $request, $path, $status = 302) public function createRedirectResponse(Request $request, $path, $status = 302)
{ {
if (0 === strpos($path, '/')) { if ('/' === $path[0]) {
$path = $request->getUriForPath($path); $path = $request->getUriForPath($path);
} elseif (0 !== strpos($path, 'http')) { } elseif (0 !== strpos($path, 'http')) {
// hack (don't have a better solution for now) $this->resetLocale($request);
$context = $this->router->getContext();
try {
$parameters = $this->router->match($request->getPathInfo());
} catch (\Exception $e) {
}
if (isset($parameters['_locale'])) {
$context->setParameter('_locale', $parameters['_locale']);
} elseif ($session = $request->getSession()) {
$context->setParameter('_locale', $session->getLocale());
}
$path = $this->generateUrl($path, true); $path = $this->generateUrl($path, true);
} }
@ -78,10 +68,26 @@ class HttpUtils
public function createRequest(Request $request, $path) public function createRequest(Request $request, $path)
{ {
if ($path && '/' !== $path[0] && 0 !== strpos($path, 'http')) { if ($path && '/' !== $path[0] && 0 !== strpos($path, 'http')) {
$this->resetLocale($request);
$path = $this->generateUrl($path, true); $path = $this->generateUrl($path, true);
} }
return Request::create($path, 'get', array(), $request->cookies->all(), array(), $request->server->all()); $newRequest = Request::create($path, 'get', array(), $request->cookies->all(), array(), $request->server->all());
if ($session = $request->getSession()) {
$newRequest->setSession($session);
}
if ($request->attributes->has(SecurityContextInterface::AUTHENTICATION_ERROR)) {
$newRequest->attributes->set(SecurityContextInterface::AUTHENTICATION_ERROR, $request->attributes->get(SecurityContextInterface::AUTHENTICATION_ERROR));
}
if ($request->attributes->has(SecurityContextInterface::ACCESS_DENIED_ERROR)) {
$newRequest->attributes->set(SecurityContextInterface::ACCESS_DENIED_ERROR, $request->attributes->get(SecurityContextInterface::ACCESS_DENIED_ERROR));
}
if ($request->attributes->has(SecurityContextInterface::LAST_USERNAME)) {
$newRequest->attributes->set(SecurityContextInterface::LAST_USERNAME, $request->attributes->get(SecurityContextInterface::LAST_USERNAME));
}
return $newRequest;
} }
/** /**
@ -107,6 +113,27 @@ class HttpUtils
return $path === $request->getPathInfo(); return $path === $request->getPathInfo();
} }
// hack (don't have a better solution for now)
private function resetLocale(Request $request)
{
$context = $this->router->getContext();
if ($context->getParameter('_locale')) {
return;
}
try {
$parameters = $this->router->match($request->getPathInfo());
if (isset($parameters['_locale'])) {
$context->setParameter('_locale', $parameters['_locale']);
} elseif ($session = $request->getSession()) {
$context->setParameter('_locale', $session->getLocale());
}
} catch (\Exception $e) {
// let's hope user doesn't use the locale in the path
}
}
private function generateUrl($route, $absolute = false) private function generateUrl($route, $absolute = false)
{ {
if (null === $this->router) { if (null === $this->router) {

View File

@ -142,7 +142,7 @@ class RequestMatcherTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($matcher->matches($request)); $this->assertFalse($matcher->matches($request));
} }
public function testPathWithLocale() public function testPathWithLocaleIsNotSupported()
{ {
$matcher = new RequestMatcher(); $matcher = new RequestMatcher();
$request = Request::create('/en/login'); $request = Request::create('/en/login');
@ -152,9 +152,6 @@ class RequestMatcherTest extends \PHPUnit_Framework_TestCase
$request->setSession($session); $request->setSession($session);
$matcher->matchPath('^/{_locale}/login$'); $matcher->matchPath('^/{_locale}/login$');
$this->assertTrue($matcher->matches($request));
$session->setLocale('de');
$this->assertFalse($matcher->matches($request)); $this->assertFalse($matcher->matches($request));
} }

View File

@ -61,6 +61,17 @@ class HttpUtilsTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('bar', $subRequest->server->get('Foo')); $this->assertEquals('bar', $subRequest->server->get('Foo'));
// route name // route name
$utils = new HttpUtils($router = $this->getMockBuilder('Symfony\Component\Routing\Router')->disableOriginalConstructor()->getMock());
$router
->expects($this->once())
->method('generate')
->will($this->returnValue('/foo/bar'))
;
$router
->expects($this->any())
->method('getContext')
->will($this->returnValue($this->getMock('Symfony\Component\Routing\RequestContext')))
;
$subRequest = $utils->createRequest($this->getRequest(), 'foobar'); $subRequest = $utils->createRequest($this->getRequest(), 'foobar');
$this->assertEquals('/foo/bar', $subRequest->getPathInfo()); $this->assertEquals('/foo/bar', $subRequest->getPathInfo());