Merge branch '2.0' into 2.1
* 2.0: [DependencyInjection] fixed composer.json [Form] Updated checks for the ICU version from 4.5+ to 4.7+ due to test failures with ICU 4.6 fixed CS small fix of #5984 when the container param is not set fixed CS Use better default ports in urlRedirectAction Add tests for urlRedirectAction Update src/Symfony/Component/DomCrawler/Tests/FormTest.php Update src/Symfony/Component/DomCrawler/Form.php [Security] remove escape charters from username provided by Digest DigestAuthenticationListener [Security] added test extra for digest authentication fixed CS [Security] Fixed digest authentication [Security] Fixed digest authentication [SecurityBundle] Convert Http method to uppercase in the config Use Norm Data instead of Data Conflicts: src/Symfony/Bridge/Doctrine/Form/EventListener/MergeCollectionListener.php src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php src/Symfony/Component/DependencyInjection/composer.json
This commit is contained in:
commit
922c2015f6
@ -57,15 +57,15 @@ class RedirectController extends ContainerAware
|
|||||||
* In case the path is empty, the status code will be 404 when permanent is false
|
* In case the path is empty, the status code will be 404 when permanent is false
|
||||||
* and 410 otherwise.
|
* and 410 otherwise.
|
||||||
*
|
*
|
||||||
* @param string $path The absolute path or URL to redirect to
|
* @param string $path The absolute path or URL to redirect to
|
||||||
* @param Boolean $permanent Whether the redirection is permanent
|
* @param Boolean $permanent Whether the redirect is permanent or not
|
||||||
* @param Boolean $scheme The URL scheme (null to keep the current one)
|
* @param string|null $scheme The URL scheme (null to keep the current one)
|
||||||
* @param integer $httpPort The HTTP port
|
* @param integer|null $httpPort The HTTP port (null to keep the current one for the same scheme or the configured port in the container)
|
||||||
* @param integer $httpsPort The HTTPS port
|
* @param integer|null $httpsPort The HTTPS port (null to keep the current one for the same scheme or the configured port in the container)
|
||||||
*
|
*
|
||||||
* @return Response A Response instance
|
* @return Response A Response instance
|
||||||
*/
|
*/
|
||||||
public function urlRedirectAction($path, $permanent = false, $scheme = null, $httpPort = 80, $httpsPort = 443)
|
public function urlRedirectAction($path, $permanent = false, $scheme = null, $httpPort = null, $httpsPort = null)
|
||||||
{
|
{
|
||||||
if ('' == $path) {
|
if ('' == $path) {
|
||||||
return new Response(null, $permanent ? 410 : 404);
|
return new Response(null, $permanent ? 410 : 404);
|
||||||
@ -89,10 +89,30 @@ class RedirectController extends ContainerAware
|
|||||||
}
|
}
|
||||||
|
|
||||||
$port = '';
|
$port = '';
|
||||||
if ('http' === $scheme && 80 != $httpPort) {
|
if ('http' === $scheme) {
|
||||||
$port = ':'.$httpPort;
|
if (null === $httpPort) {
|
||||||
} elseif ('https' === $scheme && 443 != $httpsPort) {
|
if ('http' === $request->getScheme()) {
|
||||||
$port = ':'.$httpsPort;
|
$httpPort = $request->getPort();
|
||||||
|
} elseif ($this->container->hasParameter('request_listener.http_port')) {
|
||||||
|
$httpPort = $this->container->getParameter('request_listener.http_port');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $httpPort && 80 != $httpPort) {
|
||||||
|
$port = ":$httpPort";
|
||||||
|
}
|
||||||
|
} elseif ('https' === $scheme) {
|
||||||
|
if (null === $httpsPort) {
|
||||||
|
if ('https' === $request->getScheme()) {
|
||||||
|
$httpsPort = $request->getPort();
|
||||||
|
} elseif ($this->container->hasParameter('request_listener.https_port')) {
|
||||||
|
$httpsPort = $this->container->getParameter('request_listener.https_port');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $httpsPort && 443 != $httpsPort) {
|
||||||
|
$port = ":$httpsPort";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$url = $scheme.'://'.$request->getHost().$port.$request->getBaseUrl().$path.$qs;
|
$url = $scheme.'://'.$request->getHost().$port.$request->getBaseUrl().$path.$qs;
|
||||||
|
@ -87,9 +87,7 @@ class RedirectControllerTest extends TestCase
|
|||||||
|
|
||||||
$returnResponse = $controller->redirectAction($route, $permanent);
|
$returnResponse = $controller->redirectAction($route, $permanent);
|
||||||
|
|
||||||
$this->assertInstanceOf('\Symfony\Component\HttpFoundation\Response', $returnResponse);
|
$this->assertRedirectUrl($returnResponse, $url);
|
||||||
|
|
||||||
$this->assertTrue($returnResponse->isRedirect($url));
|
|
||||||
$this->assertEquals($expectedCode, $returnResponse->getStatusCode());
|
$this->assertEquals($expectedCode, $returnResponse->getStatusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,9 +117,143 @@ class RedirectControllerTest extends TestCase
|
|||||||
$controller = new RedirectController();
|
$controller = new RedirectController();
|
||||||
$returnResponse = $controller->urlRedirectAction('http://foo.bar/');
|
$returnResponse = $controller->urlRedirectAction('http://foo.bar/');
|
||||||
|
|
||||||
$this->assertInstanceOf('\Symfony\Component\HttpFoundation\Response', $returnResponse);
|
$this->assertRedirectUrl($returnResponse, 'http://foo.bar/');
|
||||||
|
|
||||||
$this->assertEquals('http://foo.bar/', $returnResponse->headers->get('Location'));
|
|
||||||
$this->assertEquals(302, $returnResponse->getStatusCode());
|
$this->assertEquals(302, $returnResponse->getStatusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testUrlRedirectDefaultPortParameters()
|
||||||
|
{
|
||||||
|
$host = 'www.example.com';
|
||||||
|
$baseUrl = '/base';
|
||||||
|
$path = '/redirect-path';
|
||||||
|
$httpPort = 1080;
|
||||||
|
$httpsPort = 1443;
|
||||||
|
|
||||||
|
$expectedUrl = "https://$host:$httpsPort$baseUrl$path";
|
||||||
|
$request = $this->createRequestObject('http', $host, $httpPort, $baseUrl);
|
||||||
|
$controller = $this->createRedirectController($request, null, $httpsPort);
|
||||||
|
$returnValue = $controller->urlRedirectAction($path, false, 'https');
|
||||||
|
$this->assertRedirectUrl($returnValue, $expectedUrl);
|
||||||
|
|
||||||
|
$expectedUrl = "http://$host:$httpPort$baseUrl$path";
|
||||||
|
$request = $this->createRequestObject('https', $host, $httpPort, $baseUrl);
|
||||||
|
$controller = $this->createRedirectController($request, $httpPort);
|
||||||
|
$returnValue = $controller->urlRedirectAction($path, false, 'http');
|
||||||
|
$this->assertRedirectUrl($returnValue, $expectedUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function urlRedirectProvider()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
// Standard ports
|
||||||
|
array('http', null, null, 'http', 80, ""),
|
||||||
|
array('http', 80, null, 'http', 80, ""),
|
||||||
|
array('https', null, null, 'http', 80, ""),
|
||||||
|
array('https', 80, null, 'http', 80, ""),
|
||||||
|
|
||||||
|
array('http', null, null, 'https', 443, ""),
|
||||||
|
array('http', null, 443, 'https', 443, ""),
|
||||||
|
array('https', null, null, 'https', 443, ""),
|
||||||
|
array('https', null, 443, 'https', 443, ""),
|
||||||
|
|
||||||
|
// Non-standard ports
|
||||||
|
array('http', null, null, 'http', 8080, ":8080"),
|
||||||
|
array('http', 4080, null, 'http', 8080, ":4080"),
|
||||||
|
array('http', 80, null, 'http', 8080, ""),
|
||||||
|
array('https', null, null, 'http', 8080, ""),
|
||||||
|
array('https', null, 8443, 'http', 8080, ":8443"),
|
||||||
|
array('https', null, 443, 'http', 8080, ""),
|
||||||
|
|
||||||
|
array('https', null, null, 'https', 8443, ":8443"),
|
||||||
|
array('https', null, 4443, 'https', 8443, ":4443"),
|
||||||
|
array('https', null, 443, 'https', 8443, ""),
|
||||||
|
array('http', null, null, 'https', 8443, ""),
|
||||||
|
array('http', 8080, 4443, 'https', 8443, ":8080"),
|
||||||
|
array('http', 80, 4443, 'https', 8443, ""),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider urlRedirectProvider
|
||||||
|
*/
|
||||||
|
public function testUrlRedirect($scheme, $httpPort, $httpsPort, $requestScheme, $requestPort, $expectedPort)
|
||||||
|
{
|
||||||
|
$host = 'www.example.com';
|
||||||
|
$baseUrl = '/base';
|
||||||
|
$path = '/redirect-path';
|
||||||
|
$expectedUrl = "$scheme://$host$expectedPort$baseUrl$path";
|
||||||
|
|
||||||
|
$request = $this->createRequestObject($requestScheme, $host, $requestPort, $baseUrl);
|
||||||
|
$controller = $this->createRedirectController($request);
|
||||||
|
|
||||||
|
$returnValue = $controller->urlRedirectAction($path, false, $scheme, $httpPort, $httpsPort);
|
||||||
|
$this->assertRedirectUrl($returnValue, $expectedUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createRequestObject($scheme, $host, $port, $baseUrl)
|
||||||
|
{
|
||||||
|
$request = $this->getMock('Symfony\Component\HttpFoundation\Request');
|
||||||
|
$request
|
||||||
|
->expects($this->any())
|
||||||
|
->method('getScheme')
|
||||||
|
->will($this->returnValue($scheme));
|
||||||
|
$request
|
||||||
|
->expects($this->any())
|
||||||
|
->method('getHost')
|
||||||
|
->will($this->returnValue($host));
|
||||||
|
$request
|
||||||
|
->expects($this->any())
|
||||||
|
->method('getPort')
|
||||||
|
->will($this->returnValue($port));
|
||||||
|
$request
|
||||||
|
->expects($this->any())
|
||||||
|
->method('getBaseUrl')
|
||||||
|
->will($this->returnValue($baseUrl));
|
||||||
|
|
||||||
|
return $request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createRedirectController(Request $request, $httpPort = null, $httpsPort = null)
|
||||||
|
{
|
||||||
|
$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
|
||||||
|
$container
|
||||||
|
->expects($this->at(0))
|
||||||
|
->method('get')
|
||||||
|
->with($this->equalTo('request'))
|
||||||
|
->will($this->returnValue($request));
|
||||||
|
if (null !== $httpPort) {
|
||||||
|
$container
|
||||||
|
->expects($this->once())
|
||||||
|
->method('hasParameter')
|
||||||
|
->with($this->equalTo('request_listener.http_port'))
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
$container
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getParameter')
|
||||||
|
->with($this->equalTo('request_listener.http_port'))
|
||||||
|
->will($this->returnValue($httpPort));
|
||||||
|
}
|
||||||
|
if (null !== $httpsPort) {
|
||||||
|
$container
|
||||||
|
->expects($this->once())
|
||||||
|
->method('hasParameter')
|
||||||
|
->with($this->equalTo('request_listener.https_port'))
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
$container
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getParameter')
|
||||||
|
->with($this->equalTo('request_listener.https_port'))
|
||||||
|
->will($this->returnValue($httpsPort));
|
||||||
|
}
|
||||||
|
|
||||||
|
$controller = new RedirectController();
|
||||||
|
$controller->setContainer($container);
|
||||||
|
|
||||||
|
return $controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function assertRedirectUrl(Response $returnResponse, $expectedUrl)
|
||||||
|
{
|
||||||
|
$this->assertTrue($returnResponse->isRedirect($expectedUrl), "Expected: $expectedUrl\nGot: ".$returnResponse->headers->get('Location'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,7 +182,7 @@ class SecurityExtension extends Extension
|
|||||||
$container,
|
$container,
|
||||||
$access['path'],
|
$access['path'],
|
||||||
$access['host'],
|
$access['host'],
|
||||||
count($access['methods']) === 0 ? null : $access['methods'],
|
$access['methods'],
|
||||||
$access['ip']
|
$access['ip']
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -574,7 +574,7 @@ class SecurityExtension extends Extension
|
|||||||
return $switchUserListenerId;
|
return $switchUserListenerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createRequestMatcher($container, $path = null, $host = null, $methods = null, $ip = null, array $attributes = array())
|
private function createRequestMatcher($container, $path = null, $host = null, $methods = array(), $ip = null, array $attributes = array())
|
||||||
{
|
{
|
||||||
$serialized = serialize(array($path, $host, $methods, $ip, $attributes));
|
$serialized = serialize(array($path, $host, $methods, $ip, $attributes));
|
||||||
$id = 'security.request_matcher.'.md5($serialized).sha1($serialized);
|
$id = 'security.request_matcher.'.md5($serialized).sha1($serialized);
|
||||||
@ -583,6 +583,10 @@ class SecurityExtension extends Extension
|
|||||||
return $this->requestMatchers[$id];
|
return $this->requestMatchers[$id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($methods) {
|
||||||
|
$methods = array_map('strtoupper', (array) $methods);
|
||||||
|
}
|
||||||
|
|
||||||
// only add arguments that are necessary
|
// only add arguments that are necessary
|
||||||
$arguments = array($path, $host, $methods, $ip, $attributes);
|
$arguments = array($path, $host, $methods, $ip, $attributes);
|
||||||
while (count($arguments) > 0 && !end($arguments)) {
|
while (count($arguments) > 0 && !end($arguments)) {
|
||||||
|
@ -63,7 +63,7 @@ $container->loadFromExtension('security', array(
|
|||||||
),
|
),
|
||||||
|
|
||||||
'access_control' => array(
|
'access_control' => array(
|
||||||
array('path' => '/blog/524', 'role' => 'ROLE_USER', 'requires_channel' => 'https'),
|
array('path' => '/blog/524', 'role' => 'ROLE_USER', 'requires_channel' => 'https', 'methods' => array('get', 'POST')),
|
||||||
array('path' => '/blog/.*', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY'),
|
array('path' => '/blog/.*', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY'),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@
|
|||||||
<role id="ROLE_SUPER_ADMIN">ROLE_USER,ROLE_ADMIN,ROLE_ALLOWED_TO_SWITCH</role>
|
<role id="ROLE_SUPER_ADMIN">ROLE_USER,ROLE_ADMIN,ROLE_ALLOWED_TO_SWITCH</role>
|
||||||
<role id="ROLE_REMOTE">ROLE_USER,ROLE_ADMIN</role>
|
<role id="ROLE_REMOTE">ROLE_USER,ROLE_ADMIN</role>
|
||||||
|
|
||||||
<rule path="/blog/524" role="ROLE_USER" requires-channel="https" />
|
<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' path="/blog/.*" />
|
||||||
</config>
|
</config>
|
||||||
</srv:container>
|
</srv:container>
|
||||||
|
@ -51,7 +51,7 @@ security:
|
|||||||
ROLE_REMOTE: ROLE_USER,ROLE_ADMIN
|
ROLE_REMOTE: ROLE_USER,ROLE_ADMIN
|
||||||
|
|
||||||
access_control:
|
access_control:
|
||||||
- { path: /blog/524, role: ROLE_USER, requires_channel: https }
|
- { path: /blog/524, role: ROLE_USER, requires_channel: https, methods: [get, POST]}
|
||||||
-
|
-
|
||||||
path: /blog/.*
|
path: /blog/.*
|
||||||
role: IS_AUTHENTICATED_ANONYMOUSLY
|
role: IS_AUTHENTICATED_ANONYMOUSLY
|
||||||
|
@ -102,6 +102,7 @@ abstract class SecurityExtensionTest extends \PHPUnit_Framework_TestCase
|
|||||||
$matcherIds = array();
|
$matcherIds = array();
|
||||||
foreach ($rules as $rule) {
|
foreach ($rules as $rule) {
|
||||||
list($matcherId, $roles, $channel) = $rule;
|
list($matcherId, $roles, $channel) = $rule;
|
||||||
|
$requestMatcher = $container->getDefinition($matcherId);
|
||||||
|
|
||||||
$this->assertFalse(isset($matcherIds[$matcherId]));
|
$this->assertFalse(isset($matcherIds[$matcherId]));
|
||||||
$matcherIds[$matcherId] = true;
|
$matcherIds[$matcherId] = true;
|
||||||
@ -110,9 +111,17 @@ abstract class SecurityExtensionTest extends \PHPUnit_Framework_TestCase
|
|||||||
if (1 === $i) {
|
if (1 === $i) {
|
||||||
$this->assertEquals(array('ROLE_USER'), $roles);
|
$this->assertEquals(array('ROLE_USER'), $roles);
|
||||||
$this->assertEquals('https', $channel);
|
$this->assertEquals('https', $channel);
|
||||||
|
$this->assertEquals(
|
||||||
|
array('/blog/524', null, array('GET', 'POST')),
|
||||||
|
$requestMatcher->getArguments()
|
||||||
|
);
|
||||||
} elseif (2 === $i) {
|
} elseif (2 === $i) {
|
||||||
$this->assertEquals(array('IS_AUTHENTICATED_ANONYMOUSLY'), $roles);
|
$this->assertEquals(array('IS_AUTHENTICATED_ANONYMOUSLY'), $roles);
|
||||||
$this->assertNull($channel);
|
$this->assertNull($channel);
|
||||||
|
$this->assertEquals(
|
||||||
|
array('/blog/.*'),
|
||||||
|
$requestMatcher->getArguments()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -359,7 +359,7 @@ class Form extends Link implements \ArrayAccess
|
|||||||
$xpath = new \DOMXPath($document);
|
$xpath = new \DOMXPath($document);
|
||||||
|
|
||||||
foreach ($xpath->query('descendant::input | descendant::button | descendant::textarea | descendant::select', $root) as $node) {
|
foreach ($xpath->query('descendant::input | descendant::button | descendant::textarea | descendant::select', $root) as $node) {
|
||||||
if (!$node->hasAttribute('name')) {
|
if (!$node->hasAttribute('name') || !$node->getAttribute('name')) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,6 +126,12 @@ class FormTest extends \PHPUnit_Framework_TestCase
|
|||||||
<input type="submit" />',
|
<input type="submit" />',
|
||||||
array(),
|
array(),
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'does not take into account input fields with an empty name attribute value',
|
||||||
|
'<input type="text" name="" value="foo" />
|
||||||
|
<input type="submit" />',
|
||||||
|
array(),
|
||||||
|
),
|
||||||
array(
|
array(
|
||||||
'takes into account disabled input fields',
|
'takes into account disabled input fields',
|
||||||
'<input type="text" name="foo" value="foo" disabled="disabled" />
|
'<input type="text" name="foo" value="foo" disabled="disabled" />
|
||||||
|
@ -96,8 +96,8 @@ class NumberToLocalizedStringTransformerTest extends LocalizedTestCase
|
|||||||
|
|
||||||
public function testDecimalSeparatorMayBeDotIfGroupingSeparatorIsNotDot()
|
public function testDecimalSeparatorMayBeDotIfGroupingSeparatorIsNotDot()
|
||||||
{
|
{
|
||||||
if ($this->isLowerThanIcuVersion('4.5')) {
|
if ($this->isLowerThanIcuVersion('4.7')) {
|
||||||
$this->markTestSkipped('Please upgrade ICU version to 4.5+');
|
$this->markTestSkipped('Please upgrade ICU version to 4.7+');
|
||||||
}
|
}
|
||||||
|
|
||||||
\Locale::setDefault('fr');
|
\Locale::setDefault('fr');
|
||||||
@ -117,8 +117,8 @@ class NumberToLocalizedStringTransformerTest extends LocalizedTestCase
|
|||||||
*/
|
*/
|
||||||
public function testDecimalSeparatorMayNotBeDotIfGroupingSeparatorIsDot()
|
public function testDecimalSeparatorMayNotBeDotIfGroupingSeparatorIsDot()
|
||||||
{
|
{
|
||||||
if ($this->isLowerThanIcuVersion('4.5')) {
|
if ($this->isLowerThanIcuVersion('4.7')) {
|
||||||
$this->markTestSkipped('Please upgrade ICU version to 4.5+');
|
$this->markTestSkipped('Please upgrade ICU version to 4.7+');
|
||||||
}
|
}
|
||||||
|
|
||||||
$transformer = new NumberToLocalizedStringTransformer(null, true);
|
$transformer = new NumberToLocalizedStringTransformer(null, true);
|
||||||
@ -131,8 +131,8 @@ class NumberToLocalizedStringTransformerTest extends LocalizedTestCase
|
|||||||
*/
|
*/
|
||||||
public function testDecimalSeparatorMayNotBeDotIfGroupingSeparatorIsDot_noGroupSep()
|
public function testDecimalSeparatorMayNotBeDotIfGroupingSeparatorIsDot_noGroupSep()
|
||||||
{
|
{
|
||||||
if ($this->isLowerThanIcuVersion('4.5')) {
|
if ($this->isLowerThanIcuVersion('4.7')) {
|
||||||
$this->markTestSkipped('Please upgrade ICU version to 4.5+');
|
$this->markTestSkipped('Please upgrade ICU version to 4.7+');
|
||||||
}
|
}
|
||||||
|
|
||||||
$transformer = new NumberToLocalizedStringTransformer(null, true);
|
$transformer = new NumberToLocalizedStringTransformer(null, true);
|
||||||
@ -151,8 +151,8 @@ class NumberToLocalizedStringTransformerTest extends LocalizedTestCase
|
|||||||
|
|
||||||
public function testDecimalSeparatorMayBeCommaIfGroupingSeparatorIsNotComma()
|
public function testDecimalSeparatorMayBeCommaIfGroupingSeparatorIsNotComma()
|
||||||
{
|
{
|
||||||
if ($this->isLowerThanIcuVersion('4.5')) {
|
if ($this->isLowerThanIcuVersion('4.7')) {
|
||||||
$this->markTestSkipped('Please upgrade ICU version to 4.5+');
|
$this->markTestSkipped('Please upgrade ICU version to 4.7+');
|
||||||
}
|
}
|
||||||
|
|
||||||
\Locale::setDefault('ak');
|
\Locale::setDefault('ak');
|
||||||
@ -172,8 +172,8 @@ class NumberToLocalizedStringTransformerTest extends LocalizedTestCase
|
|||||||
*/
|
*/
|
||||||
public function testDecimalSeparatorMayNotBeCommaIfGroupingSeparatorIsComma()
|
public function testDecimalSeparatorMayNotBeCommaIfGroupingSeparatorIsComma()
|
||||||
{
|
{
|
||||||
if ($this->isLowerThanIcuVersion('4.5')) {
|
if ($this->isLowerThanIcuVersion('4.7')) {
|
||||||
$this->markTestSkipped('Please upgrade ICU version to 4.5+');
|
$this->markTestSkipped('Please upgrade ICU version to 4.7+');
|
||||||
}
|
}
|
||||||
|
|
||||||
\Locale::setDefault('en');
|
\Locale::setDefault('en');
|
||||||
@ -187,8 +187,8 @@ class NumberToLocalizedStringTransformerTest extends LocalizedTestCase
|
|||||||
*/
|
*/
|
||||||
public function testDecimalSeparatorMayNotBeCommaIfGroupingSeparatorIsComma_noGroupSep()
|
public function testDecimalSeparatorMayNotBeCommaIfGroupingSeparatorIsComma_noGroupSep()
|
||||||
{
|
{
|
||||||
if ($this->isLowerThanIcuVersion('4.5')) {
|
if ($this->isLowerThanIcuVersion('4.7')) {
|
||||||
$this->markTestSkipped('Please upgrade ICU version to 4.5+');
|
$this->markTestSkipped('Please upgrade ICU version to 4.7+');
|
||||||
}
|
}
|
||||||
|
|
||||||
\Locale::setDefault('en');
|
\Locale::setDefault('en');
|
||||||
|
@ -141,11 +141,12 @@ class DigestData
|
|||||||
public function __construct($header)
|
public function __construct($header)
|
||||||
{
|
{
|
||||||
$this->header = $header;
|
$this->header = $header;
|
||||||
$parts = preg_split('/, /', $header);
|
preg_match_all('/(\w+)=("((?:[^"\\\\]|\\\\.)+)"|([^\s,$]+))/', $header, $matches, PREG_SET_ORDER);
|
||||||
$this->elements = array();
|
$this->elements = array();
|
||||||
foreach ($parts as $part) {
|
foreach ($matches as $match) {
|
||||||
list($key, $value) = explode('=', $part);
|
if (isset($match[1]) && isset($match[3])) {
|
||||||
$this->elements[$key] = '"' === $value[0] ? substr($value, 1, -1) : $value;
|
$this->elements[$match[1]] = isset($match[4]) ? $match[4] : $match[3];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +157,7 @@ class DigestData
|
|||||||
|
|
||||||
public function getUsername()
|
public function getUsername()
|
||||||
{
|
{
|
||||||
return $this->elements['username'];
|
return strtr($this->elements['username'], array("\\\"" => "\"", "\\\\" => "\\"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validateAndDecode($entryPointKey, $expectedRealm)
|
public function validateAndDecode($entryPointKey, $expectedRealm)
|
||||||
@ -188,7 +189,7 @@ class DigestData
|
|||||||
$this->nonceExpiryTime = $nonceTokens[0];
|
$this->nonceExpiryTime = $nonceTokens[0];
|
||||||
|
|
||||||
if (md5($this->nonceExpiryTime.':'.$entryPointKey) !== $nonceTokens[1]) {
|
if (md5($this->nonceExpiryTime.':'.$entryPointKey) !== $nonceTokens[1]) {
|
||||||
new BadCredentialsException(sprintf('Nonce token compromised "%s".', $nonceAsPlainText));
|
throw new BadCredentialsException(sprintf('Nonce token compromised "%s".', $nonceAsPlainText));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,181 @@
|
|||||||
|
<?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\Component\Security\Tests\Http\Firewall;
|
||||||
|
|
||||||
|
use Symfony\Component\Security\Http\Firewall\DigestData;
|
||||||
|
|
||||||
|
class DigestDataTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
public function testGetResponse()
|
||||||
|
{
|
||||||
|
$digestAuth = new DigestData(
|
||||||
|
'username="user", realm="Welcome, robot!", ' .
|
||||||
|
'nonce="MTM0NzMyMTgyMy42NzkzOmRlZjM4NmIzOGNjMjE0OWJiNDU0MDAxNzJmYmM1MmZl", ' .
|
||||||
|
'uri="/path/info?p1=5&p2=5", cnonce="MDIwODkz", nc=00000001, qop="auth", ' .
|
||||||
|
'response="b52938fc9e6d7c01be7702ece9031b42"'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals('b52938fc9e6d7c01be7702ece9031b42', $digestAuth->getResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetUsername()
|
||||||
|
{
|
||||||
|
$digestAuth = new DigestData(
|
||||||
|
'username="user", realm="Welcome, robot!", ' .
|
||||||
|
'nonce="MTM0NzMyMTgyMy42NzkzOmRlZjM4NmIzOGNjMjE0OWJiNDU0MDAxNzJmYmM1MmZl", ' .
|
||||||
|
'uri="/path/info?p1=5&p2=5", cnonce="MDIwODkz", nc=00000001, qop="auth", ' .
|
||||||
|
'response="b52938fc9e6d7c01be7702ece9031b42"'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals('user', $digestAuth->getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetUsernameWithQuote()
|
||||||
|
{
|
||||||
|
$digestAuth = new DigestData(
|
||||||
|
'username="\"user\"", realm="Welcome, robot!", ' .
|
||||||
|
'nonce="MTM0NzMyMTgyMy42NzkzOmRlZjM4NmIzOGNjMjE0OWJiNDU0MDAxNzJmYmM1MmZl", ' .
|
||||||
|
'uri="/path/info?p1=5&p2=5", cnonce="MDIwODkz", nc=00000001, qop="auth", ' .
|
||||||
|
'response="b52938fc9e6d7c01be7702ece9031b42"'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals('"user"', $digestAuth->getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetUsernameWithQuoteAndEscape()
|
||||||
|
{
|
||||||
|
$digestAuth = new DigestData(
|
||||||
|
'username="\"u\\\\\"ser\"", realm="Welcome, robot!", ' .
|
||||||
|
'nonce="MTM0NzMyMTgyMy42NzkzOmRlZjM4NmIzOGNjMjE0OWJiNDU0MDAxNzJmYmM1MmZl", ' .
|
||||||
|
'uri="/path/info?p1=5&p2=5", cnonce="MDIwODkz", nc=00000001, qop="auth", ' .
|
||||||
|
'response="b52938fc9e6d7c01be7702ece9031b42"'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals('"u\\"ser"', $digestAuth->getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetUsernameWithSingleQuote()
|
||||||
|
{
|
||||||
|
$digestAuth = new DigestData(
|
||||||
|
'username="\"u\'ser\"", realm="Welcome, robot!", ' .
|
||||||
|
'nonce="MTM0NzMyMTgyMy42NzkzOmRlZjM4NmIzOGNjMjE0OWJiNDU0MDAxNzJmYmM1MmZl", ' .
|
||||||
|
'uri="/path/info?p1=5&p2=5", cnonce="MDIwODkz", nc=00000001, qop="auth", ' .
|
||||||
|
'response="b52938fc9e6d7c01be7702ece9031b42"'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals('"u\'ser"', $digestAuth->getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetUsernameWithSingleQuoteAndEscape()
|
||||||
|
{
|
||||||
|
$digestAuth = new DigestData(
|
||||||
|
'username="\"u\\\'ser\"", realm="Welcome, robot!", ' .
|
||||||
|
'nonce="MTM0NzMyMTgyMy42NzkzOmRlZjM4NmIzOGNjMjE0OWJiNDU0MDAxNzJmYmM1MmZl", ' .
|
||||||
|
'uri="/path/info?p1=5&p2=5", cnonce="MDIwODkz", nc=00000001, qop="auth", ' .
|
||||||
|
'response="b52938fc9e6d7c01be7702ece9031b42"'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals('"u\\\'ser"', $digestAuth->getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetUsernameWithEscape()
|
||||||
|
{
|
||||||
|
$digestAuth = new DigestData(
|
||||||
|
'username="\"u\\ser\"", realm="Welcome, robot!", ' .
|
||||||
|
'nonce="MTM0NzMyMTgyMy42NzkzOmRlZjM4NmIzOGNjMjE0OWJiNDU0MDAxNzJmYmM1MmZl", ' .
|
||||||
|
'uri="/path/info?p1=5&p2=5", cnonce="MDIwODkz", nc=00000001, qop="auth", ' .
|
||||||
|
'response="b52938fc9e6d7c01be7702ece9031b42"'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals('"u\\ser"', $digestAuth->getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidateAndDecode()
|
||||||
|
{
|
||||||
|
$time = microtime(true);
|
||||||
|
$key = 'ThisIsAKey';
|
||||||
|
$nonce = base64_encode($time . ':' . md5($time . ':' . $key));
|
||||||
|
|
||||||
|
$digestAuth = new DigestData(
|
||||||
|
'username="user", realm="Welcome, robot!", nonce="' . $nonce . '", ' .
|
||||||
|
'uri="/path/info?p1=5&p2=5", cnonce="MDIwODkz", nc=00000001, qop="auth", ' .
|
||||||
|
'response="b52938fc9e6d7c01be7702ece9031b42"'
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$digestAuth->validateAndDecode($key, 'Welcome, robot!');
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->fail(sprintf('testValidateAndDecode fail with message: %s', $e->getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCalculateServerDigest()
|
||||||
|
{
|
||||||
|
$this->calculateServerDigest('user', 'Welcome, robot!', 'pass,word=password', 'ThisIsAKey', '00000001', 'MDIwODkz', 'auth', 'GET', '/path/info?p1=5&p2=5');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCalculateServerDigestWithQuote()
|
||||||
|
{
|
||||||
|
$this->calculateServerDigest('\"user\"', 'Welcome, \"robot\"!', 'pass,word=password', 'ThisIsAKey', '00000001', 'MDIwODkz', 'auth', 'GET', '/path/info?p1=5&p2=5');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCalculateServerDigestWithQuoteAndEscape()
|
||||||
|
{
|
||||||
|
$this->calculateServerDigest('\"u\\\\\"ser\"', 'Welcome, \"robot\"!', 'pass,word=password', 'ThisIsAKey', '00000001', 'MDIwODkz', 'auth', 'GET', '/path/info?p1=5&p2=5');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCalculateServerDigestEscape()
|
||||||
|
{
|
||||||
|
$this->calculateServerDigest('\"u\\ser\"', 'Welcome, \"robot\"!', 'pass,word=password', 'ThisIsAKey', '00000001', 'MDIwODkz', 'auth', 'GET', '/path/info?p1=5&p2=5');
|
||||||
|
$this->calculateServerDigest('\"u\\ser\\\\\"', 'Welcome, \"robot\"!', 'pass,word=password', 'ThisIsAKey', '00000001', 'MDIwODkz', 'auth', 'GET', '/path/info?p1=5&p2=5');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsNonceExpired()
|
||||||
|
{
|
||||||
|
$time = microtime(true) + 10;
|
||||||
|
$key = 'ThisIsAKey';
|
||||||
|
$nonce = base64_encode($time . ':' . md5($time . ':' . $key));
|
||||||
|
|
||||||
|
$digestAuth = new DigestData(
|
||||||
|
'username="user", realm="Welcome, robot!", nonce="' . $nonce . '", ' .
|
||||||
|
'uri="/path/info?p1=5&p2=5", cnonce="MDIwODkz", nc=00000001, qop="auth", ' .
|
||||||
|
'response="b52938fc9e6d7c01be7702ece9031b42"'
|
||||||
|
);
|
||||||
|
|
||||||
|
$digestAuth->validateAndDecode($key, 'Welcome, robot!');
|
||||||
|
|
||||||
|
$this->assertFalse($digestAuth->isNonceExpired());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
class_exists('Symfony\Component\Security\Http\Firewall\DigestAuthenticationListener', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function calculateServerDigest($username, $realm, $password, $key, $nc, $cnonce, $qop, $method, $uri)
|
||||||
|
{
|
||||||
|
$time = microtime(true);
|
||||||
|
$nonce = base64_encode($time . ':' . md5($time . ':' . $key));
|
||||||
|
|
||||||
|
$response = md5(
|
||||||
|
md5($username . ':' . $realm . ':' . $password) . ':' . $nonce . ':' . $nc . ':' . $cnonce . ':' . $qop . ':' . md5($method . ':' . $uri)
|
||||||
|
);
|
||||||
|
|
||||||
|
$digest = sprintf('username="%s", realm="%s", nonce="%s", uri="%s", cnonce="%s", nc=%s, qop="%s", response="%s"',
|
||||||
|
$username, $realm, $nonce, $uri, $cnonce, $nc, $qop, $response
|
||||||
|
);
|
||||||
|
|
||||||
|
$digestAuth = new DigestData($digest);
|
||||||
|
|
||||||
|
$this->assertEquals($digestAuth->getResponse(), $digestAuth->calculateServerDigest($password, $method));
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user