diff --git a/CHANGELOG-2.3.md b/CHANGELOG-2.3.md
index b8e185e9de783..d0ca6221aca02 100644
--- a/CHANGELOG-2.3.md
+++ b/CHANGELOG-2.3.md
@@ -7,6 +7,35 @@ in 2.3 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v2.3.0...v2.3.1
+* 2.3.40 (2016-04-29)
+
+ * bug #18246 [DependencyInjection] fix ambiguous services schema (backbone87)
+ * bug #18603 [PropertyAccess] ->getValue() should be read-only (nicolas-grekas)
+ * bug #18280 [Routing] add query param if value is different from default (Tobion)
+ * bug #18515 [Filesystem] Better error handling in remove() (nicolas-grekas)
+ * bug #18449 [PropertyAccess] Fix regression (nicolas-grekas)
+ * bug #18467 [DependencyInjection] Resolve aliases before removing abstract services + add tests (nicolas-grekas)
+ * bug #18460 [DomCrawler] Fix select option with empty value (Matt Wells)
+ * bug #18425 [Security] Fixed SwitchUserListener when exiting an impersonation with AnonymousToken (lyrixx)
+ * bug #18317 [Form] fix "prototype" not required when parent form is not required (HeahDude)
+ * bug #18439 [Logging] Add support for Firefox (43+) in ChromePhpHandler (arjenm)
+ * bug #18385 Detect CLI color support for Windows 10 build 10586 (mlocati)
+ * bug #18426 [EventDispatcher] Try first if the event is Stopped (lyrixx)
+ * bug #18265 Optimize ReplaceAliasByActualDefinitionPass (ajb-in)
+ * bug #18358 [Form] NumberToLocalizedStringTransformer should return floats when possible (nicolas-grekas)
+ * bug #17926 [DependencyInjection] Enable alias for service_container (hason)
+ * bug #18336 [Debug] Fix handling of php7 throwables (nicolas-grekas)
+ * bug #18312 [ClassLoader] Fix storing not-found classes in APC cache (nicolas-grekas)
+ * bug #18255 [HttpFoundation] Fix support of custom mime types with parameters (Ener-Getick)
+ * bug #18259 [PropertyAccess] Backport fixes from 2.7 (nicolas-grekas)
+ * bug #18224 [PropertyAccess] Remove most ref mismatches to improve perf (nicolas-grekas)
+ * bug #18210 [PropertyAccess] Throw an UnexpectedTypeException when the type do not match (dunglas, nicolas-grekas)
+ * bug #18216 [Intl] Fix invalid numeric literal on PHP 7 (nicolas-grekas)
+ * bug #18147 [Validator] EmailValidator cannot extract hostname if email contains multiple @ symbols (natechicago)
+ * bug #18175 [Translation] Add support for fuzzy tags in PoFileLoader (nud)
+ * bug #18179 [Form] Fix NumberToLocalizedStringTransformer::reverseTransform with big integers (ovrflo, nicolas-grekas)
+ * bug #18164 [HttpKernel] set s-maxage only if all responses are cacheable (xabbuh)
+
* 2.3.39 (2016-03-13)
* bug #18080 [HttpFoundation] Set the Content-Range header if the requested Range is unsatisfied (jakzal)
diff --git a/CHANGELOG-2.7.md b/CHANGELOG-2.7.md
index 89ee3b549f479..cfe286f2a4caf 100644
--- a/CHANGELOG-2.7.md
+++ b/CHANGELOG-2.7.md
@@ -7,6 +7,14 @@ in 2.7 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v2.7.0...v2.7.1
+* 2.7.13 (2016-05-09)
+
+ * security #18733 limited the maximum length of a submitted username (fabpot)
+ * bug #18730 [FrameworkBundle] prevent calling get() for service_container service (xabbuh)
+ * bug #18709 [DependencyInjection] top-level anonymous services must be public (xabbuh)
+ * bug #18692 add @Event annotation for KernelEvents (Haehnchen)
+ * bug #18246 [DependencyInjection] fix ambiguous services schema (backbone87)
+
* 2.7.12 (2016-04-29)
* bug #18180 [Form] fixed BC break with pre selection of choices with `ChoiceType` and its children (HeahDude)
diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/ContainerBuilderTest.php b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/ContainerBuilderTest.php
index ae13d543b0e1e..3f3c577b846df 100644
--- a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/ContainerBuilderTest.php
+++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/ContainerBuilderTest.php
@@ -33,6 +33,8 @@ public function testCreateProxyServiceWithRuntimeInstantiator()
$builder->register('foo1', 'ProxyManagerBridgeFooClass')->setFile(__DIR__.'/Fixtures/includes/foo.php');
$builder->getDefinition('foo1')->setLazy(true);
+ $builder->compile();
+
/* @var $foo1 \ProxyManager\Proxy\LazyLoadingInterface|\ProxyManager\Proxy\ValueHolderInterface */
$foo1 = $builder->get('foo1');
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php
index d6e0c14da4893..33334e79920c9 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php
@@ -274,6 +274,10 @@ protected function resolveServiceDefinition(ContainerBuilder $builder, $serviceI
return $builder->getAlias($serviceId);
}
+ if ('service_container' === $serviceId) {
+ return $builder;
+ }
+
// the service has been injected in some special way, just return the service
return $builder->get($serviceId);
}
diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
index f4ec265d533f7..9e2e679e61c95 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
@@ -292,6 +292,10 @@ private function processAnonymousServices(\DOMDocument $xml, $file)
if ($services = $this->getChildren($node, 'service')) {
$definitions[$id] = array($services[0], $file, false);
$services[0]->setAttribute('id', $id);
+
+ // anonymous services are always private
+ // we could not use the constant false here, because of XML parsing
+ $services[0]->setAttribute('public', 'false');
}
}
}
@@ -311,9 +315,6 @@ private function processAnonymousServices(\DOMDocument $xml, $file)
foreach ($definitions as $id => $def) {
list($domElement, $file, $wild) = $def;
- // anonymous services are always private
- // we could not use the constant false here, because of XML parsing
- $domElement->setAttribute('public', 'false');
if (null !== $definition = $this->parseDefinition($domElement, $file)) {
$this->container->setDefinition($id, $definition);
diff --git a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd
index c8e747efffbc3..a7a534c9f1b64 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd
+++ b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd
@@ -24,14 +24,28 @@
]]>
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
getDefinition($id);
}
$this->assertEquals('BizClass', $service->getClass(), '->load() uses the same configuration as for the anonymous ones');
- $this->assertFalse($service->isPublic());
+ $this->assertTrue($service->isPublic());
// anonymous services are shared when using decoration definitions
$container->compile();
diff --git a/src/Symfony/Component/DependencyInjection/composer.json b/src/Symfony/Component/DependencyInjection/composer.json
index c2b2550607005..d42c7a0c6c0d6 100644
--- a/src/Symfony/Component/DependencyInjection/composer.json
+++ b/src/Symfony/Component/DependencyInjection/composer.json
@@ -29,6 +29,7 @@
"suggest": {
"symfony/yaml": "",
"symfony/config": "",
+ "symfony/expression-language": "For using expressions in service container configuration",
"symfony/proxy-manager-bridge": "Generate service proxies to lazy load them"
},
"autoload": {
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index bee3360413739..c348cac299911 100644
--- a/src/Symfony/Component/HttpKernel/Kernel.php
+++ b/src/Symfony/Component/HttpKernel/Kernel.php
@@ -58,11 +58,11 @@ abstract class Kernel implements KernelInterface, TerminableInterface
protected $startTime;
protected $loadClassCache;
- const VERSION = '2.7.12';
- const VERSION_ID = 20712;
+ const VERSION = '2.7.13';
+ const VERSION_ID = 20713;
const MAJOR_VERSION = 2;
const MINOR_VERSION = 7;
- const RELEASE_VERSION = 12;
+ const RELEASE_VERSION = 13;
const EXTRA_VERSION = '';
const END_OF_MAINTENANCE = '05/2018';
diff --git a/src/Symfony/Component/HttpKernel/KernelEvents.php b/src/Symfony/Component/HttpKernel/KernelEvents.php
index 8768979da6bd4..abbbfcc0048b9 100644
--- a/src/Symfony/Component/HttpKernel/KernelEvents.php
+++ b/src/Symfony/Component/HttpKernel/KernelEvents.php
@@ -108,6 +108,10 @@ final class KernelEvents
*
* This event allows you to reset the global and environmental state of
* the application, when it was changed during the request.
+ * The event listener method receives a
+ * Symfony\Component\HttpKernel\Event\FinishRequestEvent instance.
+ *
+ * @Event
*
* @var string
*/
diff --git a/src/Symfony/Component/OptionsResolver/README.md b/src/Symfony/Component/OptionsResolver/README.md
index 5768f68e7ff7d..245e69b548d6d 100644
--- a/src/Symfony/Component/OptionsResolver/README.md
+++ b/src/Symfony/Component/OptionsResolver/README.md
@@ -1,7 +1,7 @@
OptionsResolver Component
=========================
-The OptionsResolver component is `array_replace on steroids. It allows you to
+The OptionsResolver component is `array_replace` on steroids. It allows you to
create an options system with required options, defaults, validation (type,
value), normalization and more.
diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php
index 571816ca9ecb2..5f3241f20d62f 100644
--- a/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php
+++ b/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php
@@ -26,7 +26,7 @@ class AnonymousToken extends AbstractToken
* Constructor.
*
* @param string $key The key shared with the authentication provider
- * @param string $user The user
+ * @param string|object $user The user can be a UserInterface instance, or an object implementing a __toString method or the username as a regular string.
* @param RoleInterface[] $roles An array of roles
*/
public function __construct($key, $user, array $roles = array())
diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php
index 1798203690455..5a3fc95327c08 100644
--- a/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php
+++ b/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php
@@ -26,7 +26,7 @@ class PreAuthenticatedToken extends AbstractToken
/**
* Constructor.
*
- * @param string|object $user The user
+ * @param string|object $user The user can be a UserInterface instance, or an object implementing a __toString method or the username as a regular string.
* @param mixed $credentials The user credentials
* @param string $providerKey The provider key
* @param RoleInterface[]|string[] $roles An array of roles
diff --git a/src/Symfony/Component/Security/Core/AuthenticationEvents.php b/src/Symfony/Component/Security/Core/AuthenticationEvents.php
index 90b714267466c..13bce30768908 100644
--- a/src/Symfony/Component/Security/Core/AuthenticationEvents.php
+++ b/src/Symfony/Component/Security/Core/AuthenticationEvents.php
@@ -20,6 +20,8 @@ final class AuthenticationEvents
* The event listener method receives a
* Symfony\Component\Security\Core\Event\AuthenticationEvent instance.
*
+ * @Event
+ *
* @var string
*/
const AUTHENTICATION_SUCCESS = 'security.authentication.success';
@@ -32,6 +34,8 @@ final class AuthenticationEvents
* Symfony\Component\Security\Core\Event\AuthenticationFailureEvent
* instance.
*
+ * @Event
+ *
* @var string
*/
const AUTHENTICATION_FAILURE = 'security.authentication.failure';
diff --git a/src/Symfony/Component/Security/Core/Security.php b/src/Symfony/Component/Security/Core/Security.php
index 14d32f81482e5..84cc77dcf7f32 100644
--- a/src/Symfony/Component/Security/Core/Security.php
+++ b/src/Symfony/Component/Security/Core/Security.php
@@ -21,4 +21,5 @@ final class Security
const ACCESS_DENIED_ERROR = '_security.403_error';
const AUTHENTICATION_ERROR = '_security.last_error';
const LAST_USERNAME = '_security.last_username';
+ const MAX_USERNAME_LENGTH = 4096;
}
diff --git a/src/Symfony/Component/Security/Core/SecurityContextInterface.php b/src/Symfony/Component/Security/Core/SecurityContextInterface.php
index 2a06ca426a487..73edd2383573b 100644
--- a/src/Symfony/Component/Security/Core/SecurityContextInterface.php
+++ b/src/Symfony/Component/Security/Core/SecurityContextInterface.php
@@ -26,4 +26,5 @@ interface SecurityContextInterface extends TokenStorageInterface, AuthorizationC
const ACCESS_DENIED_ERROR = Security::ACCESS_DENIED_ERROR;
const AUTHENTICATION_ERROR = Security::AUTHENTICATION_ERROR;
const LAST_USERNAME = Security::LAST_USERNAME;
+ const MAX_USERNAME_LENGTH = Security::MAX_USERNAME_LENGTH;
}
diff --git a/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php
index 4733b6ac261d5..8123e0e22e7b5 100644
--- a/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php
+++ b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php
@@ -24,6 +24,7 @@
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\SimpleFormAuthenticatorInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
+use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Http\HttpUtils;
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
@@ -116,6 +117,10 @@ protected function attemptAuthentication(Request $request)
$password = $request->get($this->options['password_parameter'], null, true);
}
+ if (strlen($username) > Security::MAX_USERNAME_LENGTH) {
+ throw new BadCredentialsException('Invalid username.');
+ }
+
$request->getSession()->set(Security::LAST_USERNAME, $username);
$token = $this->simpleAuthenticator->createToken($request, $username, $password, $this->providerKey);
diff --git a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php
index 07ab85ae7e8fa..ba4329b0eadc4 100644
--- a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php
+++ b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php
@@ -24,6 +24,7 @@
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
+use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Core\Exception\InvalidArgumentException;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\Security;
@@ -91,6 +92,10 @@ protected function attemptAuthentication(Request $request)
$password = $request->get($this->options['password_parameter'], null, true);
}
+ if (strlen($username) > Security::MAX_USERNAME_LENGTH) {
+ throw new BadCredentialsException('Invalid username.');
+ }
+
$request->getSession()->set(Security::LAST_USERNAME, $username);
return $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey));
diff --git a/src/Symfony/Component/Security/Tests/Http/Firewall/UsernamePasswordFormAuthenticationListenerTest.php b/src/Symfony/Component/Security/Tests/Http/Firewall/UsernamePasswordFormAuthenticationListenerTest.php
new file mode 100644
index 0000000000000..b7c6ab9db5752
--- /dev/null
+++ b/src/Symfony/Component/Security/Tests/Http/Firewall/UsernamePasswordFormAuthenticationListenerTest.php
@@ -0,0 +1,78 @@
+
+ *
+ * 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\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener;
+use Symfony\Component\Security\Core\SecurityContextInterface;
+
+class UsernamePasswordFormAuthenticationListenerTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider getUsernameForLength
+ */
+ public function testHandleWhenUsernameLength($username, $ok)
+ {
+ $request = Request::create('/login_check', 'POST', array('_username' => $username));
+ $request->setSession($this->getMock('Symfony\Component\HttpFoundation\Session\SessionInterface'));
+
+ $httpUtils = $this->getMock('Symfony\Component\Security\Http\HttpUtils');
+ $httpUtils
+ ->expects($this->any())
+ ->method('checkRequestPath')
+ ->will($this->returnValue(true))
+ ;
+
+ $failureHandler = $this->getMock('Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface');
+ $failureHandler
+ ->expects($ok ? $this->never() : $this->once())
+ ->method('onAuthenticationFailure')
+ ->will($this->returnValue(new Response()))
+ ;
+
+ $authenticationManager = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager')->disableOriginalConstructor()->getMock();
+ $authenticationManager
+ ->expects($ok ? $this->once() : $this->never())
+ ->method('authenticate')
+ ->will($this->returnValue(new Response()))
+ ;
+
+ $listener = new UsernamePasswordFormAuthenticationListener(
+ $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'),
+ $authenticationManager,
+ $this->getMock('Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface'),
+ $httpUtils,
+ 'TheProviderKey',
+ $this->getMock('Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface'),
+ $failureHandler,
+ array('require_previous_session' => false)
+ );
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ $event
+ ->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+
+ $listener->handle($event);
+ }
+
+ public function getUsernameForLength()
+ {
+ return array(
+ array(str_repeat('x', SecurityContextInterface::MAX_USERNAME_LENGTH + 1), false),
+ array(str_repeat('x', SecurityContextInterface::MAX_USERNAME_LENGTH - 1), true),
+ );
+ }
+}