Skip to content

Commit 279a6b9

Browse files
committed
Merge branch '2.1'
2 parents 1cf2081 + b7d4d46 commit 279a6b9

File tree

6 files changed

+165
-80
lines changed

6 files changed

+165
-80
lines changed

book/_security-2012-6431.rst.inc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.. note::
2+
3+
Since Symfony 2.0.20/2.1.5, the Twig ``render`` tag now takes an absolute url
4+
instead of a controller logical path. This fixes an important security
5+
issue (`CVE-2012-6431`_) reported on the official blog. If your application
6+
uses an older version of Symfony or still uses the previous ``render`` tag
7+
syntax, you should upgrade as soon as possible.
8+
9+
.. _`CVE-2012-6431`: http://symfony.com/blog/security-release-symfony-2-0-20-and-2-1-5-released

book/http_cache.rst

Lines changed: 41 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -881,17 +881,50 @@ matter), Symfony2 uses the standard ``render`` helper to configure ESI tags:
881881

882882
.. code-block:: jinja
883883
884-
{% render '...:news' with {}, {'standalone': true} %}
884+
{% render url('latest_news', { 'max': 5 }), {'standalone': true} %}
885885
886886
.. code-block:: php
887887
888-
<?php echo $view['actions']->render('...:news', array(), array('standalone' => true)) ?>
888+
<?php echo $view['actions']->render(
889+
$view['router']->generate('latest_news', array('max' => 5), true),
890+
array('standalone' => true)
891+
) ?>
889892
890-
By setting ``standalone`` to ``true``, you tell Symfony2 that the action
891-
should be rendered as an ESI tag. You might be wondering why you would want to
892-
use a helper instead of just writing the ESI tag yourself. That's because
893-
using a helper makes your application work even if there is no gateway cache
894-
installed.
893+
.. include:: /book/_security-2012-6431.rst.inc
894+
895+
The ``render`` tag takes the absolute url to the embedded action. This means
896+
that you need to define a new route to the controller that you're embedding:
897+
898+
.. code-block:: yaml
899+
900+
# app/config/routing.yml
901+
latest_news:
902+
pattern: /esi/latest-news/{max}
903+
defaults: { _controller: AcmeNewsBundle:News:news }
904+
requirements: { max: \d+ }
905+
906+
.. caution::
907+
908+
Unless you want this URL to be accessible to the outside world, you
909+
should use Symfony's firewall to secure it (by allowing access to your
910+
reverse proxy's IP range). See the :ref:`Securing by IP<book-security-securing-ip>`
911+
section of the :doc:`Security Chapter </book/security>` for more information
912+
on how to do this.
913+
914+
.. tip::
915+
916+
The best practice is to mount all your ESI urls on a single prefix (e.g.
917+
``/esi``) of your choice. This has two main advantages. First, it eases
918+
the management of ESI urls as you can easily identify the routes used for ESI.
919+
Second, it eases security management since securing all urls starting
920+
with the same prefix is easier than securing each individual url. See
921+
the above note for more details on securing ESI URLs.
922+
923+
By setting ``standalone`` to ``true`` in the ``render`` Twig tag, you tell
924+
Symfony2 that the action should be rendered as an ESI tag. You might be
925+
wondering why you would want to use a helper instead of just writing the ESI tag
926+
yourself. That's because using a helper makes your application work even if
927+
there is no gateway cache installed.
895928

896929
When standalone is ``false`` (the default), Symfony2 merges the included page
897930
content within the main one before sending the response to the client. But
@@ -912,7 +945,7 @@ of the master page.
912945

913946
.. code-block:: php
914947
915-
public function newsAction()
948+
public function newsAction($max)
916949
{
917950
// ...
918951
@@ -922,52 +955,6 @@ of the master page.
922955
With ESI, the full page cache will be valid for 600 seconds, but the news
923956
component cache will only last for 60 seconds.
924957

925-
A requirement of ESI, however, is that the embedded action be accessible
926-
via a URL so the gateway cache can fetch it independently of the rest of
927-
the page. Of course, an action can't be accessed via a URL unless it has
928-
a route that points to it. Symfony2 takes care of this via a generic route
929-
and controller. For the ESI include tag to work properly, you must define
930-
the ``_internal`` route:
931-
932-
.. configuration-block::
933-
934-
.. code-block:: yaml
935-
936-
# app/config/routing.yml
937-
_internal:
938-
resource: "@FrameworkBundle/Resources/config/routing/internal.xml"
939-
prefix: /_internal
940-
941-
.. code-block:: xml
942-
943-
<!-- app/config/routing.xml -->
944-
<?xml version="1.0" encoding="UTF-8" ?>
945-
946-
<routes xmlns="http://symfony.com/schema/routing"
947-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
948-
xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
949-
950-
<import resource="@FrameworkBundle/Resources/config/routing/internal.xml" prefix="/_internal" />
951-
</routes>
952-
953-
.. code-block:: php
954-
955-
// app/config/routing.php
956-
use Symfony\Component\Routing\RouteCollection;
957-
use Symfony\Component\Routing\Route;
958-
959-
$collection->addCollection($loader->import('@FrameworkBundle/Resources/config/routing/internal.xml', '/_internal'));
960-
961-
return $collection;
962-
963-
.. tip::
964-
965-
Since this route allows all actions to be accessed via a URL, you might
966-
want to protect it by using the Symfony2 firewall feature (by allowing
967-
access to your reverse proxy's IP range). See the :ref:`Securing by IP<book-security-securing-ip>`
968-
section of the :doc:`Security Chapter </book/security>` for more information
969-
on how to do this.
970-
971958
One great advantage of this caching strategy is that you can make your
972959
application as dynamic as needed and at the same time, hit the application as
973960
little as possible.

book/security.rst

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -755,14 +755,16 @@ Securing by IP
755755
~~~~~~~~~~~~~~
756756

757757
Certain situations may arise when you may need to restrict access to a given
758-
route based on IP. This is particularly relevant in the case of :ref:`Edge Side Includes<edge-side-includes>`
759-
(ESI), for example, which utilize a route named "_internal". When
760-
ESI is used, the _internal route is required by the gateway cache to enable
761-
different caching options for subsections within a given page. This route
762-
comes with the ^/_internal prefix by default in the standard edition (assuming
763-
you've uncommented those lines from the routing file).
758+
route based on IP. This is particularly relevant in the case of
759+
:ref:`Edge Side Includes<edge-side-includes>` (ESI), for example. When ESI is
760+
enabled, it's recommended to secure access to ESI URLs. Indeed, some ESI may
761+
contain some private contents like the current logged in user's information. To
762+
prevent any direct access to these resources from a web browser by guessing the
763+
URL pattern, the ESI route must be secured to be only visible from the trusted
764+
reverse proxy cache.
764765

765-
Here is an example of how you might secure this route from outside access:
766+
Here is an example of how you might secure all ESI routes that start with a
767+
given prefix, ``/esi``, from outside access:
766768

767769
.. configuration-block::
768770

@@ -772,22 +774,24 @@ Here is an example of how you might secure this route from outside access:
772774
security:
773775
# ...
774776
access_control:
775-
- { path: ^/_internal, roles: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 }
777+
- { path: ^/esi, roles: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 }
776778
777779
.. code-block:: xml
778780
779781
<access-control>
780-
<rule path="^/_internal" role="IS_AUTHENTICATED_ANONYMOUSLY" ip="127.0.0.1" />
782+
<rule path="^/esi" role="IS_AUTHENTICATED_ANONYMOUSLY" ip="127.0.0.1" />
781783
</access-control>
782784
783785
.. code-block:: php
784786
785787
'access_control' => array(
786-
array('path' => '^/_internal', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY', 'ip' => '127.0.0.1'),
788+
array('path' => '^/esi', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY', 'ip' => '127.0.0.1'),
787789
),
788790
789791
.. _book-security-securing-channel:
790792

793+
.. include:: /book/_security-2012-6431.rst.inc
794+
791795
Securing by Channel
792796
~~~~~~~~~~~~~~~~~~~
793797

book/templating.rst

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -623,8 +623,43 @@ The ``recentList`` template is perfectly straightforward:
623623
(e.g. ``/article/*slug*``). This is a bad practice. In the next section,
624624
you'll learn how to do this correctly.
625625

626-
To include the controller, you'll need to refer to it using the standard string
627-
syntax for controllers (i.e. **bundle**:**controller**:**action**):
626+
Even though this controller will only be used internally, you'll need to
627+
create a route that points to the controller:
628+
629+
.. configuration-block::
630+
631+
.. code-block:: yaml
632+
633+
latest_articles:
634+
pattern: /articles/latest/{max}
635+
defaults: { _controller: AcmeArticleBundle:Article:recentArticles }
636+
637+
.. code-block:: xml
638+
639+
<?xml version="1.0" encoding="UTF-8" ?>
640+
641+
<routes xmlns="http://symfony.com/schema/routing"
642+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
643+
xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
644+
645+
<route id="latest_articles" pattern="/articles/latest/{max}">
646+
<default key="_controller">AcmeArticleBundle:Article:recentArticles</default>
647+
</route>
648+
</routes>
649+
650+
.. code-block:: php
651+
652+
use Symfony\Component\Routing\RouteCollection;
653+
use Symfony\Component\Routing\Route;
654+
655+
$collection = new RouteCollection();
656+
$collection->add('latest_articles', new Route('/articles/latest/{max}', array(
657+
'_controller' => 'AcmeArticleBundle:Article:recentArticles',
658+
)));
659+
660+
return $collection;
661+
662+
To include the controller, you'll need to refer to it using an absolute url:
628663

629664
.. configuration-block::
630665

@@ -634,7 +669,7 @@ syntax for controllers (i.e. **bundle**:**controller**:**action**):
634669

635670
{# ... #}
636671
<div id="sidebar">
637-
{% render "AcmeArticleBundle:Article:recentArticles" with {'max': 3} %}
672+
{% render url('latest_articles', { 'max': 3 }) %}
638673
</div>
639674

640675
.. code-block:: html+php
@@ -643,9 +678,13 @@ syntax for controllers (i.e. **bundle**:**controller**:**action**):
643678

644679
<!-- ... -->
645680
<div id="sidebar">
646-
<?php echo $view['actions']->render('AcmeArticleBundle:Article:recentArticles', array('max' => 3)) ?>
681+
<?php echo $view['actions']->render(
682+
$view['router']->generate('latest_articles', array('max' => 3), true)
683+
) ?>
647684
</div>
648685

686+
.. include:: /book/_security-2012-6431.rst.inc
687+
649688
Whenever you find that you need a variable or a piece of information that
650689
you don't have access to in a template, consider rendering a controller.
651690
Controllers are fast to execute and promote good code organization and reuse.
@@ -664,11 +703,14 @@ Symfony2 uses the standard ``render`` helper to configure ``hinclude`` tags:
664703

665704
.. code-block:: jinja
666705
667-
{% render '...:news' with {}, {'standalone': 'js'} %}
706+
{% render url('...'), {'standalone': 'js'} %}
668707
669708
.. code-block:: php
670709
671-
<?php echo $view['actions']->render('...:news', array(), array('standalone' => 'js')) ?>
710+
<?php echo $view['actions']->render(
711+
$view['router']->generate('...'),
712+
array('standalone' => 'js')
713+
) ?>
672714
673715
.. note::
674716

quick_tour/the_view.rst

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -180,18 +180,57 @@ And what if you want to embed the result of another controller in a template?
180180
That's very useful when working with Ajax, or when the embedded template needs
181181
some variable not available in the main template.
182182

183-
Suppose you've created a ``fancy`` action, and you want to include it inside
184-
the ``index`` template. To do this, use the ``render`` tag:
183+
Suppose you've created a ``fancyAction`` controller method, and you want to "render"
184+
it inside the ``index`` template. First, create a route to your new controller
185+
in one of your application's routing configuration files.
186+
187+
.. configuration-block::
188+
189+
.. code-block:: yaml
190+
191+
# app/config/routing.yml
192+
fancy:
193+
pattern: /included/fancy/{name}/{color}
194+
defaults: { _controller: AcmeDemoBundle:Demo:fancy }
195+
196+
.. code-block:: xml
197+
198+
<!-- app/config/routing.xml -->
199+
<?xml version="1.0" encoding="UTF-8" ?>
200+
<routes xmlns="http://symfony.com/schema/routing"
201+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
202+
xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
203+
204+
<route id="fancy" pattern="/included/fancy/{name}/{color}">
205+
<default key="_controller">AcmeDemoBundle:Demo:fancy</default>
206+
</route>
207+
</routes>
208+
209+
.. code-block:: php
210+
211+
// app/config/routing.php
212+
use Symfony\Component\Routing\RouteCollection;
213+
use Symfony\Component\Routing\Route;
214+
215+
$collection = new RouteCollection();
216+
$collection->add('fancy', new Route('/included/fancy/{name}/{color}', array(
217+
'_controller' => 'AcmeDemoBundle:Demo:fancy',
218+
)));
219+
220+
return $collection;
221+
222+
To include the result (e.g. ``HTML``) of the controller, use the ``render`` tag:
185223

186224
.. code-block:: jinja
187225
188226
{# src/Acme/DemoBundle/Resources/views/Demo/index.html.twig #}
189-
{% render "AcmeDemoBundle:Demo:fancy" with {'name': name, 'color': 'green'} %}
227+
{% render url('fancy', { 'name': name, 'color': 'green'}) %}
228+
229+
.. include:: /book/_security-2012-6431.rst.inc
190230

191-
Here, the ``AcmeDemoBundle:Demo:fancy`` string refers to the ``fancy`` action
192-
of the ``Demo`` controller. The arguments (``name`` and ``color``) act like
193-
simulated request variables (as if the ``fancyAction`` were handling a whole
194-
new request) and are made available to the controller::
231+
The ``render`` tag will execute the ``AcmeDemoBundle:Demo:fancy`` controller
232+
and include its result. For example, your new ``fancyAction`` might look
233+
like this::
195234

196235
// src/Acme/DemoBundle/Controller/DemoController.php
197236

@@ -202,7 +241,10 @@ new request) and are made available to the controller::
202241
// create some object, based on the $color variable
203242
$object = ...;
204243

205-
return $this->render('AcmeDemoBundle:Demo:fancy.html.twig', array('name' => $name, 'object' => $object));
244+
return $this->render('AcmeDemoBundle:Demo:fancy.html.twig', array(
245+
'name' => $name,
246+
'object' => $object
247+
));
206248
}
207249

208250
// ...

reference/twig_reference.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,9 @@ Tags
113113
+---------------------------------------------------+-------------------------------------------------------------------+
114114
| Tag Syntax | Usage |
115115
+===================================================+===================================================================+
116-
| ``{% render 'controller' with {parameters} %}`` | This will render the Response Content for the given controller, |
117-
| | more information in :ref:`templating-embedding-controller`. |
116+
| ``{% render url('route', {parameters}) %}`` | This will render the Response Content for the given controller |
117+
| | that the URL points to. For more information, |
118+
| | see :ref:`templating-embedding-controller`. |
118119
+---------------------------------------------------+-------------------------------------------------------------------+
119120
| ``{% form_theme form 'file' %}`` | This will look inside the given file for overridden form blocks, |
120121
| | more information in :doc:`/cookbook/form/form_customization`. |

0 commit comments

Comments
 (0)