From 4a5a327b1ff760ae7d19bef23798e7ab1d543dad Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 27 May 2023 10:05:50 +0200 Subject: [PATCH 01/25] Update CHANGELOG for 5.4.24 --- CHANGELOG-5.4.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/CHANGELOG-5.4.md b/CHANGELOG-5.4.md index 8241220390c11..dca25ff5b0d50 100644 --- a/CHANGELOG-5.4.md +++ b/CHANGELOG-5.4.md @@ -7,6 +7,34 @@ in 5.4 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/v5.4.0...v5.4.1 +* 5.4.24 (2023-05-27) + + * bug #50429 [Console] block input stream if needed (joelwurtz) + * bug #50315 [Translation] Fix handling of null messages in `ArrayLoader` (rob006) + * bug #50338 [Console] Remove ``exec`` and replace it by ``shell_exec`` (maxbeckers) + * bug #50362 [FrameworkBundle] Fix Workflow without a marking store definition uses marking store definition of previously defined workflow (krciga22) + * bug #50309 [HttpFoundation] UrlHelper is now aware of RequestContext changes (giosh94mhz) + * bug #50309 [HttpFoundation] UrlHelper is now aware of RequestContext changes (giosh94mhz) + * bug #50354 [Process] Stop the process correctly even if underlying input stream is not closed (joelwurtz) + * bug #50332 [PropertyInfo] Fix `PhpStanExtractor` when constructor has no docblock (HypeMC) + * bug #50253 [FrameworkBundle] Generate caches consistently on successive run of `cache:clear` command (Okhoshi) + * bug #49063 [Messenger] Respect `isRetryable` decision of the retry strategy for re-delivery (FlyingDR) + * bug #50251 [Serializer] Handle datetime deserialization in U format (tugmaks) + * bug #50266 [HttpFoundation] Fix file streaming after connection aborted (rlshukhov) + * bug #50269 Fix param type annotation (l-vo) + * bug #50256 [HttpClient] Fix setting duplicate-name headers when redirecting with AmpHttpClient (nicolas-grekas) + * bug #50214 [WebProfilerBundle] Remove legacy filters remnants (MatTheCat) + * bug #50235 [HttpClient] Fix getting through proxies via CONNECT (nicolas-grekas) + * bug #50244 [HttpKernel] Fix restoring surrogate content from cache (nicolas-grekas) + * bug #50246 [DependencyInjection] Do not check errored definitions’ type (MatTheCat) + * bug #49557 [PropertyInfo] Fix phpDocExtractor nullable array value type (fabpot) + * bug #50213 [ErrorHandler] Prevent conflicts with WebProfilerBundle’s JavaScript (MatTheCat) + * bug #50192 [Serializer] backed enum throw notNormalizableValueException outside construct method (alli83) + * bug #50238 [HttpKernel] Don't use eval() to render ESI/SSI (nicolas-grekas) + * bug #50226 [HttpClient] Ensure HttplugClient ignores invalid HTTP headers (nicolas-grekas) + * bug #50203 [Messenger] Fix registering message handlers (nicolas-grekas) + * bug #50204 [ErrorHandler] Skip Httplug deprecations for HttplugClient (nicolas-grekas) + * 5.4.23 (2023-04-28) * bug #50143 [Console] trim(): Argument #1 () must be of type string, bool given (danepowell) From 5ab98605fdb93dbd42c83dbbe986ee0f25f9c7ed Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 27 May 2023 10:06:30 +0200 Subject: [PATCH 02/25] Update VERSION for 5.4.24 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 1173f499d023f..f44eac93104ea 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -78,12 +78,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static $freshCache = []; - public const VERSION = '5.4.24-DEV'; + public const VERSION = '5.4.24'; public const VERSION_ID = 50424; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 4; public const RELEASE_VERSION = 24; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2024'; public const END_OF_LIFE = '11/2025'; From b6b2dec5f2351085939fecfe263a30fa3e6da9e1 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 27 May 2023 10:08:53 +0200 Subject: [PATCH 03/25] Update CONTRIBUTORS for 5.4.24 --- CONTRIBUTORS.md | 65 +++++++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 24afd64907140..cf5f960f7a101 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -21,9 +21,9 @@ The Symfony Connect username in parenthesis allows to get more information - Jordi Boggiano (seldaek) - Roland Franssen (ro0) - Victor Berchet (victor) + - Javier Eguiluz (javier.eguiluz) - Yonel Ceruto (yonelceruto) - Tobias Nyholm (tobias) - - Javier Eguiluz (javier.eguiluz) - Oskar Stark (oskarstark) - Ryan Weaver (weaverryan) - Johannes S (johannes) @@ -40,8 +40,8 @@ The Symfony Connect username in parenthesis allows to get more information - Abdellatif Ait boudad (aitboudad) - Jan Schädlich (jschaedl) - Lukas Kahwe Smith (lsmith) - - Jérôme Tamarelle (gromnan) - Kevin Bond (kbond) + - Jérôme Tamarelle (gromnan) - Martin Hasoň (hason) - Jeremy Mikola (jmikola) - Jean-François Simon (jfsimon) @@ -52,21 +52,21 @@ The Symfony Connect username in parenthesis allows to get more information - Valentin Udaltsov (vudaltsov) - Vasilij Duško (staff) - Matthias Pigulla (mpdude) + - Antoine Lamirault (alamirault) - Gabriel Ostrolucký (gadelat) - - Antoine Makdessi (amakdessi) - Laurent VOULLEMIER (lvo) + - Antoine Makdessi (amakdessi) - Pierre du Plessis (pierredup) - - Antoine Lamirault (alamirault) - Grégoire Paris (greg0ire) - Jonathan Wage (jwage) + - Mathieu Lechat (mat_the_cat) - Titouan Galopin (tgalopin) - David Maicher (dmaicher) + - Alexander Schranz (alexander-schranz) - Gábor Egyed (1ed) - Mathieu Santostefano (welcomattic) - - Alexander Schranz (alexander-schranz) - Alexandre Salomé (alexandresalome) - William DURAND - - Mathieu Lechat (mat_the_cat) - ornicar - Dany Maillard (maidmaid) - Eriksen Costa @@ -76,10 +76,10 @@ The Symfony Connect username in parenthesis allows to get more information - Francis Besset (francisbesset) - Vasilij Dusko | CREATION - Bulat Shakirzyanov (avalanche123) + - Vincent Langlet (deviling) - Iltar van der Berg - Miha Vrhovnik (mvrhov) - Mathieu Piot (mpiot) - - Vincent Langlet (deviling) - Saša Stamenković (umpirsky) - Alex Pott - Guilhem N (guilhemn) @@ -95,14 +95,14 @@ The Symfony Connect username in parenthesis allows to get more information - Ruud Kamphuis (ruudk) - Henrik Bjørnskov (henrikbjorn) - David Buchmann (dbu) + - Massimiliano Arione (garak) - Andrej Hudec (pulzarraider) - Julien Falque (julienfalque) - - Massimiliano Arione (garak) - Jáchym Toušek (enumag) - Douglas Greenshields (shieldo) + - Mathias Arlaud (mtarld) - Christian Raue - Fran Moreno (franmomu) - - Mathias Arlaud (mtarld) - Graham Campbell (graham) - Michel Weimerskirch (mweimerskirch) - Eric Clemmons (ericclemmons) @@ -117,18 +117,18 @@ The Symfony Connect username in parenthesis allows to get more information - Dariusz Górecki (canni) - Maxime Helias (maxhelias) - Ener-Getick - - Sebastiaan Stok (sstok) - Tugdual Saunier (tucksaun) + - Sebastiaan Stok (sstok) - Jérôme Vasseur (jvasseur) - Ion Bazan (ionbazan) - Rokas Mikalkėnas (rokasm) + - Yanick Witschi (toflar) - Lee McDermott - Brandon Turner - Luis Cordova (cordoval) - Daniel Holmes (dholmes) - Toni Uebernickel (havvg) - Bart van den Burg (burgov) - - Yanick Witschi (toflar) - Jordan Alliot (jalliot) - Smaine Milianni (ismail1432) - John Wards (johnwards) @@ -137,6 +137,7 @@ The Symfony Connect username in parenthesis allows to get more information - Antoine Hérault (herzult) - Konstantin.Myakshin - Arman Hosseini (arman) + - gnito-org - Saif Eddin Gmati (azjezz) - Simon Berger - Arnaud Le Blanc (arnaud-lb) @@ -152,6 +153,7 @@ The Symfony Connect username in parenthesis allows to get more information - Chris Wilkinson (thewilkybarkid) - Brice BERNARD (brikou) - Roman Martinuk (a2a4) + - Joel Wurtz (brouznouf) - Gregor Harlan (gharlan) - Baptiste Clavié (talus) - Adrien Brault (adrienbrault) @@ -168,7 +170,6 @@ The Symfony Connect username in parenthesis allows to get more information - Guillaume (guill) - Christopher Hertel (chertel) - Jacob Dreesen (jdreesen) - - Joel Wurtz (brouznouf) - Olivier Dolbeau (odolbeau) - Florian Voutzinos (florianv) - zairig imad (zairigimad) @@ -180,6 +181,7 @@ The Symfony Connect username in parenthesis allows to get more information - HeahDude - Richard van Laak (rvanlaak) - Paráda József (paradajozsef) + - Hubert Lenoir (hubert_lenoir) - Alessandro Lai (jean85) - Alexander Schwenn (xelaris) - Fabien Pennequin (fabienpennequin) @@ -203,7 +205,6 @@ The Symfony Connect username in parenthesis allows to get more information - Tigran Azatyan (tigranazatyan) - Eric GELOEN (gelo) - Matthieu Napoli (mnapoli) - - Hubert Lenoir (hubert_lenoir) - Tomáš Votruba (tomas_votruba) - Joshua Thijssen - Stefano Sala (stefano.sala) @@ -295,7 +296,6 @@ The Symfony Connect username in parenthesis allows to get more information - Samuel NELA (snela) - Romain Monteil (ker0x) - dFayet - - gnito-org - Karoly Gossler (connorhu) - Vincent AUBERT (vincent) - Sebastien Morel (plopix) @@ -304,7 +304,9 @@ The Symfony Connect username in parenthesis allows to get more information - Timothée Barray (tyx) - Sébastien Alfaiate (seb33300) - James Halsall (jaitsu) + - Maximilian Beckers (maxbeckers) - Mikael Pajunen + - Marcin Sikoń (marphi) - Warnar Boekkooi (boekkooi) - Marco Petersen (ocrampete16) - Benjamin Leveque (benji07) @@ -335,6 +337,7 @@ The Symfony Connect username in parenthesis allows to get more information - Urinbayev Shakhobiddin (shokhaa) - Ahmed Raafat - Philippe Segatori + - Allison Guilhem (a_guilhem) - Thibaut Cheymol (tcheymol) - Julien Pauli - Islam Israfilov (islam93) @@ -346,7 +349,6 @@ The Symfony Connect username in parenthesis allows to get more information - Ruben Gonzalez (rubenrua) - Benjamin Dulau (dbenjamin) - Pavel Kirpitsov (pavel-kirpichyov) - - Maximilian Beckers (maxbeckers) - Mathieu Lemoine (lemoinem) - Christian Schmidt - Andreas Hucks (meandmymonkey) @@ -357,7 +359,6 @@ The Symfony Connect username in parenthesis allows to get more information - Clara van Miert - Martin Auswöger - Alexander Menshchikov - - Marcin Sikoń (marphi) - Stepan Anchugov (kix) - bronze1man - sun (sun) @@ -375,11 +376,13 @@ The Symfony Connect username in parenthesis allows to get more information - Kyle - Dominique Bongiraud - Hidde Wieringa (hiddewie) + - Dane Powell - Christopher Davis (chrisguitarguy) - Lukáš Holeczy (holicz) - Michael Lee (zerustech) - Florian Lonqueu-Brochard (florianlb) - Leszek Prabucki (l3l0) + - Giorgio Premi - Emanuele Panzeri (thepanz) - Matthew Smeets - François Zaninotto (fzaninotto) @@ -415,14 +418,12 @@ The Symfony Connect username in parenthesis allows to get more information - Mantis Development - Pablo Lozano (arkadis) - quentin neyrat (qneyrat) - - Dane Powell - Antonio Jose Cerezo (ajcerezo) - Marcin Szepczynski (czepol) - Lescot Edouard (idetox) - Loïc Frémont (loic425) - Rob Frawley 2nd (robfrawley) - Mohammad Emran Hasan (phpfour) - - Allison Guilhem (a_guilhem) - Dmitriy Mamontov (mamontovdmitriy) - Kévin THERAGE (kevin_therage) - Nikita Konstantinov (unkind) @@ -430,7 +431,6 @@ The Symfony Connect username in parenthesis allows to get more information - Francois Zaninotto - Laurent Masforné (heisenberg) - Claude Khedhiri (ck-developer) - - Giorgio Premi - Daniel Tschinder - Christian Schmidt - Alexander Kotynia (olden) @@ -576,6 +576,7 @@ The Symfony Connect username in parenthesis allows to get more information - Grégoire Passault (gregwar) - Jerzy Zawadzki (jzawadzki) - Ismael Ambrosi (iambrosi) + - Samaël Villette (samadu61) - Saif Eddin G - Emmanuel BORGES (eborges78) - siganushka (siganushka) @@ -691,6 +692,7 @@ The Symfony Connect username in parenthesis allows to get more information - Ruben Jacobs (rubenj) - Arkadius Stefanski (arkadius) - Jérémy M (th3mouk) + - Tristan Pouliquen - Terje Bråten - Pierre Rineau - Renan Gonçalves (renan_saddam) @@ -720,6 +722,7 @@ The Symfony Connect username in parenthesis allows to get more information - Eric COURTIAL - Xesxen - ShinDarth + - Phil E. Taylor (philetaylor) - Arun Philip - Stéphane PY (steph_py) - Philipp Kräutli (pkraeutli) @@ -752,10 +755,10 @@ The Symfony Connect username in parenthesis allows to get more information - Hassan Amouhzi - Antonin CLAUZIER (0x346e3730) - Andrei C. (moldman) - - Samaël Villette (samadu61) - Tamas Szijarto - stlrnz - Adrien Wilmet (adrienfr) + - Mathieu Rochette (mathroc) - Alex Bacart - hugovms - Michele Locati @@ -898,6 +901,7 @@ The Symfony Connect username in parenthesis allows to get more information - Jonas Flodén (flojon) - Adrien Lucas (adrienlucas) - Dominik Zogg + - Quentin Devos - Kai Dederichs - Luc Vieillescazes (iamluc) - Thomas Nunninger @@ -956,7 +960,6 @@ The Symfony Connect username in parenthesis allows to get more information - Gigino Chianese (sajito) - Xav` (xavismeh) - Remi Collet - - Mathieu Rochette (mathroc) - Vicent Soria Durá (vicentgodella) - Michael Moravec - Anthony Ferrara @@ -1026,6 +1029,7 @@ The Symfony Connect username in parenthesis allows to get more information - Loïc Faugeron - Aurélien Fredouelle - Pavel Campr (pcampr) + - Markus Staab - Forfarle (forfarle) - Johnny Robeson (johnny) - Kai Eichinger (kai_eichinger) @@ -1267,7 +1271,6 @@ The Symfony Connect username in parenthesis allows to get more information - Szijarto Tamas - Arend Hummeling - Makdessi Alex - - Phil E. Taylor (philetaylor) - Juan Miguel Besada Vidal (soutlink) - dlorek - Stuart Fyfe @@ -1295,7 +1298,6 @@ The Symfony Connect username in parenthesis allows to get more information - Simon Schick (simonsimcity) - Victor Macko (victor_m) - Tristan Roussel - - Quentin Devos - Jorge Vahldick (jvahldick) - Vladimir Mantulo (mantulo) - aim8604 @@ -1303,6 +1305,7 @@ The Symfony Connect username in parenthesis allows to get more information - Maciej Zgadzaj - David Legatt (dlegatt) - Maarten de Boer (mdeboer) + - Alexandre parent - Cameron Porter - Hossein Bukhamsin - Oliver Hoff @@ -1449,7 +1452,6 @@ The Symfony Connect username in parenthesis allows to get more information - Michael Olšavský - Benny Born - Emirald Mateli - - Tristan Pouliquen - Jose Gonzalez - Claudio Zizza - Ivo Valchev @@ -1841,7 +1843,6 @@ The Symfony Connect username in parenthesis allows to get more information - vladyslavstartsev - Kévin - Marc Abramowitz - - Markus Staab - michal - Martijn Evers - Sjoerd Adema @@ -2220,11 +2221,13 @@ The Symfony Connect username in parenthesis allows to get more information - Andrew Tch - Alexander Cheprasov - Rodrigo Díez Villamuera (rodrigodiez) + - Brad Treloar - Stephen Clouse - e-ivanov - Abderrahman DAIF (death_maker) - Yann Rabiller (einenlum) - Jochen Bayer (jocl) + - Constantine Shtompel - VAN DER PUTTE Guillaume (guillaume_vdp) - Patrick Carlo-Hickman - Bruno MATEU @@ -2235,6 +2238,7 @@ The Symfony Connect username in parenthesis allows to get more information - Viacheslav Sychov - Nicolas Sauveur (baishu) - Helmut Hummel (helhum) + - Andrew Neil Forster (krciga22) - Matt Brunt - Carlos Ortega Huetos - Péter Buri (burci) @@ -2285,7 +2289,6 @@ The Symfony Connect username in parenthesis allows to get more information - John Espiritu (johnillo) - Oxan van Leeuwen - pkowalczyk - - Alexandre parent - Soner Sayakci - Max Voloshin (maxvoloshin) - Nicolas Fabre (nfabre) @@ -2400,6 +2403,7 @@ The Symfony Connect username in parenthesis allows to get more information - Claudiu Cristea - Zacharias Luiten - Sebastian Utz + - Oliver Hader - Adrien Gallou (agallou) - Maks Rafalko (bornfree) - Conrad Kleinespel (conradk) @@ -2417,6 +2421,7 @@ The Symfony Connect username in parenthesis allows to get more information - Cédric Lahouste (rapotor) - Samuel Vogel (samuelvogel) - Berat Doğan + - Christian Kolb - Guillaume LECERF - Juanmi Rodriguez Cerón - twifty @@ -2437,6 +2442,8 @@ The Symfony Connect username in parenthesis allows to get more information - Eric Stern - ShiraNai7 - Antal Áron (antalaron) + - Alexander Grimalovsky (flying) + - Ivan Pepelko (pepelko) - Vašek Purchart (vasek-purchart) - Janusz Jabłoński (yanoosh) - Fleuv @@ -2581,6 +2588,7 @@ The Symfony Connect username in parenthesis allows to get more information - Nicolas Schwartz (nicoschwartz) - Tim Jabs (rubinum) - Stéphane Seng (stephaneseng) + - Robert Korulczyk - Jonathan Gough - Benoit Leveque - Benjamin Bender @@ -2652,6 +2660,7 @@ The Symfony Connect username in parenthesis allows to get more information - Martin Schophaus (m_schophaus_adcada) - Martynas Sudintas (martiis) - Anton Sukhachev (mrsuh) + - Vitaliy Zhuk (zhukv) - Marcel Siegert - ryunosuke - Roy de Vos Burchart @@ -2707,6 +2716,7 @@ The Symfony Connect username in parenthesis allows to get more information - Jovan Perovic (jperovic) - Pablo Maria Martelletti (pmartelletti) - Sander van der Vlugt (stranding) + - Maxim Tugaev (tugmaks) - Florian Bogey - Waqas Ahmed - Bert Hekman @@ -3141,6 +3151,7 @@ The Symfony Connect username in parenthesis allows to get more information - Antoine LA - Vyacheslav Slinko - Benjamin Laugueux + - Lane Shukhov - Jakub Chábek - William Pinaud (DocFX) - Johannes @@ -3244,6 +3255,7 @@ The Symfony Connect username in parenthesis allows to get more information - Ahmed Abdulrahman - dinitrol - Penny Leach + - Kevin Mian Kraiker - Yurii K - Richard Trebichavský - g123456789l @@ -3282,6 +3294,7 @@ The Symfony Connect username in parenthesis allows to get more information - ADmad - Nicolas Roudaire - Abdouni Karim (abdounikarim) + - Adrian Günter (adrianguenter) - Andreas Forsblom (aforsblo) - Alex Olmos (alexolmos) - Cedric BERTOLINI (alsciende) From f2af155921a44fb7f53cdbfe5bd2f9c2d6651c1f Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 27 May 2023 19:20:39 +0200 Subject: [PATCH 04/25] Bump Symfony version to 5.4.25 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index f44eac93104ea..ae666d4dc307f 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -78,12 +78,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static $freshCache = []; - public const VERSION = '5.4.24'; - public const VERSION_ID = 50424; + public const VERSION = '5.4.25-DEV'; + public const VERSION_ID = 50425; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 4; - public const RELEASE_VERSION = 24; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 25; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '11/2024'; public const END_OF_LIFE = '11/2025'; From 50ff60f02ae3d87d58b6fcf0d28420e10a1d3354 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 27 May 2023 23:12:49 +0200 Subject: [PATCH 05/25] Update CHANGELOG for 6.2.11 --- CHANGELOG-6.2.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/CHANGELOG-6.2.md b/CHANGELOG-6.2.md index d685302315bcb..5a003a6343fe2 100644 --- a/CHANGELOG-6.2.md +++ b/CHANGELOG-6.2.md @@ -7,6 +7,42 @@ in 6.2 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/v6.2.0...v6.2.1 +* 6.2.11 (2023-05-27) + + * bug #50442 [SecurityBundle] Update security-1.0.xsd to include missing access-token definition (aegypius) + * bug #50429 [Console] block input stream if needed (joelwurtz) + * bug #50312 [Security] Skip clearing CSRF Token on stateless logout (chalasr) + * bug #50315 [Translation] Fix handling of null messages in `ArrayLoader` (rob006) + * bug #50338 [Console] Remove ``exec`` and replace it by ``shell_exec`` (maxbeckers) + * bug #50193 [Serializer] Fix `SerializedPath` not working with constructor arguments (HypeMC) + * bug #50280 [PropertyAccess] Fix nullsafe operator on array index (HypeMC) + * bug #50362 [FrameworkBundle] Fix Workflow without a marking store definition uses marking store definition of previously defined workflow (krciga22) + * bug #50309 [HttpFoundation] UrlHelper is now aware of RequestContext changes (giosh94mhz) + * bug #50309 [HttpFoundation] UrlHelper is now aware of RequestContext changes (giosh94mhz) + * bug #50352 [Notifier][TurboSMS] Fix get sender name (ZhukV) + * bug #50354 [Process] Stop the process correctly even if underlying input stream is not closed (joelwurtz) + * bug #50332 [PropertyInfo] Fix `PhpStanExtractor` when constructor has no docblock (HypeMC) + * bug #50253 [FrameworkBundle] Generate caches consistently on successive run of `cache:clear` command (Okhoshi) + * bug #49063 [Messenger] Respect `isRetryable` decision of the retry strategy for re-delivery (FlyingDR) + * bug #50251 [Serializer] Handle datetime deserialization in U format (tugmaks) + * bug #50266 [HttpFoundation] Fix file streaming after connection aborted (rlshukhov) + * bug #50277 [Messenger] Add `IS_REPEATABLE` flag to `AsMessageHandler` attribute (adrianguenter) + * bug #50269 Fix param type annotation (l-vo) + * bug #50268 Allow resources in Query::setParam (l-vo) + * bug #50256 [HttpClient] Fix setting duplicate-name headers when redirecting with AmpHttpClient (nicolas-grekas) + * bug #50214 [WebProfilerBundle] Remove legacy filters remnants (MatTheCat) + * bug #50235 [HttpClient] Fix getting through proxies via CONNECT (nicolas-grekas) + * bug #50241 [HttpKernel] Prevent initialising lazy services during services reset (tucksaun) + * bug #50244 [HttpKernel] Fix restoring surrogate content from cache (nicolas-grekas) + * bug #50246 [DependencyInjection] Do not check errored definitions’ type (MatTheCat) + * bug #49557 [PropertyInfo] Fix phpDocExtractor nullable array value type (fabpot) + * bug #50213 [ErrorHandler] Prevent conflicts with WebProfilerBundle’s JavaScript (MatTheCat) + * bug #50192 [Serializer] backed enum throw notNormalizableValueException outside construct method (alli83) + * bug #50238 [HttpKernel] Don't use eval() to render ESI/SSI (nicolas-grekas) + * bug #50226 [HttpClient] Ensure HttplugClient ignores invalid HTTP headers (nicolas-grekas) + * bug #50203 [Messenger] Fix registering message handlers (nicolas-grekas) + * bug #50204 [ErrorHandler] Skip Httplug deprecations for HttplugClient (nicolas-grekas) + * 6.2.10 (2023-04-28) * bug #50143 [Console] trim(): Argument #1 () must be of type string, bool given (danepowell) From 3ce0d07a69d90719a542af98065e2d83df4631b8 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 27 May 2023 23:12:52 +0200 Subject: [PATCH 06/25] Update VERSION for 6.2.11 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index c0dd3e646d336..1ad714e6d98a9 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -75,12 +75,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static array $freshCache = []; - public const VERSION = '6.2.11-DEV'; + public const VERSION = '6.2.11'; public const VERSION_ID = 60211; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 2; public const RELEASE_VERSION = 11; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '07/2023'; public const END_OF_LIFE = '07/2023'; From 4b72b6112a3845d9d8baa754e7de3f9fe3055091 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 27 May 2023 23:15:53 +0200 Subject: [PATCH 07/25] Bump Symfony version to 6.2.12 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 1ad714e6d98a9..f6d91d7b6a81f 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -75,12 +75,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static array $freshCache = []; - public const VERSION = '6.2.11'; - public const VERSION_ID = 60211; + public const VERSION = '6.2.12-DEV'; + public const VERSION_ID = 60212; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 2; - public const RELEASE_VERSION = 11; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 12; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '07/2023'; public const END_OF_LIFE = '07/2023'; From e1bf69c913b13c38347cc49f13e8c83419d8ff34 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 27 May 2023 23:20:47 +0200 Subject: [PATCH 08/25] Bump Symfony version to 6.3.0 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 0bd152bc8208a..f9a969b659130 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -76,12 +76,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static array $freshCache = []; - public const VERSION = '6.3.0-RC2'; + public const VERSION = '6.3.0-DEV'; public const VERSION_ID = 60300; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 3; public const RELEASE_VERSION = 0; - public const EXTRA_VERSION = 'RC2'; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '01/2024'; public const END_OF_LIFE = '01/2024'; From 2c668ba8a2fe6f077e94891e4f273bf4002af2f3 Mon Sep 17 00:00:00 2001 From: vorozcovmaksim Date: Sat, 27 May 2023 16:43:39 +0300 Subject: [PATCH 09/25] Ignore definitions bearing the `container.excluded` tag --- .../Console/Descriptor/JsonDescriptor.php | 3 +++ .../Console/Descriptor/MarkdownDescriptor.php | 3 +++ .../Console/Descriptor/TextDescriptor.php | 4 ++++ .../Console/Descriptor/XmlDescriptor.php | 6 ++++++ .../Tests/Fixtures/ContainerExcluded.php | 12 ++++++++++++ .../Tests/Functional/ContainerDebugCommandTest.php | 14 ++++++++++++++ .../Tests/Functional/app/ContainerDebug/config.yml | 2 ++ 7 files changed, 44 insertions(+) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/ContainerExcluded.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php index c454b85ffb4bf..5f0588c9a6d48 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php @@ -106,6 +106,9 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o if ($service instanceof Alias) { $data['aliases'][$serviceId] = $this->getContainerAliasData($service); } elseif ($service instanceof Definition) { + if ($service->hasTag('container.excluded')) { + continue; + } $data['definitions'][$serviceId] = $this->getContainerDefinitionData($service, $omitTags, $showArguments, $builder, $serviceId); } else { $data['services'][$serviceId] = $service::class; diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php index 36b297172681f..836f06742cd6b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php @@ -162,6 +162,9 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o if ($service instanceof Alias) { $services['aliases'][$serviceId] = $service; } elseif ($service instanceof Definition) { + if ($service->hasTag('container.excluded')) { + continue; + } $services['definitions'][$serviceId] = $service; } else { $services['services'][$serviceId] = $service; diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index e589f7b3400a8..8f6ef7e9a420e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -198,6 +198,10 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o } if ($definition instanceof Definition) { + if ($definition->hasTag('container.excluded')) { + unset($serviceIds[$key]); + continue; + } if ($showTag) { $tags = $definition->getTag($showTag); foreach ($tags as $tag) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php index 6c01c15ce04db..6c49b768f67e6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php @@ -294,6 +294,12 @@ private function getContainerServicesDocument(ContainerBuilder $builder, string continue; } + if ($service instanceof Definition) { + if ($service->hasTag('container.excluded')) { + continue; + } + } + $serviceXML = $this->getContainerServiceDocument($service, $serviceId, null, $showArguments); $containerXML->appendChild($containerXML->ownerDocument->importNode($serviceXML->childNodes->item(0), true)); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/ContainerExcluded.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/ContainerExcluded.php new file mode 100644 index 0000000000000..b89eed5f8db85 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/ContainerExcluded.php @@ -0,0 +1,12 @@ + + */ +class ContainerExcluded +{ +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php index 67727202e72b7..bb09c6aed0765 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php @@ -13,6 +13,7 @@ use Symfony\Bundle\FrameworkBundle\Console\Application; use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\BackslashClass; +use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\ContainerExcluded; use Symfony\Component\Console\Tester\ApplicationTester; use Symfony\Component\Console\Tester\CommandCompletionTester; @@ -85,6 +86,19 @@ public function testDeprecatedServiceAndAlias() $this->assertStringContainsString('[WARNING] The "deprecated_alias" alias is deprecated since foo/bar 1.9 and will be removed in 2.0', $tester->getDisplay()); } + public function testExcludedService() + { + static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml']); + + $application = new Application(static::$kernel); + $application->setAutoExit(false); + + $tester = new ApplicationTester($application); + + $tester->run(['command' => 'debug:container']); + $this->assertStringNotContainsString(ContainerExcluded::class, $tester->getDisplay()); + } + /** * @dataProvider provideIgnoreBackslashWhenFindingService */ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ContainerDebug/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ContainerDebug/config.yml index cc1a01bb8f0b5..15ddaca64356f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ContainerDebug/config.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ContainerDebug/config.yml @@ -33,3 +33,5 @@ services: - '%env(REAL)%' - '%env(int:key:2:json:JSON)%' - '%env(float:key:2:json:JSON)%' + Symfony\Bundle\FrameworkBundle\Tests\Fixtures\ContainerExcluded: + tags: ['container.excluded'] From 83d469dd4319dd48015c53d379fd1e1f4ce34637 Mon Sep 17 00:00:00 2001 From: "Phil E. Taylor" Date: Sun, 28 May 2023 19:16:27 +0100 Subject: [PATCH 10/25] Fix Typos Signed-off-by: Phil E. Taylor --- src/Symfony/Contracts/Translation/Test/TranslatorTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Contracts/Translation/Test/TranslatorTest.php b/src/Symfony/Contracts/Translation/Test/TranslatorTest.php index fdf4f76c1589a..dff86ddad8aba 100644 --- a/src/Symfony/Contracts/Translation/Test/TranslatorTest.php +++ b/src/Symfony/Contracts/Translation/Test/TranslatorTest.php @@ -258,13 +258,13 @@ public static function getChooseTests() new-line in it. Selector = 0.|{1}This is a text with a new-line in it. Selector = 1.|[1,Inf]This is a text with a new-line in it. Selector > 1.', 5], - // with double-quotes and id split accros lines + // with double-quotes and id split across lines ['This is a text with a new-line in it. Selector = 1.', '{0}This is a text with a new-line in it. Selector = 0.|{1}This is a text with a new-line in it. Selector = 1.|[1,Inf]This is a text with a new-line in it. Selector > 1.', 1], - // with single-quotes and id split accros lines + // with single-quotes and id split across lines ['This is a text with a new-line in it. Selector > 1.', '{0}This is a text with a new-line in it. Selector = 0.|{1}This is a text with a @@ -272,7 +272,7 @@ public static function getChooseTests() new-line in it. Selector > 1.', 5], // with single-quotes and \n in text ['This is a text with a\nnew-line in it. Selector = 0.', '{0}This is a text with a\nnew-line in it. Selector = 0.|{1}This is a text with a\nnew-line in it. Selector = 1.|[1,Inf]This is a text with a\nnew-line in it. Selector > 1.', 0], - // with double-quotes and id split accros lines + // with double-quotes and id split across lines ["This is a text with a\nnew-line in it. Selector = 1.", "{0}This is a text with a\nnew-line in it. Selector = 0.|{1}This is a text with a\nnew-line in it. Selector = 1.|[1,Inf]This is a text with a\nnew-line in it. Selector > 1.", 1], // escape pipe ['This is a text with | in it. Selector = 0.', '{0}This is a text with || in it. Selector = 0.|{1}This is a text with || in it. Selector = 1.', 0], From 0a0a2c9d04b3ea456bb312c07a48217ecd66b87f Mon Sep 17 00:00:00 2001 From: Uladzimir Tsykun Date: Mon, 29 May 2023 15:12:36 +0200 Subject: [PATCH 11/25] Fix unable to use asset mapper with CSP --- src/Symfony/Bridge/Twig/Extension/ImportMapRuntime.php | 4 ++-- .../AssetMapper/ImportMap/ImportMapRenderer.php | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Extension/ImportMapRuntime.php b/src/Symfony/Bridge/Twig/Extension/ImportMapRuntime.php index aa5097d35de5d..aa68111b7b819 100644 --- a/src/Symfony/Bridge/Twig/Extension/ImportMapRuntime.php +++ b/src/Symfony/Bridge/Twig/Extension/ImportMapRuntime.php @@ -22,8 +22,8 @@ public function __construct(private readonly ImportMapRenderer $importMapRendere { } - public function importmap(?string $entryPoint = 'app'): string + public function importmap(?string $entryPoint = 'app', array $attributes = []): string { - return $this->importMapRenderer->render($entryPoint); + return $this->importMapRenderer->render($entryPoint, $attributes); } } diff --git a/src/Symfony/Component/AssetMapper/ImportMap/ImportMapRenderer.php b/src/Symfony/Component/AssetMapper/ImportMap/ImportMapRenderer.php index 7a5dc43001001..2a9a215f38a63 100644 --- a/src/Symfony/Component/AssetMapper/ImportMap/ImportMapRenderer.php +++ b/src/Symfony/Component/AssetMapper/ImportMap/ImportMapRenderer.php @@ -29,15 +29,16 @@ public function __construct( ) { } - public function render(string $entryPoint = null): string + public function render(string $entryPoint = null, array $attributes = []): string { $attributeString = ''; - if (isset($this->scriptAttributes['src']) || isset($this->scriptAttributes['type'])) { + $attributes += $this->scriptAttributes; + if (isset($attributes['src']) || isset($attributes['type'])) { throw new \InvalidArgumentException(sprintf('The "src" and "type" attributes are not allowed on the "; + $output .= "\n"; } return $output; From fabe7bc84a687309a5d5c0de9c71188d6351fe3f Mon Sep 17 00:00:00 2001 From: HypeMC Date: Sun, 28 May 2023 22:40:37 +0200 Subject: [PATCH 12/25] [HttpKernel] Fix default value ignored with pinned resolvers --- .../Controller/ArgumentResolver.php | 5 +++- .../QueryParameterValueResolver.php | 8 ++---- .../QueryParameterValueResolverTest.php | 4 +-- .../Tests/Controller/ArgumentResolverTest.php | 28 +++++++++++++++++++ 4 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php index 7b8d5b521d123..3b0f89509f65c 100644 --- a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php +++ b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php @@ -71,7 +71,10 @@ public function getArguments(Request $request, callable $controller, \Reflection throw new ResolverNotFoundException($resolverName, $this->namedResolvers instanceof ServiceProviderInterface ? array_keys($this->namedResolvers->getProvidedServices()) : []); } - $argumentValueResolvers = [$this->namedResolvers->get($resolverName)]; + $argumentValueResolvers = [ + $this->namedResolvers->get($resolverName), + new DefaultValueResolver(), + ]; } } diff --git a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/QueryParameterValueResolver.php b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/QueryParameterValueResolver.php index 7255a792ba754..f2e4bee812d79 100644 --- a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/QueryParameterValueResolver.php +++ b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/QueryParameterValueResolver.php @@ -31,12 +31,8 @@ public function resolve(Request $request, ArgumentMetadata $argument): array $name = $attribute->name ?? $argument->getName(); if (!$request->query->has($name)) { - if ($argument->hasDefaultValue()) { - return [$argument->getDefaultValue()]; - } - - if ($argument->isNullable()) { - return [null]; + if ($argument->isNullable() || $argument->hasDefaultValue()) { + return []; } throw new NotFoundHttpException(sprintf('Missing query parameter "%s".', $name)); diff --git a/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/QueryParameterValueResolverTest.php b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/QueryParameterValueResolverTest.php index 1383475988b52..539aaac78ee65 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/QueryParameterValueResolverTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/QueryParameterValueResolverTest.php @@ -179,14 +179,14 @@ public static function provideTestResolve(): iterable yield 'parameter not found but nullable' => [ Request::create('/', 'GET'), new ArgumentMetadata('firstName', 'string', false, false, false, true, [new MapQueryParameter()]), - [null], + [], null, ]; yield 'parameter not found but optional' => [ Request::create('/', 'GET'), new ArgumentMetadata('firstName', 'string', false, true, false, attributes: [new MapQueryParameter()]), - [false], + [], null, ]; diff --git a/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolverTest.php b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolverTest.php index e62001633ca93..ef44f45bae078 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolverTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolverTest.php @@ -296,6 +296,26 @@ public function testTargetedResolver() $this->assertSame([1], $resolver->getArguments($request, $controller)); } + public function testTargetedResolverWithDefaultValue() + { + $resolver = self::getResolver([], [RequestAttributeValueResolver::class => new RequestAttributeValueResolver()]); + + $request = Request::create('/'); + $controller = $this->controllerTargetingResolverWithDefaultValue(...); + + $this->assertSame([2], $resolver->getArguments($request, $controller)); + } + + public function testTargetedResolverWithNullableValue() + { + $resolver = self::getResolver([], [RequestAttributeValueResolver::class => new RequestAttributeValueResolver()]); + + $request = Request::create('/'); + $controller = $this->controllerTargetingResolverWithNullableValue(...); + + $this->assertSame([null], $resolver->getArguments($request, $controller)); + } + public function testDisabledResolver() { $resolver = self::getResolver(namedResolvers: []); @@ -373,6 +393,14 @@ public function controllerTargetingResolver(#[ValueResolver(DefaultValueResolver { } + public function controllerTargetingResolverWithDefaultValue(#[ValueResolver(RequestAttributeValueResolver::class)] int $foo = 2) + { + } + + public function controllerTargetingResolverWithNullableValue(#[ValueResolver(RequestAttributeValueResolver::class)] ?int $foo) + { + } + public function controllerDisablingResolver(#[ValueResolver(RequestAttributeValueResolver::class, disabled: true)] int $foo = 1) { } From cbe48081f512fb823727d8aaf4ea35507a9d3c67 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 30 May 2023 10:36:39 +0200 Subject: [PATCH 13/25] [FrameworkBundle][PhpUnitBridge] Configure doctrine/deprecations as expected --- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php | 5 +++++ src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php index f28933cf97357..50f62b9abcfef 100644 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php @@ -151,6 +151,11 @@ putenv('SYMFONY_DEPRECATIONS_HELPER=disabled'); } +if (!$getEnvVar('DOCTRINE_DEPRECATIONS')) { + putenv('DOCTRINE_DEPRECATIONS=trigger'); + $_SERVER['DOCTRINE_DEPRECATIONS'] = $_ENV['DOCTRINE_DEPRECATIONS'] = 'trigger'; +} + $COMPOSER = ($COMPOSER = getenv('COMPOSER_BINARY')) || file_exists($COMPOSER = $oldPwd.'/composer.phar') || ($COMPOSER = rtrim((string) ('\\' === \DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', shell_exec('where.exe composer.phar 2> NUL')) : shell_exec('which composer.phar 2> /dev/null')))) diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index ffb96a23e5f5b..36e5cd4028010 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -95,6 +95,8 @@ class FrameworkBundle extends Bundle */ public function boot() { + $_ENV['DOCTRINE_DEPRECATIONS'] = $_SERVER['DOCTRINE_DEPRECATIONS'] ??= 'trigger'; + $handler = ErrorHandler::register(null, false); $this->container->get('debug.error_handler_configurator')->configure($handler); From 380e709c5e7975393feef650ce2264bd5ca79726 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 30 May 2023 11:11:03 +0200 Subject: [PATCH 14/25] CS fix --- .../FrameworkBundle/Console/Descriptor/XmlDescriptor.php | 6 ++---- .../FrameworkBundle/Tests/Fixtures/ContainerExcluded.php | 5 ----- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php index 6c49b768f67e6..ecb9b01b776a7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php @@ -294,10 +294,8 @@ private function getContainerServicesDocument(ContainerBuilder $builder, string continue; } - if ($service instanceof Definition) { - if ($service->hasTag('container.excluded')) { - continue; - } + if ($service instanceof Definition && $service->hasTag('container.excluded')) { + continue; } $serviceXML = $this->getContainerServiceDocument($service, $serviceId, null, $showArguments); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/ContainerExcluded.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/ContainerExcluded.php index b89eed5f8db85..2508b74276bc0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/ContainerExcluded.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/ContainerExcluded.php @@ -1,12 +1,7 @@ - */ class ContainerExcluded { } From 8dd9d9393f9b205fa43ff3180f74cc4fae655dee Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 30 May 2023 14:42:45 +0200 Subject: [PATCH 15/25] [Notifier] Fix ContactEveryoneOptions --- .../ContactEveryoneOptions.php | 26 ++++++++++++++++++- .../ContactEveryoneTransport.php | 4 ++- .../Tests/ContactEveryoneOptionsTest.php | 2 +- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Notifier/Bridge/ContactEveryone/ContactEveryoneOptions.php b/src/Symfony/Component/Notifier/Bridge/ContactEveryone/ContactEveryoneOptions.php index 122cb93680f48..ca264d8018eae 100644 --- a/src/Symfony/Component/Notifier/Bridge/ContactEveryone/ContactEveryoneOptions.php +++ b/src/Symfony/Component/Notifier/Bridge/ContactEveryone/ContactEveryoneOptions.php @@ -15,6 +15,8 @@ /** * @author gnito-org + * + * @see https://ceo-be.multimediabs.com/attachments/hosted/lightApiManualsFR */ final class ContactEveryoneOptions implements MessageOptionsInterface { @@ -35,7 +37,7 @@ public function getRecipientId(): ?string */ public function diffusionName(string $diffusionName): static { - $this->options['diffusion_name'] = $diffusionName; + $this->options['diffusionname'] = $diffusionName; return $this; } @@ -50,6 +52,28 @@ public function category(string $category): static return $this; } + /** + * @param 'fr_FR'|'en_GB' $locale + * + * @return $this + */ + public function locale(string $locale): static + { + $this->options['locale'] = $locale; + + return $this; + } + + /** + * @return $this + */ + public function unicode(bool $unicode): static + { + $this->options['xcharset'] = $unicode ? 'true' : 'false'; + + return $this; + } + public function toArray(): array { return $this->options; diff --git a/src/Symfony/Component/Notifier/Bridge/ContactEveryone/ContactEveryoneTransport.php b/src/Symfony/Component/Notifier/Bridge/ContactEveryone/ContactEveryoneTransport.php index 0f09f1e54cde6..f9d2e6c2dfe66 100644 --- a/src/Symfony/Component/Notifier/Bridge/ContactEveryone/ContactEveryoneTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/ContactEveryone/ContactEveryoneTransport.php @@ -73,7 +73,9 @@ protected function doSend(MessageInterface $message): SentMessage } $options = $message->getOptions()?->toArray() ?? []; - $options['xcharset'] = 'true'; + $options['category'] ??= $this->category; + $options['diffusionname'] ??= $this->diffusionName; + $options['xcharset'] ??= 'true'; $options['token'] = $this->token; $options['to'] = $message->getPhone(); $options['msg'] = $message->getSubject(); diff --git a/src/Symfony/Component/Notifier/Bridge/ContactEveryone/Tests/ContactEveryoneOptionsTest.php b/src/Symfony/Component/Notifier/Bridge/ContactEveryone/Tests/ContactEveryoneOptionsTest.php index 89b367509bd88..4485d18e5b3b3 100644 --- a/src/Symfony/Component/Notifier/Bridge/ContactEveryone/Tests/ContactEveryoneOptionsTest.php +++ b/src/Symfony/Component/Notifier/Bridge/ContactEveryone/Tests/ContactEveryoneOptionsTest.php @@ -24,7 +24,7 @@ public function testContactEveryoneOptions() self::assertSame([ 'category' => 'test_category', - 'diffusion_name' => 'test_diffusion_name', + 'diffusionname' => 'test_diffusion_name', ], $contactEveryoneOptions->toArray()); } } From 23c9e17c3ec56cd39b186bf158d61a094edc4c9f Mon Sep 17 00:00:00 2001 From: Vincent Chalamon <407859+vincentchalamon@users.noreply.github.com> Date: Tue, 30 May 2023 14:03:49 +0200 Subject: [PATCH 16/25] [SecurityBundle] Fix configuring OIDC user info token handler client --- .../OidcUserInfoTokenHandlerFactory.php | 50 +++++++++---------- .../security_authenticator_access_token.php | 8 ++- .../Factory/AccessTokenFactoryTest.php | 41 ++++++++++++--- .../Bundle/SecurityBundle/composer.json | 1 + 4 files changed, 68 insertions(+), 32 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcUserInfoTokenHandlerFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcUserInfoTokenHandlerFactory.php index 08b1019f2c210..78bc45224db33 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcUserInfoTokenHandlerFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcUserInfoTokenHandlerFactory.php @@ -15,7 +15,7 @@ use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\HttpClient\HttpClient; +use Symfony\Contracts\HttpClient\HttpClientInterface; /** * Configures a token handler for an OIDC server. @@ -26,24 +26,20 @@ class OidcUserInfoTokenHandlerFactory implements TokenHandlerFactoryInterface { public function create(ContainerBuilder $container, string $id, array|string $config): void { - $tokenHandlerDefinition = $container->setDefinition($id, new ChildDefinition('security.access_token_handler.oidc_user_info')); - $tokenHandlerDefinition->replaceArgument(2, $config['claim']); + $clientDefinition = (new ChildDefinition('security.access_token_handler.oidc_user_info.http_client')) + ->replaceArgument(0, ['base_uri' => $config['base_uri']]); - // Create the client service - if (!isset($config['client']['id'])) { - $clientDefinitionId = 'http_client.security.access_token_handler.oidc_user_info'; - if (!ContainerBuilder::willBeAvailable('symfony/http-client', HttpClient::class, ['symfony/security-bundle'])) { - $container->register($clientDefinitionId, 'stdClass') - ->addError('You cannot use the "oidc_user_info" token handler since the HttpClient component is not installed. Try running "composer require symfony/http-client".'); - } else { - $container->register($clientDefinitionId, HttpClient::class) - ->setFactory([HttpClient::class, 'create']) - ->setArguments([$config['client']]) - ->addTag('http_client.client'); - } + if (isset($config['client'])) { + $clientDefinition->setFactory([new Reference($config['client']), 'withOptions']); + } elseif (!ContainerBuilder::willBeAvailable('symfony/http-client', HttpClientInterface::class, ['symfony/security-bundle'])) { + $clientDefinition + ->setFactory(null) + ->addError('You cannot use the "oidc_user_info" token handler since the HttpClient component is not installed. Try running "composer require symfony/http-client".'); } - $tokenHandlerDefinition->replaceArgument(0, new Reference($config['client']['id'] ?? $clientDefinitionId)); + $container->setDefinition($id, new ChildDefinition('security.access_token_handler.oidc_user_info')) + ->replaceArgument(0, $clientDefinition) + ->replaceArgument(2, $config['claim']); } public function getKey(): string @@ -56,19 +52,23 @@ public function addConfiguration(NodeBuilder $node): void $node ->arrayNode($this->getKey()) ->fixXmlConfig($this->getKey()) + ->beforeNormalization() + ->ifString() + ->then(static fn ($v) => ['claim' => 'sub', 'base_uri' => $v]) + ->end() ->children() + ->scalarNode('base_uri') + ->info('Base URI of the userinfo endpoint on the OIDC server.') + ->isRequired() + ->cannotBeEmpty() + ->end() ->scalarNode('claim') - ->info('Claim which contains the user identifier (e.g.: sub, email..).') + ->info('Claim which contains the user identifier (e.g. sub, email, etc.).') ->defaultValue('sub') + ->cannotBeEmpty() ->end() - ->arrayNode('client') - ->info('HttpClient to call the OIDC server.') - ->isRequired() - ->beforeNormalization() - ->ifString() - ->then(static function ($v): array { return ['id' => $v]; }) - ->end() - ->prototype('scalar')->end() + ->scalarNode('client') + ->info('HttpClient service id to use to call the OIDC server.') ->end() ->end() ->end() diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_access_token.php b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_access_token.php index fafe477d5bd23..3170112b46c08 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_access_token.php +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_access_token.php @@ -18,6 +18,7 @@ use Symfony\Component\Security\Http\AccessToken\Oidc\OidcUserInfoTokenHandler; use Symfony\Component\Security\Http\AccessToken\QueryAccessTokenExtractor; use Symfony\Component\Security\Http\Authenticator\AccessTokenAuthenticator; +use Symfony\Contracts\HttpClient\HttpClientInterface; return static function (ContainerConfigurator $container) { $container->services() @@ -44,12 +45,17 @@ ]) // OIDC + ->set('security.access_token_handler.oidc_user_info.http_client', HttpClientInterface::class) + ->abstract() + ->factory([service('http_client'), 'withOptions']) + ->args([abstract_arg('http client options')]) + ->set('security.access_token_handler.oidc_user_info', OidcUserInfoTokenHandler::class) ->abstract() ->args([ abstract_arg('http client'), service('logger')->nullOnInvalid(), - 'sub', + abstract_arg('claim'), ]) ->set('security.access_token_handler.oidc', OidcTokenHandler::class) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AccessTokenFactoryTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AccessTokenFactoryTest.php index a9da80fbb40ba..42f186e6e5b83 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AccessTokenFactoryTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AccessTokenFactoryTest.php @@ -18,7 +18,9 @@ use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AccessTokenFactory; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; +use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; class AccessTokenFactoryTest extends TestCase { @@ -76,7 +78,12 @@ public function testOidcUserInfoTokenHandlerConfigurationWithExistingClient() { $container = new ContainerBuilder(); $config = [ - 'token_handler' => ['oidc_user_info' => ['client' => 'oidc.client']], + 'token_handler' => [ + 'oidc_user_info' => [ + 'base_uri' => 'https://www.example.com/realms/demo/protocol/openid-connect/userinfo', + 'client' => 'oidc.client', + ], + ], ]; $factory = new AccessTokenFactory($this->createTokenHandlerFactories()); @@ -86,14 +93,24 @@ public function testOidcUserInfoTokenHandlerConfigurationWithExistingClient() $this->assertTrue($container->hasDefinition('security.authenticator.access_token.firewall1')); $this->assertTrue($container->hasDefinition('security.access_token_handler.firewall1')); - $this->assertFalse($container->hasDefinition('http_client.security.access_token_handler.oidc_user_info')); + + $expected = [ + 'index_0' => (new ChildDefinition('security.access_token_handler.oidc_user_info.http_client')) + ->setFactory([new Reference('oidc.client'), 'withOptions']) + ->replaceArgument(0, ['base_uri' => 'https://www.example.com/realms/demo/protocol/openid-connect/userinfo']), + 'index_2' => 'sub', + ]; + $this->assertEquals($expected, $container->getDefinition('security.access_token_handler.firewall1')->getArguments()); } - public function testOidcUserInfoTokenHandlerConfigurationWithClientCreation() + /** + * @dataProvider getOidcUserInfoConfiguration + */ + public function testOidcUserInfoTokenHandlerConfigurationWithBaseUri(array|string $configuration) { $container = new ContainerBuilder(); $config = [ - 'token_handler' => ['oidc_user_info' => ['client' => ['base_uri' => 'https://www.example.com/realms/demo/protocol/openid-connect/userinfo']]], + 'token_handler' => ['oidc_user_info' => $configuration], ]; $factory = new AccessTokenFactory($this->createTokenHandlerFactories()); @@ -103,7 +120,19 @@ public function testOidcUserInfoTokenHandlerConfigurationWithClientCreation() $this->assertTrue($container->hasDefinition('security.authenticator.access_token.firewall1')); $this->assertTrue($container->hasDefinition('security.access_token_handler.firewall1')); - $this->assertTrue($container->hasDefinition('http_client.security.access_token_handler.oidc_user_info')); + + $expected = [ + 'index_0' => (new ChildDefinition('security.access_token_handler.oidc_user_info.http_client')) + ->replaceArgument(0, ['base_uri' => 'https://www.example.com/realms/demo/protocol/openid-connect/userinfo']), + 'index_2' => 'sub', + ]; + $this->assertEquals($expected, $container->getDefinition('security.access_token_handler.firewall1')->getArguments()); + } + + public static function getOidcUserInfoConfiguration(): iterable + { + yield [['base_uri' => 'https://www.example.com/realms/demo/protocol/openid-connect/userinfo']]; + yield ['https://www.example.com/realms/demo/protocol/openid-connect/userinfo']; } public function testMultipleTokenHandlersSet() @@ -114,7 +143,7 @@ public function testMultipleTokenHandlersSet() $config = [ 'token_handler' => [ 'id' => 'in_memory_token_handler_service_id', - 'oidc_user_info' => ['client' => 'oidc.client'], + 'oidc_user_info' => 'https://www.example.com/realms/demo/protocol/openid-connect/userinfo', ], ]; diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 8fb916cd27114..55f1382dfaf7a 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -60,6 +60,7 @@ "symfony/browser-kit": "<5.4", "symfony/console": "<5.4", "symfony/framework-bundle": "<5.4", + "symfony/http-client": "<5.4", "symfony/ldap": "<5.4", "symfony/twig-bundle": "<5.4" }, From cf78f125d5a5ae35b51669a82a151b5b76f30c12 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 30 May 2023 17:06:47 +0200 Subject: [PATCH 17/25] Fix tests --- .../Security/Factory/AccessTokenFactoryTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AccessTokenFactoryTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AccessTokenFactoryTest.php index 42f186e6e5b83..4607830e73916 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AccessTokenFactoryTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AccessTokenFactoryTest.php @@ -21,6 +21,7 @@ use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Contracts\HttpClient\HttpClientInterface; class AccessTokenFactoryTest extends TestCase { @@ -126,6 +127,13 @@ public function testOidcUserInfoTokenHandlerConfigurationWithBaseUri(array|strin ->replaceArgument(0, ['base_uri' => 'https://www.example.com/realms/demo/protocol/openid-connect/userinfo']), 'index_2' => 'sub', ]; + + if (!interface_exists(HttpClientInterface::class)) { + $expected['index_0'] + ->setFactory(null) + ->addError('You cannot use the "oidc_user_info" token handler since the HttpClient component is not installed. Try running "composer require symfony/http-client".'); + } + $this->assertEquals($expected, $container->getDefinition('security.access_token_handler.firewall1')->getArguments()); } From 7776c28f745cf02d9a2ba085025750175d4af5a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 30 May 2023 17:24:33 +0200 Subject: [PATCH 18/25] [FrameworkBundle] remove support for preloading ESM modules using headers --- .../Controller/AbstractController.php | 15 +-------------- .../Tests/Controller/AbstractControllerTest.php | 1 - 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php b/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php index 6d39e9440f02a..13e155235358b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php @@ -14,7 +14,6 @@ use Psr\Container\ContainerInterface; use Psr\Link\EvolvableLinkInterface; use Psr\Link\LinkInterface; -use Symfony\Component\AssetMapper\ImportMap\ImportMapManager; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface; use Symfony\Component\Form\Extension\Core\Type\FormType; @@ -97,7 +96,6 @@ public static function getSubscribedServices(): array 'security.csrf.token_manager' => '?'.CsrfTokenManagerInterface::class, 'parameter_bag' => '?'.ContainerBagInterface::class, 'web_link.http_header_serializer' => '?'.HttpHeaderSerializer::class, - 'asset_mapper.importmap.manager' => '?'.ImportMapManager::class, ]; } @@ -412,7 +410,7 @@ protected function addLink(Request $request, LinkInterface $link): void /** * @param LinkInterface[] $links */ - protected function sendEarlyHints(iterable $links = [], Response $response = null, bool $preloadJavaScriptModules = false): Response + protected function sendEarlyHints(iterable $links = [], Response $response = null): Response { if (!$this->container->has('web_link.http_header_serializer')) { throw new \LogicException('You cannot use the "sendEarlyHints" method if the WebLink component is not available. Try running "composer require symfony/web-link".'); @@ -421,17 +419,6 @@ protected function sendEarlyHints(iterable $links = [], Response $response = nul $response ??= new Response(); $populatedLinks = []; - - if ($preloadJavaScriptModules) { - if (!$this->container->has('asset_mapper.importmap.manager')) { - throw new \LogicException('You cannot use the JavaScript modules method if the AssetMapper component is not available. Try running "composer require symfony/asset-mapper".'); - } - - foreach ($this->container->get('asset_mapper.importmap.manager')->getModulesToPreload() as $url) { - $populatedLinks[] = new Link('modulepreload', $url); - } - } - foreach ($links as $link) { if ($link instanceof EvolvableLinkInterface && !$link->getRels()) { $link = $link->withRel('preload'); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php index 960735e884958..efa9c7becab59 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php @@ -74,7 +74,6 @@ public function testSubscribedServices() 'security.token_storage' => '?Symfony\\Component\\Security\\Core\\Authentication\\Token\\Storage\\TokenStorageInterface', 'security.csrf.token_manager' => '?Symfony\\Component\\Security\\Csrf\\CsrfTokenManagerInterface', 'web_link.http_header_serializer' => '?Symfony\\Component\\WebLink\\HttpHeaderSerializer', - 'asset_mapper.importmap.manager' => '?Symfony\\Component\\AssetMapper\\ImportMap\\ImportMapManager', ]; $this->assertEquals($expectedServices, $subscribed, 'Subscribed core services in AbstractController have changed'); From bff06016b6fce5ac215e2f6a9ef2da1ff1991829 Mon Sep 17 00:00:00 2001 From: aegypius Date: Fri, 26 May 2023 12:00:24 +0200 Subject: [PATCH 19/25] [SecurityBundle] add missing xsd definition for OIDC --- .../Resources/config/schema/security-1.0.xsd | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) 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 23fe45e243fbf..2f08fcadfea1c 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 @@ -309,6 +309,7 @@ + @@ -317,6 +318,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From bb4eeb07a501d9b060f7f31622cc1fd250a71f5c Mon Sep 17 00:00:00 2001 From: MatTheCat Date: Tue, 30 May 2023 17:50:20 +0200 Subject: [PATCH 20/25] [DependencyInjection] Escape `%` from parameter-like default values --- .../Compiler/AutowirePass.php | 18 ++++++++++++++---- .../Tests/Compiler/AutowirePassTest.php | 13 +++++++++++++ .../Fixtures/includes/autowiring_classes.php | 7 +++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index 6c3cf82cac072..845f09c116fe1 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -52,6 +52,15 @@ public function __construct(bool $throwOnAutowireException = true) $this->defaultArgument = new class() { public $value; public $names; + public $bag; + + public function withValue(\ReflectionParameter $parameter): self + { + $clone = clone $this; + $clone->value = $this->bag->escapeValue($parameter->getDefaultValue()); + + return $clone; + } }; } @@ -60,6 +69,8 @@ public function __construct(bool $throwOnAutowireException = true) */ public function process(ContainerBuilder $container) { + $this->defaultArgument->bag = $container->getParameterBag(); + try { $this->typesClone = clone $this; parent::process($container); @@ -67,6 +78,7 @@ public function process(ContainerBuilder $container) $this->decoratedClass = null; $this->decoratedId = null; $this->methodCalls = null; + $this->defaultArgument->bag = null; $this->defaultArgument->names = null; $this->getPreviousValue = null; $this->decoratedMethodIndex = null; @@ -287,8 +299,7 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a } // specifically pass the default value - $arguments[$index] = clone $this->defaultArgument; - $arguments[$index]->value = $parameter->getDefaultValue(); + $arguments[$index] = $this->defaultArgument->withValue($parameter); continue; } @@ -298,8 +309,7 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a $failureMessage = $this->createTypeNotFoundMessageCallback($ref, sprintf('argument "$%s" of method "%s()"', $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method)); if ($parameter->isDefaultValueAvailable()) { - $value = clone $this->defaultArgument; - $value->value = $parameter->getDefaultValue(); + $value = $this->defaultArgument->withValue($parameter); } elseif (!$parameter->allowsNull()) { throw new AutowiringFailedException($this->currentId, $failureMessage); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index e61e2d45fc41f..ac81725033e42 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -1219,4 +1219,17 @@ public function testAutowireWithNamedArgs() $this->assertEquals([new TypedReference(A::class, A::class), 'abc'], $container->getDefinition('foo')->getArguments()); } + + public function testAutowireDefaultValueParametersLike() + { + $container = new ContainerBuilder(); + + $container->register('foo', ParametersLikeDefaultValue::class) + ->setAutowired(true) + ->setArgument(1, 'ok'); + + (new AutowirePass())->process($container); + + $this->assertSame('%%not%%one%%parameter%%here%%', $container->getDefinition('foo')->getArgument(0)); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php index ad1f06a49231e..87440891d85fc 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php @@ -431,3 +431,10 @@ public function __construct(NotExisting $notExisting) { } } + +class ParametersLikeDefaultValue +{ + public function __construct(string $parameterLike = '%not%one%parameter%here%', string $willBeSetToKeepFirstArgumentDefaultValue = 'ok') + { + } +} From 539413034b7906762f47b902bc49acb0d1a7365c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 30 May 2023 17:17:22 +0200 Subject: [PATCH 21/25] [Security] Add clock dependency to OidcTokenHandler From "web-token/jwt-checker": The parameter "$clock" will become mandatory in 4.0.0. Please set a valid PSR Clock implementation instead of "null". --- .../AccessToken/OidcTokenHandlerFactory.php | 48 +++++++++---------- .../Factory/SignatureAlgorithmFactory.php | 26 ++++------ .../Resources/config/schema/security-1.0.xsd | 8 ---- .../security_authenticator_access_token.php | 35 +++++++++++++- .../app/AccessToken/config_oidc.yml | 7 ++- .../Bundle/SecurityBundle/composer.json | 5 +- .../AccessToken/Oidc/OidcTokenHandler.php | 13 ++--- .../Oidc/OidcUserInfoTokenHandler.php | 2 +- .../AccessToken/Oidc/OidcTokenHandlerTest.php | 4 ++ .../Component/Security/Http/composer.json | 2 + 10 files changed, 85 insertions(+), 65 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php index 6f19f3845cb15..86d2783cb8d78 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php @@ -13,7 +13,6 @@ use Jose\Component\Core\Algorithm; use Jose\Component\Core\JWK; -use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SignatureAlgorithmFactory; use Symfony\Component\Config\Definition\Builder\NodeBuilder; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -28,26 +27,28 @@ class OidcTokenHandlerFactory implements TokenHandlerFactoryInterface { public function create(ContainerBuilder $container, string $id, array|string $config): void { - $tokenHandlerDefinition = $container->setDefinition($id, new ChildDefinition('security.access_token_handler.oidc')); - $tokenHandlerDefinition->replaceArgument(3, $config['claim']); - $tokenHandlerDefinition->replaceArgument(4, $config['audience']); + $tokenHandlerDefinition = $container->setDefinition($id, (new ChildDefinition('security.access_token_handler.oidc')) + ->replaceArgument(4, $config['claim']) + ->replaceArgument(5, $config['audience']) + ); - // Create the signature algorithm and the JWK if (!ContainerBuilder::willBeAvailable('web-token/jwt-core', Algorithm::class, ['symfony/security-bundle'])) { - $container->register('security.access_token_handler.oidc.signature', 'stdClass') + $container->register('security.access_token_handler.oidc.signature', Algorithm::class) ->addError('You cannot use the "oidc" token handler since "web-token/jwt-core" is not installed. Try running "web-token/jwt-core".'); - $container->register('security.access_token_handler.oidc.jwk', 'stdClass') + $container->register('security.access_token_handler.oidc.jwk', JWK::class) ->addError('You cannot use the "oidc" token handler since "web-token/jwt-core" is not installed. Try running "web-token/jwt-core".'); + } + + if (\in_array($config['algorithm'], ['ES256', 'ES384', 'ES512'], true)) { + $tokenHandlerDefinition->replaceArgument(0, new Reference('security.access_token_handler.oidc.signature.'.$config['algorithm'])); } else { - $container->register('security.access_token_handler.oidc.signature', Algorithm::class) - ->setFactory([SignatureAlgorithmFactory::class, 'create']) - ->setArguments([$config['signature']['algorithm']]); - $container->register('security.access_token_handler.oidc.jwk', JWK::class) - ->setFactory([JWK::class, 'createFromJson']) - ->setArguments([$config['signature']['key']]); + $tokenHandlerDefinition->replaceArgument(0, (new ChildDefinition('security.access_token_handler.oidc.signature'))) + ->replaceArgument(0, $config['algorithm']); } - $tokenHandlerDefinition->replaceArgument(0, new Reference('security.access_token_handler.oidc.signature')); - $tokenHandlerDefinition->replaceArgument(1, new Reference('security.access_token_handler.oidc.jwk')); + + $tokenHandlerDefinition->replaceArgument(1, (new ChildDefinition('security.access_token_handler.oidc.jwk')) + ->replaceArgument(0, $config['key']) + ); } public function getKey(): string @@ -69,18 +70,13 @@ public function addConfiguration(NodeBuilder $node): void ->info('Audience set in the token, for validation purpose.') ->defaultNull() ->end() - ->arrayNode('signature') + ->scalarNode('algorithm') + ->info('Algorithm used to sign the token.') + ->isRequired() + ->end() + ->scalarNode('key') + ->info('JSON-encoded JWK used to sign the token (must contain a "kty" key).') ->isRequired() - ->children() - ->scalarNode('algorithm') - ->info('Algorithm used to sign the token.') - ->isRequired() - ->end() - ->scalarNode('key') - ->info('JSON-encoded JWK used to sign the token (must contain a "kty" key).') - ->isRequired() - ->end() - ->end() ->end() ->end() ->end() diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SignatureAlgorithmFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SignatureAlgorithmFactory.php index f9f876deff2bf..a81d662cd338c 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SignatureAlgorithmFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SignatureAlgorithmFactory.php @@ -11,7 +11,7 @@ namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory; -use Jose\Component\Core\Algorithm as SignatureAlgorithm; +use Jose\Component\Core\Algorithm as AlgorithmInterface; use Jose\Component\Signature\Algorithm; use Symfony\Component\Security\Core\Exception\InvalidArgumentException; use Symfony\Component\Security\Http\AccessToken\Oidc\OidcTokenHandler; @@ -23,29 +23,21 @@ */ final class SignatureAlgorithmFactory { - public static function create(string $algorithm): SignatureAlgorithm + public static function create(string $algorithm): AlgorithmInterface { switch ($algorithm) { case 'ES256': - if (!class_exists(Algorithm\ES256::class)) { - throw new \LogicException('You cannot use the "ES256" signature algorithm since "web-token/jwt-signature-algorithm-ecdsa" is not installed. Try running "composer require web-token/jwt-signature-algorithm-ecdsa".'); - } - - return new Algorithm\ES256(); case 'ES384': - if (!class_exists(Algorithm\ES384::class)) { - throw new \LogicException('You cannot use the "ES384" signature algorithm since "web-token/jwt-signature-algorithm-ecdsa" is not installed. Try running "composer require web-token/jwt-signature-algorithm-ecdsa".'); - } - - return new Algorithm\ES384(); case 'ES512': - if (!class_exists(Algorithm\ES512::class)) { - throw new \LogicException('You cannot use the "ES512" signature algorithm since "web-token/jwt-signature-algorithm-ecdsa" is not installed. Try running "composer require web-token/jwt-signature-algorithm-ecdsa".'); + if (!class_exists(Algorithm::class.'\\'.$algorithm)) { + throw new \LogicException(sprintf('You cannot use the "%s" signature algorithm since "web-token/jwt-signature-algorithm-ecdsa" is not installed. Try running "composer require web-token/jwt-signature-algorithm-ecdsa".', $algorithm)); } - return new Algorithm\ES512(); - default: - throw new InvalidArgumentException(sprintf('Unsupported signature algorithm "%s". Only ES* algorithms are supported. If you want to use another algorithm, create your TokenHandler as a service.', $algorithm)); + $algorithm = Algorithm::class.'\\'.$algorithm; + + return new $algorithm(); } + + throw new InvalidArgumentException(sprintf('Unsupported signature algorithm "%s". Only ES* algorithms are supported. If you want to use another algorithm, create your TokenHandler as a service.', $algorithm)); } } 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 2f08fcadfea1c..7798be2a28632 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 @@ -335,16 +335,8 @@ - - - - - - - - diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_access_token.php b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_access_token.php index 3170112b46c08..32eac0e580c57 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_access_token.php +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_access_token.php @@ -11,6 +11,12 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; +use Jose\Component\Core\Algorithm; +use Jose\Component\Core\JWK; +use Jose\Component\Signature\Algorithm\ES256; +use Jose\Component\Signature\Algorithm\ES384; +use Jose\Component\Signature\Algorithm\ES512; +use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SignatureAlgorithmFactory; use Symfony\Component\Security\Http\AccessToken\ChainAccessTokenExtractor; use Symfony\Component\Security\Http\AccessToken\FormEncodedBodyExtractor; use Symfony\Component\Security\Http\AccessToken\HeaderAccessTokenExtractor; @@ -62,10 +68,37 @@ ->abstract() ->args([ abstract_arg('signature algorithm'), - abstract_arg('jwk'), + abstract_arg('signature key'), service('logger')->nullOnInvalid(), + service('clock'), 'sub', null, ]) + + ->set('security.access_token_handler.oidc.jwk', JWK::class) + ->abstract() + ->factory([JWK::class, 'createFromJson']) + ->args([ + abstract_arg('signature key'), + ]) + + ->set('security.access_token_handler.oidc.signature', Algorithm::class) + ->abstract() + ->factory([SignatureAlgorithmFactory::class, 'create']) + ->args([ + abstract_arg('signature algorithm'), + ]) + + ->set('security.access_token_handler.oidc.signature.ES256', ES256::class) + ->parent('security.access_token_handler.oidc.signature') + ->args(['index_0' => 'ES256']) + + ->set('security.access_token_handler.oidc.signature.ES384', ES384::class) + ->parent('security.access_token_handler.oidc.signature') + ->args(['index_0' => 'ES384']) + + ->set('security.access_token_handler.oidc.signature.ES512', ES512::class) + ->parent('security.access_token_handler.oidc.signature') + ->args(['index_0' => 'ES512']) ; }; diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_oidc.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_oidc.yml index 45802961a1a61..920bc81f1e788 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_oidc.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_oidc.yml @@ -23,10 +23,9 @@ security: oidc: claim: 'username' audience: 'Symfony OIDC' - signature: - algorithm: 'ES256' - # tip: use https://mkjwk.org/ to generate a JWK - key: '{"kty":"EC","d":"iA_TV2zvftni_9aFAQwFO_9aypfJFCSpcCyevDvz220","crv":"P-256","x":"0QEAsI1wGI-dmYatdUZoWSRWggLEpyzopuhwk-YUnA4","y":"KYl-qyZ26HobuYwlQh-r0iHX61thfP82qqEku7i0woo"}' + algorithm: 'ES256' + # tip: use https://mkjwk.org/ to generate a JWK + key: '{"kty":"EC","d":"iA_TV2zvftni_9aFAQwFO_9aypfJFCSpcCyevDvz220","crv":"P-256","x":"0QEAsI1wGI-dmYatdUZoWSRWggLEpyzopuhwk-YUnA4","y":"KYl-qyZ26HobuYwlQh-r0iHX61thfP82qqEku7i0woo"}' token_extractors: 'header' realm: 'My API' diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 55f1382dfaf7a..c10e76ca459bb 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -19,6 +19,7 @@ "php": ">=8.1", "composer-runtime-api": ">=2.1", "ext-xml": "*", + "symfony/clock": "^6.3", "symfony/config": "^6.1", "symfony/dependency-injection": "^6.2", "symfony/event-dispatcher": "^5.4|^6.0", @@ -38,7 +39,7 @@ "symfony/dom-crawler": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/form": "^5.4|^6.0", - "symfony/framework-bundle": "^5.4|^6.0", + "symfony/framework-bundle": "^6.3", "symfony/ldap": "^5.4|^6.0", "symfony/process": "^5.4|^6.0", "symfony/rate-limiter": "^5.4|^6.0", @@ -59,7 +60,7 @@ "conflict": { "symfony/browser-kit": "<5.4", "symfony/console": "<5.4", - "symfony/framework-bundle": "<5.4", + "symfony/framework-bundle": "<6.3", "symfony/http-client": "<5.4", "symfony/ldap": "<5.4", "symfony/twig-bundle": "<5.4" diff --git a/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcTokenHandler.php b/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcTokenHandler.php index 047cc3318e017..c103236ed2021 100644 --- a/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcTokenHandler.php +++ b/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcTokenHandler.php @@ -20,8 +20,9 @@ use Jose\Component\Signature\JWSVerifier; use Jose\Component\Signature\Serializer\CompactSerializer; use Jose\Component\Signature\Serializer\JWSSerializerManager; +use Psr\Clock\ClockInterface; use Psr\Log\LoggerInterface; -use Symfony\Component\Clock\NativeClock; +use Symfony\Component\Clock\Clock; use Symfony\Component\Security\Core\Exception\BadCredentialsException; use Symfony\Component\Security\Http\AccessToken\AccessTokenHandlerInterface; use Symfony\Component\Security\Http\AccessToken\Oidc\Exception\InvalidSignatureException; @@ -41,6 +42,7 @@ public function __construct( private Algorithm $signatureAlgorithm, private JWK $jwk, private ?LoggerInterface $logger = null, + private ClockInterface $clock = new Clock(), private string $claim = 'sub', private ?string $audience = null ) { @@ -74,11 +76,10 @@ public function getUserBadgeFrom(string $accessToken): UserBadge $headerCheckerManager->check($jws, 0); // Verify the claims - $clock = class_exists(NativeClock::class) ? new NativeClock() : null; $checkers = [ - new Checker\IssuedAtChecker(0, false, $clock), - new Checker\NotBeforeChecker(0, false, $clock), - new Checker\ExpirationTimeChecker(0, false, $clock), + new Checker\IssuedAtChecker(0, false, $this->clock), + new Checker\NotBeforeChecker(0, false, $this->clock), + new Checker\ExpirationTimeChecker(0, false, $this->clock), ]; if ($this->audience) { $checkers[] = new Checker\AudienceChecker($this->audience); @@ -93,7 +94,7 @@ public function getUserBadgeFrom(string $accessToken): UserBadge // UserLoader argument can be overridden by a UserProvider on AccessTokenAuthenticator::authenticate return new UserBadge($claims[$this->claim], fn () => $this->createUser($claims), $claims); - } catch (\Throwable $e) { + } catch (\Exception $e) { $this->logger?->error('An error while decoding and validating the token.', [ 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), diff --git a/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcUserInfoTokenHandler.php b/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcUserInfoTokenHandler.php index d69775f192e20..26279ebf19e68 100644 --- a/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcUserInfoTokenHandler.php +++ b/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcUserInfoTokenHandler.php @@ -49,7 +49,7 @@ public function getUserBadgeFrom(string $accessToken): UserBadge // UserLoader argument can be overridden by a UserProvider on AccessTokenAuthenticator::authenticate return new UserBadge($claims[$this->claim], fn () => $this->createUser($claims), $claims); - } catch (\Throwable $e) { + } catch (\Exception $e) { $this->logger?->error('An error occurred on OIDC server.', [ 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), diff --git a/src/Symfony/Component/Security/Http/Tests/AccessToken/Oidc/OidcTokenHandlerTest.php b/src/Symfony/Component/Security/Http/Tests/AccessToken/Oidc/OidcTokenHandlerTest.php index d9fa14f0b8ff5..2d35bfb8aede3 100644 --- a/src/Symfony/Component/Security/Http/Tests/AccessToken/Oidc/OidcTokenHandlerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/AccessToken/Oidc/OidcTokenHandlerTest.php @@ -18,6 +18,7 @@ use Jose\Component\Signature\Serializer\CompactSerializer; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; +use Symfony\Component\Clock\Clock; use Symfony\Component\Security\Core\Exception\BadCredentialsException; use Symfony\Component\Security\Core\User\OidcUser; use Symfony\Component\Security\Http\AccessToken\Oidc\OidcTokenHandler; @@ -55,6 +56,7 @@ public function testGetsUserIdentifierFromSignedToken(string $claim, string $exp new ES256(), $this->getJWK(), $loggerMock, + new Clock(), $claim, self::AUDIENCE ))->getUserBadgeFrom($token); @@ -88,6 +90,7 @@ public function testThrowsAnErrorIfTokenIsInvalid(string $token) new ES256(), $this->getJWK(), $loggerMock, + new Clock(), 'sub', self::AUDIENCE ))->getUserBadgeFrom($token); @@ -146,6 +149,7 @@ public function testThrowsAnErrorIfUserPropertyIsMissing() new ES256(), self::getJWK(), $loggerMock, + new Clock(), 'email', self::AUDIENCE ))->getUserBadgeFrom($token); diff --git a/src/Symfony/Component/Security/Http/composer.json b/src/Symfony/Component/Security/Http/composer.json index b3c688147e9ea..74f7ddb8f50d0 100644 --- a/src/Symfony/Component/Security/Http/composer.json +++ b/src/Symfony/Component/Security/Http/composer.json @@ -26,6 +26,7 @@ }, "require-dev": { "symfony/cache": "^5.4|^6.0", + "symfony/clock": "^6.3", "symfony/expression-language": "^5.4|^6.0", "symfony/http-client-contracts": "^3.0", "symfony/rate-limiter": "^5.4|^6.0", @@ -37,6 +38,7 @@ "web-token/jwt-signature-algorithm-ecdsa": "^3.1" }, "conflict": { + "symfony/clock": "<6.3", "symfony/event-dispatcher": "<5.4.9|>=6,<6.0.9", "symfony/http-client-contracts": "<3.0", "symfony/security-bundle": "<5.4", From 4aa8b46c2ee59c9f54a97f2ae200891f30b8671e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Auswo=CC=88ger?= Date: Thu, 25 May 2023 23:26:31 +0200 Subject: [PATCH 22/25] [Filesystem] Follow symlinks when dumping files --- .../Component/Filesystem/Filesystem.php | 6 ++ .../Filesystem/Tests/FilesystemTest.php | 67 ++++++++++++++++++- 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index 98725e9149931..23192bc74c237 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -669,6 +669,12 @@ public function dumpFile(string $filename, $content) $dir = \dirname($filename); + if (is_link($filename) && $linkTarget = $this->readlink($filename)) { + $this->dumpFile(Path::makeAbsolute($linkTarget, $dir), $content); + + return; + } + if (!is_dir($dir)) { $this->mkdir($dir); } diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index 768b9db6f97b5..252635bc95e8f 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -1091,14 +1091,16 @@ public function testReadBrokenLink() { $this->markAsSkippedIfSymlinkIsMissing(); - if ('\\' === \DIRECTORY_SEPARATOR) { - $this->markTestSkipped('Windows does not support creating "broken" symlinks'); + if ('\\' === \DIRECTORY_SEPARATOR && \PHP_VERSION_ID < 70400) { + $this->markTestSkipped('Windows does not support reading "broken" symlinks in PHP < 7.4.0'); } $file = $this->workspace.'/file'; $link = $this->workspace.'/link'; + touch($file); $this->filesystem->symlink($file, $link); + $this->filesystem->remove($file); $this->assertEquals($file, $this->filesystem->readlink($link)); $this->assertNull($this->filesystem->readlink($link, true)); @@ -1605,6 +1607,38 @@ public function testDumpFileOverwritesAnExistingFile() $this->assertStringEqualsFile($filename, 'bar'); } + public function testDumpFileFollowsSymlink() + { + $filename = $this->workspace.\DIRECTORY_SEPARATOR.'foo.txt'; + file_put_contents($filename, 'FOO BAR'); + $linknameA = $this->workspace.\DIRECTORY_SEPARATOR.'bar.txt'; + $linknameB = $this->workspace.\DIRECTORY_SEPARATOR.'baz.txt'; + $this->filesystem->symlink($filename, $linknameA); + $this->filesystem->symlink($linknameA, $linknameB); + + $this->filesystem->dumpFile($linknameB, 'bar'); + + $this->assertFileExists($filename); + $this->assertFileExists($linknameA); + $this->assertFileExists($linknameB); + $this->assertStringEqualsFile($filename, 'bar'); + $this->assertStringEqualsFile($linknameA, 'bar'); + $this->assertStringEqualsFile($linknameB, 'bar'); + + // Windows does not support reading "broken" symlinks in PHP < 7.4.0 + if ('\\' === \DIRECTORY_SEPARATOR && \PHP_VERSION_ID < 70400) { + return; + } + + $this->filesystem->remove($filename); + $this->filesystem->dumpFile($linknameB, 'baz'); + + $this->assertFileExists($filename); + $this->assertStringEqualsFile($filename, 'baz'); + $this->assertStringEqualsFile($linknameA, 'baz'); + $this->assertStringEqualsFile($linknameB, 'baz'); + } + public function testDumpFileWithFileScheme() { $scheme = 'file://'; @@ -1678,6 +1712,35 @@ public function testAppendToFileWithResource() } } + public function testAppendToFileFollowsSymlink() + { + $filename = $this->workspace.\DIRECTORY_SEPARATOR.'foo.txt'; + file_put_contents($filename, 'foo'); + $linknameA = $this->workspace.\DIRECTORY_SEPARATOR.'bar.txt'; + $linknameB = $this->workspace.\DIRECTORY_SEPARATOR.'baz.txt'; + $this->filesystem->symlink($filename, $linknameA); + $this->filesystem->symlink($linknameA, $linknameB); + + $this->filesystem->appendToFile($linknameA, 'bar'); + $this->filesystem->appendToFile($linknameB, 'baz'); + + $this->assertFileExists($filename); + $this->assertFileExists($linknameA); + $this->assertFileExists($linknameB); + $this->assertStringEqualsFile($filename, 'foobarbaz'); + $this->assertStringEqualsFile($linknameA, 'foobarbaz'); + $this->assertStringEqualsFile($linknameB, 'foobarbaz'); + + $this->filesystem->remove($filename); + $this->filesystem->appendToFile($linknameB, 'foo'); + $this->filesystem->appendToFile($linknameA, 'bar'); + + $this->assertFileExists($filename); + $this->assertStringEqualsFile($filename, 'foobar'); + $this->assertStringEqualsFile($linknameA, 'foobar'); + $this->assertStringEqualsFile($linknameB, 'foobar'); + } + public function testAppendToFileWithScheme() { $scheme = 'file://'; From 90011f59584820465aa92b213a2a11531ccc20cf Mon Sep 17 00:00:00 2001 From: Vincent Chalamon <407859+vincentchalamon@users.noreply.github.com> Date: Thu, 25 May 2023 15:13:40 +0200 Subject: [PATCH 23/25] [Security] Validate `aud` and `iss` claims on OidcTokenHandler --- .../AccessToken/OidcTokenHandlerFactory.php | 17 +++++++++--- .../Resources/config/schema/security-1.0.xsd | 12 ++++++++- .../security_authenticator_access_token.php | 5 ++-- .../Tests/Functional/AccessTokenTest.php | 2 +- .../app/AccessToken/config_oidc.yml | 1 + .../AccessToken/Oidc/OidcTokenHandler.php | 12 ++++----- .../AccessToken/Oidc/OidcTokenHandlerTest.php | 27 +++++++++---------- 7 files changed, 48 insertions(+), 28 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php index 86d2783cb8d78..18a5ee6ac3eef 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php @@ -28,8 +28,9 @@ class OidcTokenHandlerFactory implements TokenHandlerFactoryInterface public function create(ContainerBuilder $container, string $id, array|string $config): void { $tokenHandlerDefinition = $container->setDefinition($id, (new ChildDefinition('security.access_token_handler.oidc')) + ->replaceArgument(2, $config['audience']) + ->replaceArgument(3, $config['issuers']) ->replaceArgument(4, $config['claim']) - ->replaceArgument(5, $config['audience']) ); if (!ContainerBuilder::willBeAvailable('web-token/jwt-core', Algorithm::class, ['symfony/security-bundle'])) { @@ -39,11 +40,14 @@ public function create(ContainerBuilder $container, string $id, array|string $co ->addError('You cannot use the "oidc" token handler since "web-token/jwt-core" is not installed. Try running "web-token/jwt-core".'); } + // @see Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SignatureAlgorithmFactory + // for supported algorithms if (\in_array($config['algorithm'], ['ES256', 'ES384', 'ES512'], true)) { $tokenHandlerDefinition->replaceArgument(0, new Reference('security.access_token_handler.oidc.signature.'.$config['algorithm'])); } else { - $tokenHandlerDefinition->replaceArgument(0, (new ChildDefinition('security.access_token_handler.oidc.signature'))) - ->replaceArgument(0, $config['algorithm']); + $tokenHandlerDefinition->replaceArgument(0, (new ChildDefinition('security.access_token_handler.oidc.signature')) + ->replaceArgument(0, $config['algorithm']) + ); } $tokenHandlerDefinition->replaceArgument(1, (new ChildDefinition('security.access_token_handler.oidc.jwk')) @@ -68,7 +72,12 @@ public function addConfiguration(NodeBuilder $node): void ->end() ->scalarNode('audience') ->info('Audience set in the token, for validation purpose.') - ->defaultNull() + ->isRequired() + ->end() + ->arrayNode('issuers') + ->info('Issuers allowed to generate the token, for validation purpose.') + ->isRequired() + ->prototype('scalar')->end() ->end() ->scalarNode('algorithm') ->info('Algorithm used to sign the token.') 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 7798be2a28632..ab90f4b42606c 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 @@ -335,12 +335,22 @@ + + + + - + + + + + + + diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_access_token.php b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_access_token.php index 32eac0e580c57..3254f332aace0 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_access_token.php +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_access_token.php @@ -69,10 +69,11 @@ ->args([ abstract_arg('signature algorithm'), abstract_arg('signature key'), + abstract_arg('audience'), + abstract_arg('issuers'), + 'sub', service('logger')->nullOnInvalid(), service('clock'), - 'sub', - null, ]) ->set('security.access_token_handler.oidc.jwk', JWK::class) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AccessTokenTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AccessTokenTest.php index 8ca49ccc1430c..3deb91402165e 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AccessTokenTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AccessTokenTest.php @@ -343,7 +343,7 @@ public function testOidcSuccess() 'iat' => $time, 'nbf' => $time, 'exp' => $time + 3600, - 'iss' => 'https://www.example.com/', + 'iss' => 'https://www.example.com', 'aud' => 'Symfony OIDC', 'sub' => 'e21bf182-1538-406e-8ccb-e25a17aba39f', 'username' => 'dunglas', diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_oidc.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_oidc.yml index 920bc81f1e788..dd770e4520e41 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_oidc.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_oidc.yml @@ -23,6 +23,7 @@ security: oidc: claim: 'username' audience: 'Symfony OIDC' + issuers: [ 'https://www.example.com' ] algorithm: 'ES256' # tip: use https://mkjwk.org/ to generate a JWK key: '{"kty":"EC","d":"iA_TV2zvftni_9aFAQwFO_9aypfJFCSpcCyevDvz220","crv":"P-256","x":"0QEAsI1wGI-dmYatdUZoWSRWggLEpyzopuhwk-YUnA4","y":"KYl-qyZ26HobuYwlQh-r0iHX61thfP82qqEku7i0woo"}' diff --git a/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcTokenHandler.php b/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcTokenHandler.php index c103236ed2021..0623a60016a0d 100644 --- a/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcTokenHandler.php +++ b/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcTokenHandler.php @@ -41,10 +41,11 @@ final class OidcTokenHandler implements AccessTokenHandlerInterface public function __construct( private Algorithm $signatureAlgorithm, private JWK $jwk, - private ?LoggerInterface $logger = null, - private ClockInterface $clock = new Clock(), + private string $audience, + private array $issuers, private string $claim = 'sub', - private ?string $audience = null + private ?LoggerInterface $logger = null, + private ClockInterface $clock = new Clock() ) { } @@ -80,10 +81,9 @@ public function getUserBadgeFrom(string $accessToken): UserBadge new Checker\IssuedAtChecker(0, false, $this->clock), new Checker\NotBeforeChecker(0, false, $this->clock), new Checker\ExpirationTimeChecker(0, false, $this->clock), + new Checker\AudienceChecker($this->audience), + new Checker\IssuerChecker($this->issuers), ]; - if ($this->audience) { - $checkers[] = new Checker\AudienceChecker($this->audience); - } $claimCheckerManager = new ClaimCheckerManager($checkers); // if this check fails, an InvalidClaimException is thrown $claimCheckerManager->check($claims); diff --git a/src/Symfony/Component/Security/Http/Tests/AccessToken/Oidc/OidcTokenHandlerTest.php b/src/Symfony/Component/Security/Http/Tests/AccessToken/Oidc/OidcTokenHandlerTest.php index 2d35bfb8aede3..8c8d86284b59a 100644 --- a/src/Symfony/Component/Security/Http/Tests/AccessToken/Oidc/OidcTokenHandlerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/AccessToken/Oidc/OidcTokenHandlerTest.php @@ -18,7 +18,6 @@ use Jose\Component\Signature\Serializer\CompactSerializer; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; -use Symfony\Component\Clock\Clock; use Symfony\Component\Security\Core\Exception\BadCredentialsException; use Symfony\Component\Security\Core\User\OidcUser; use Symfony\Component\Security\Http\AccessToken\Oidc\OidcTokenHandler; @@ -41,7 +40,7 @@ public function testGetsUserIdentifierFromSignedToken(string $claim, string $exp 'iat' => $time, 'nbf' => $time, 'exp' => $time + 3600, - 'iss' => 'https://www.example.com/', + 'iss' => 'https://www.example.com', 'aud' => self::AUDIENCE, 'sub' => 'e21bf182-1538-406e-8ccb-e25a17aba39f', 'email' => 'foo@example.com', @@ -55,10 +54,10 @@ public function testGetsUserIdentifierFromSignedToken(string $claim, string $exp $userBadge = (new OidcTokenHandler( new ES256(), $this->getJWK(), - $loggerMock, - new Clock(), + self::AUDIENCE, + ['https://www.example.com'], $claim, - self::AUDIENCE + $loggerMock, ))->getUserBadgeFrom($token); $actualUser = $userBadge->getUserLoader()(); @@ -89,10 +88,10 @@ public function testThrowsAnErrorIfTokenIsInvalid(string $token) (new OidcTokenHandler( new ES256(), $this->getJWK(), - $loggerMock, - new Clock(), + self::AUDIENCE, + ['https://www.example.com'], 'sub', - self::AUDIENCE + $loggerMock, ))->getUserBadgeFrom($token); } @@ -106,7 +105,7 @@ public static function getInvalidTokens(): iterable 'iat' => time() - 3600, 'nbf' => time() - 3600, 'exp' => time() - 3590, - 'iss' => 'https://www.example.com/', + 'iss' => 'https://www.example.com', 'aud' => self::AUDIENCE, 'sub' => 'e21bf182-1538-406e-8ccb-e25a17aba39f', 'email' => 'foo@example.com', @@ -118,7 +117,7 @@ public static function getInvalidTokens(): iterable 'iat' => time(), 'nbf' => time(), 'exp' => time() + 3590, - 'iss' => 'https://www.example.com/', + 'iss' => 'https://www.example.com', 'aud' => 'invalid', 'sub' => 'e21bf182-1538-406e-8ccb-e25a17aba39f', 'email' => 'foo@example.com', @@ -139,7 +138,7 @@ public function testThrowsAnErrorIfUserPropertyIsMissing() 'iat' => $time, 'nbf' => $time, 'exp' => $time + 3600, - 'iss' => 'https://www.example.com/', + 'iss' => 'https://www.example.com', 'aud' => self::AUDIENCE, 'sub' => 'e21bf182-1538-406e-8ccb-e25a17aba39f', ]; @@ -148,10 +147,10 @@ public function testThrowsAnErrorIfUserPropertyIsMissing() (new OidcTokenHandler( new ES256(), self::getJWK(), - $loggerMock, - new Clock(), + self::AUDIENCE, + ['https://www.example.com'], 'email', - self::AUDIENCE + $loggerMock, ))->getUserBadgeFrom($token); } From e9afaa379d0f66d880777537e77d337f9c2a423d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 30 May 2023 21:03:29 +0200 Subject: [PATCH 24/25] Update CHANGELOG for 6.3.0 --- CHANGELOG-6.3.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG-6.3.md b/CHANGELOG-6.3.md index 73ef0487e49f5..e5d6c9162a7c5 100644 --- a/CHANGELOG-6.3.md +++ b/CHANGELOG-6.3.md @@ -7,6 +7,21 @@ in 6.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/v6.3.0...v6.3.1 +* 6.3.0 (2023-05-30) + + * bug #50432 [Security] Validate `aud` and `iss` claims on OidcTokenHandler (vincentchalamon) + * bug #50477 [Security] Add clock dependency to OidcTokenHandler (nicolas-grekas) + * bug #50437 [Filesystem] Follow symlinks when dumping files (ausi) + * bug #50478 [DependencyInjection] Escape `` from parameter-like default values (MatTheCat) + * bug #50476 [FrameworkBundle] remove support for preloading ESM using headers (dunglas) + * bug #50453 [SecurityBundle] add missing xsd definition for OIDC (aegypius) + * bug #50468 [FrameworkBundle][PhpUnitBridge] Configure doctrine/deprecations as expected (nicolas-grekas) + * bug #50473 [Notifier] Fix ContactEveryoneOptions (nicolas-grekas) + * bug #50470 [SecurityBundle] Fix configuring OIDC user info token handler client (vincentchalamon) + * bug #50456 [AssetMapper] Fix unable to use asset mapper with CSP (vtsykun) + * bug #50458 [HttpKernel] Fix default value ignored with pinned resolvers (HypeMC) + * bug #50452 Hide definitions bearing the `container.excluded` tag (Myks92) + * 6.3.0-RC2 (2023-05-27) * feature #50445 [AssetMapper] Add "=alias" syntax to importmap:require (weaverryan) From 9241f844e74b545bbb0cbed9b8eeb16773b87026 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 30 May 2023 21:03:32 +0200 Subject: [PATCH 25/25] Update VERSION for 6.3.0 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index f9a969b659130..c98705163d086 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -76,12 +76,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static array $freshCache = []; - public const VERSION = '6.3.0-DEV'; + public const VERSION = '6.3.0'; public const VERSION_ID = 60300; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 3; public const RELEASE_VERSION = 0; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '01/2024'; public const END_OF_LIFE = '01/2024';