diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd b/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd
index 1a367b8397213..3b13833629102 100644
--- a/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd
+++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd
@@ -117,7 +117,7 @@
-
+
@@ -176,7 +176,7 @@
-
+
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/Authenticator/CustomAuthenticator.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/Authenticator/CustomAuthenticator.php
new file mode 100644
index 0000000000000..89019e7be41e2
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/Authenticator/CustomAuthenticator.php
@@ -0,0 +1,29 @@
+children()
+ ->scalarNode('foo')->defaultValue('bar')->end()
+ ->end()
+ ;
+ }
+}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/custom_authenticator_under_own_namespace.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/custom_authenticator_under_own_namespace.xml
new file mode 100644
index 0000000000000..177cb88f59e6b
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/custom_authenticator_under_own_namespace.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/custom_authenticator_under_security_namespace.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/custom_authenticator_under_security_namespace.xml
new file mode 100644
index 0000000000000..1dbbc9d9a8901
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/custom_authenticator_under_security_namespace.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/custom_provider_under_own_namespace.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/custom_provider_under_own_namespace.xml
new file mode 100644
index 0000000000000..45d6602516a69
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/custom_provider_under_own_namespace.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/custom_provider_under_security_namespace.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/custom_provider_under_security_namespace.xml
new file mode 100644
index 0000000000000..00890b2d66be0
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/custom_provider_under_security_namespace.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/XmlCustomAuthenticatorTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/XmlCustomAuthenticatorTest.php
new file mode 100644
index 0000000000000..de3db233a2060
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/XmlCustomAuthenticatorTest.php
@@ -0,0 +1,51 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\SecurityBundle\Tests\DependencyInjection;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Bundle\SecurityBundle\DependencyInjection\SecurityExtension;
+use Symfony\Bundle\SecurityBundle\Tests\DependencyInjection\Fixtures\Authenticator\CustomAuthenticator;
+use Symfony\Bundle\SecurityBundle\Tests\DependencyInjection\Fixtures\UserProvider\CustomProvider;
+use Symfony\Component\Config\FileLocator;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
+
+class XmlCustomAuthenticatorTest extends TestCase
+{
+ /**
+ * @dataProvider provideXmlConfigurationFile
+ */
+ public function testCustomProviderElement(string $configurationFile)
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('kernel.debug', false);
+ $container->register('cache.system', \stdClass::class);
+
+ $security = new SecurityExtension();
+ $security->addAuthenticatorFactory(new CustomAuthenticator());
+ $container->registerExtension($security);
+
+ (new XmlFileLoader($container, new FileLocator(__DIR__.'/Fixtures/xml')))->load($configurationFile);
+
+ $container->getCompilerPassConfig()->setRemovingPasses([]);
+ $container->getCompilerPassConfig()->setAfterRemovingPasses([]);
+ $container->compile();
+
+ $this->addToAssertionCount(1);
+ }
+
+ public static function provideXmlConfigurationFile(): iterable
+ {
+ yield 'Custom authenticator element under SecurityBundle’s namespace' => ['custom_authenticator_under_security_namespace.xml'];
+ yield 'Custom authenticator element under its own namespace' => ['custom_authenticator_under_own_namespace.xml'];
+ }
+}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/XmlCustomProviderTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/XmlCustomProviderTest.php
new file mode 100644
index 0000000000000..a3f59fc299a24
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/XmlCustomProviderTest.php
@@ -0,0 +1,50 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\SecurityBundle\Tests\DependencyInjection;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Bundle\SecurityBundle\DependencyInjection\SecurityExtension;
+use Symfony\Bundle\SecurityBundle\Tests\DependencyInjection\Fixtures\UserProvider\CustomProvider;
+use Symfony\Component\Config\FileLocator;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
+
+class XmlCustomProviderTest extends TestCase
+{
+ /**
+ * @dataProvider provideXmlConfigurationFile
+ */
+ public function testCustomProviderElement(string $configurationFile)
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('kernel.debug', false);
+ $container->register('cache.system', \stdClass::class);
+
+ $security = new SecurityExtension();
+ $security->addUserProviderFactory(new CustomProvider());
+ $container->registerExtension($security);
+
+ (new XmlFileLoader($container, new FileLocator(__DIR__.'/Fixtures/xml')))->load($configurationFile);
+
+ $container->getCompilerPassConfig()->setRemovingPasses([]);
+ $container->getCompilerPassConfig()->setAfterRemovingPasses([]);
+ $container->compile();
+
+ $this->addToAssertionCount(1);
+ }
+
+ public static function provideXmlConfigurationFile(): iterable
+ {
+ yield 'Custom provider element under SecurityBundle’s namespace' => ['custom_provider_under_security_namespace.xml'];
+ yield 'Custom provider element under its own namespace' => ['custom_provider_under_own_namespace.xml'];
+ }
+}
diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json
index 097031baffb6d..2ffc3df2e5f12 100644
--- a/src/Symfony/Bundle/SecurityBundle/composer.json
+++ b/src/Symfony/Bundle/SecurityBundle/composer.json
@@ -19,7 +19,7 @@
"php": ">=7.2.5",
"ext-xml": "*",
"symfony/config": "^4.4|^5.0|^6.0",
- "symfony/dependency-injection": "^5.3|^6.0",
+ "symfony/dependency-injection": "^5.4.43|^6.4.11",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/event-dispatcher": "^5.1|^6.0",
"symfony/http-kernel": "^5.3|^6.0",
diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
index 7d52958809f62..c8ecaec19affd 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
@@ -404,7 +404,33 @@ private function parseFileToDOM(string $file): \DOMDocument
try {
$dom = XmlUtils::loadFile($file, [$this, 'validateSchema']);
} catch (\InvalidArgumentException $e) {
- throw new InvalidArgumentException(sprintf('Unable to parse file "%s": ', $file).$e->getMessage(), $e->getCode(), $e);
+ $invalidSecurityElements = [];
+ $errors = explode("\n", $e->getMessage());
+ foreach ($errors as $i => $error) {
+ if (preg_match("#^\[ERROR 1871] Element '\{http://symfony\.com/schema/dic/security}([^']+)'#", $error, $matches)) {
+ $invalidSecurityElements[$i] = $matches[1];
+ }
+ }
+ if ($invalidSecurityElements) {
+ $dom = XmlUtils::loadFile($file);
+
+ foreach ($invalidSecurityElements as $errorIndex => $tagName) {
+ foreach ($dom->getElementsByTagNameNS('http://symfony.com/schema/dic/security', $tagName) as $element) {
+ if (!$parent = $element->parentNode) {
+ continue;
+ }
+ if ('http://symfony.com/schema/dic/security' !== $parent->namespaceURI) {
+ continue;
+ }
+ if ('provider' === $parent->localName || 'firewall' === $parent->localName) {
+ unset($errors[$errorIndex]);
+ }
+ }
+ }
+ }
+ if ($errors) {
+ throw new InvalidArgumentException(sprintf('Unable to parse file "%s": ', $file).implode("/n", $errors), $e->getCode(), $e);
+ }
}
$this->validateExtensions($dom, $file);
@@ -777,6 +803,6 @@ private function loadFromExtensions(\DOMDocument $xml)
*/
public static function convertDomElementToArray(\DOMElement $element)
{
- return XmlUtils::convertDomElementToArray($element);
+ return XmlUtils::convertDomElementToArray($element, false);
}
}