浏览代码

Evolution #756: Sécuriser les urls playlist

Bastien Sevajol 11 年前
父节点
当前提交
a1f60d87a5

+ 18 - 2
src/Muzich/CoreBundle/Extension/MyTwigExtension.php 查看文件

5
 use Symfony\Bundle\FrameworkBundle\Translation\Translator;
5
 use Symfony\Bundle\FrameworkBundle\Translation\Translator;
6
 use Muzich\CoreBundle\Entity\Event;
6
 use Muzich\CoreBundle\Entity\Event;
7
 use Symfony\Component\Form\FormView;
7
 use Symfony\Component\Form\FormView;
8
+use Symfony\Component\DependencyInjection\Container;
8
 
9
 
9
 class MyTwigExtension extends \Twig_Extension {
10
 class MyTwigExtension extends \Twig_Extension {
10
 
11
 
11
   private $translator;
12
   private $translator;
13
+  private $container;
12
   protected $params = array();
14
   protected $params = array();
13
 
15
 
14
-  public function __construct(Translator $translator, $params)
16
+  public function __construct(Translator $translator, $params, Container $container)
15
   {
17
   {
16
     $this->translator = $translator;
18
     $this->translator = $translator;
17
     $this->params = $params;
19
     $this->params = $params;
20
+    $this->container = $container;
18
   }
21
   }
19
   
22
   
20
   public function getFilters()
23
   public function getFilters()
33
     return array(
36
     return array(
34
       'date_or_relative_date'  => new \Twig_Function_Method($this, 'date_or_relative_date'),
37
       'date_or_relative_date'  => new \Twig_Function_Method($this, 'date_or_relative_date'),
35
       'event_const'            => new \Twig_Function_Method($this, 'event_const'),
38
       'event_const'            => new \Twig_Function_Method($this, 'event_const'),
36
-      'css_list_length_class'  => new \Twig_Function_Method($this, 'getCssLengthClassForList')
39
+      'css_list_length_class'  => new \Twig_Function_Method($this, 'getCssLengthClassForList'),
40
+      'token'                  => new \Twig_Function_Method($this, 'token'),
41
+      'path_token'             => new \Twig_Function_Method($this, 'path_token')
37
     );
42
     );
38
   }
43
   }
39
   
44
   
192
     }
197
     }
193
   }
198
   }
194
   
199
   
200
+  public function token($intention = '')
201
+  {
202
+    return $this->container->get('form.csrf_provider')->generateCsrfToken($intention);
203
+  }
204
+  
205
+  public function path_token($route, $parameters = array(), $intention = '', $absolute = false)
206
+  {
207
+    $parameters = array_merge($parameters, array('token' => $this->token($intention)));
208
+    return $this->container->get('router')->generate($route, $parameters, $absolute);
209
+  }
210
+  
195
   public function form_has_errors(FormView $form)
211
   public function form_has_errors(FormView $form)
196
   {
212
   {
197
     $form_vars = $form->getVars();
213
     $form_vars = $form->getVars();

+ 16 - 8
src/Muzich/CoreBundle/Tests/lib/Security/ContextTestCases.php 查看文件

266
       $this->test->generateUrl('playlists_add_element', array(
266
       $this->test->generateUrl('playlists_add_element', array(
267
         'playlist_id' => $playlist_id,
267
         'playlist_id' => $playlist_id,
268
         'element_id'  => $element_id,
268
         'element_id'  => $element_id,
269
-        '_locale'     => 'fr'
269
+        '_locale'     => 'fr',
270
+        'token'       => $this->test->getToken()
270
       ))
271
       ))
271
     );
272
     );
272
   }
273
   }
293
       'GET',
294
       'GET',
294
       $this->test->generateUrl('playlist_update_order', array(
295
       $this->test->generateUrl('playlist_update_order', array(
295
         'playlist_id' => $playlist_id,
296
         'playlist_id' => $playlist_id,
296
-        '_locale'     => 'fr'
297
+        '_locale'     => 'fr',
298
+        'token'       => $this->test->getToken()
297
       )),
299
       )),
298
       array(
300
       array(
299
         'elements' => $elements_ids
301
         'elements' => $elements_ids
318
       $this->test->generateUrl('playlist_remove_element', array(
320
       $this->test->generateUrl('playlist_remove_element', array(
319
         'playlist_id' => $playlist_id,
321
         'playlist_id' => $playlist_id,
320
         'element_id'  => $element_id,
322
         'element_id'  => $element_id,
321
-        '_locale'     => 'fr'
323
+        '_locale'     => 'fr',
324
+        'token'       => $this->test->getToken()
322
       ))
325
       ))
323
     );
326
     );
324
   }
327
   }
330
       $this->test->generateUrl('playlists_add_element_and_copy', array(
333
       $this->test->generateUrl('playlists_add_element_and_copy', array(
331
         'playlist_id' => $playlist_id,
334
         'playlist_id' => $playlist_id,
332
         'element_id'  => $element_id,
335
         'element_id'  => $element_id,
333
-        '_locale'     => 'fr'
336
+        '_locale'     => 'fr',
337
+        'token'       => $this->test->getToken()
334
       ))
338
       ))
335
     );
339
     );
336
   }
340
   }
385
         $this->test->generateUrl('playlists_add_element_and_copy', array(
389
         $this->test->generateUrl('playlists_add_element_and_copy', array(
386
           'playlist_id' => 0,
390
           'playlist_id' => 0,
387
           'element_id'  => 0,
391
           'element_id'  => 0,
388
-          '_locale'     => 'fr'
392
+          '_locale'     => 'fr',
393
+          'token'       => $this->test->getToken()
389
         ))
394
         ))
390
       ), 
395
       ), 
391
       $success, 
396
       $success, 
410
       'GET', 
415
       'GET', 
411
       $this->test->generateUrl('playlist_delete', array(
416
       $this->test->generateUrl('playlist_delete', array(
412
           'playlist_id' => $playlist_id,
417
           'playlist_id' => $playlist_id,
413
-          '_locale'     => 'fr'
418
+          '_locale'     => 'fr',
419
+          'token'       => $this->test->getToken()
414
         )), 
420
         )), 
415
       array(), 
421
       array(), 
416
       array(), 
422
       array(), 
433
   {
439
   {
434
     $this->test->goToPage($this->test->generateUrl('playlist_unpick', array(
440
     $this->test->goToPage($this->test->generateUrl('playlist_unpick', array(
435
       'playlist_id' => $playlist_id,
441
       'playlist_id' => $playlist_id,
436
-      '_locale'     => 'fr'
442
+      '_locale'     => 'fr',
443
+      'token'       => $this->test->getToken()
437
     )));
444
     )));
438
   }
445
   }
439
   
446
   
453
       'GET',
460
       'GET',
454
       $this->test->generateUrl('playlist_pick', array(
461
       $this->test->generateUrl('playlist_pick', array(
455
         'playlist_id' => $playlist_id,
462
         'playlist_id' => $playlist_id,
456
-        '_locale'     => 'fr'
463
+        '_locale'     => 'fr',
464
+        'token'       => $this->test->getToken()
457
       ))
465
       ))
458
     );
466
     );
459
   }
467
   }

+ 8 - 0
src/Muzich/CoreBundle/lib/Controller.php 查看文件

685
     return $this->createForm(new PlaylistForm(), $this->getPlaylistManager()->getNewPlaylist($this->getUserOrNullIfVisitor()));
685
     return $this->createForm(new PlaylistForm(), $this->getPlaylistManager()->getNewPlaylist($this->getUserOrNullIfVisitor()));
686
   }
686
   }
687
   
687
   
688
+  protected function tokenIsCorrect($intention = '')
689
+  {
690
+    if ($this->getRequest()->get('token') != $this->container->get('form.csrf_provider')->generateCsrfToken($intention))
691
+      return false;
692
+    
693
+    return true;
694
+  }
695
+  
688
 }
696
 }

+ 6 - 0
src/Muzich/CoreBundle/lib/FunctionalTest.php 查看文件

551
   public function jsonResponseIsSuccess($json_response)
551
   public function jsonResponseIsSuccess($json_response)
552
   {
552
   {
553
     $response = json_decode($json_response, true);
553
     $response = json_decode($json_response, true);
554
+    $this->assertFalse(is_null($response));
554
     $this->assertTrue(array_key_exists('status', $response));
555
     $this->assertTrue(array_key_exists('status', $response));
555
     $this->assertEquals('success', $response['status']);
556
     $this->assertEquals('success', $response['status']);
556
   }
557
   }
568
     $this->crawler = new Crawler($response['data']);
569
     $this->crawler = new Crawler($response['data']);
569
   }
570
   }
570
   
571
   
572
+  public function getToken($intention = '')
573
+  {
574
+    return $this->getContainer()->get('form.csrf_provider')->generateCsrfToken($intention);
575
+  }
576
+  
571
 }
577
 }

+ 7 - 7
src/Muzich/PlaylistBundle/Controller/EditController.php 查看文件

16
       return $this->jsonResponseError($uncondition);
16
       return $this->jsonResponseError($uncondition);
17
     
17
     
18
     $playlist_manager = $this->getPlaylistManager();
18
     $playlist_manager = $this->getPlaylistManager();
19
-    if (!($playlist = $playlist_manager->findOwnedPlaylistWithId($playlist_id, $this->getUser())) || !$request->get('elements'))
19
+    if (!$this->tokenIsCorrect() || !($playlist = $playlist_manager->findOwnedPlaylistWithId($playlist_id, $this->getUser())) || !$request->get('elements'))
20
       return $this->jsonNotFoundResponse();
20
       return $this->jsonNotFoundResponse();
21
     
21
     
22
     $playlist_manager->updatePlaylistElementsOrder($playlist, $request->get('elements'));
22
     $playlist_manager->updatePlaylistElementsOrder($playlist, $request->get('elements'));
30
       return $this->jsonResponseError($uncondition);
30
       return $this->jsonResponseError($uncondition);
31
     
31
     
32
     $playlist_manager = $this->getPlaylistManager();
32
     $playlist_manager = $this->getPlaylistManager();
33
-    if (!($playlist = $playlist_manager->findOwnedPlaylistWithId($playlist_id, $this->getUser())))
33
+    if (!$this->tokenIsCorrect() || !($playlist = $playlist_manager->findOwnedPlaylistWithId($playlist_id, $this->getUser())))
34
       return $this->jsonNotFoundResponse();
34
       return $this->jsonNotFoundResponse();
35
     
35
     
36
     $playlist_manager->removePlaylistElementWithId($playlist, $element_id);
36
     $playlist_manager->removePlaylistElementWithId($playlist, $element_id);
44
       return $this->jsonResponseError($uncondition);
44
       return $this->jsonResponseError($uncondition);
45
     
45
     
46
     $playlist_manager = $this->getPlaylistManager();
46
     $playlist_manager = $this->getPlaylistManager();
47
-    if (!($playlist = $playlist_manager->findOwnedPlaylistWithId($playlist_id, $this->getUser()))
47
+    if (!$this->tokenIsCorrect() || !($playlist = $playlist_manager->findOwnedPlaylistWithId($playlist_id, $this->getUser()))
48
         || !($element = $this->getElementWithId($element_id)))
48
         || !($element = $this->getElementWithId($element_id)))
49
       return $this->jsonNotFoundResponse();
49
       return $this->jsonNotFoundResponse();
50
     
50
     
83
     if (($uncondition = $this->userHaveNonConditionToMakeAction(SecurityContext::ACTION_PLAYLIST_COPY)) !== false)
83
     if (($uncondition = $this->userHaveNonConditionToMakeAction(SecurityContext::ACTION_PLAYLIST_COPY)) !== false)
84
       return $this->jsonResponseError($uncondition);
84
       return $this->jsonResponseError($uncondition);
85
     
85
     
86
-    if (!($element = $this->getElementWithId($element_id)))
86
+    if (!$this->tokenIsCorrect() || !($element = $this->getElementWithId($element_id)))
87
       return $this->jsonNotFoundResponse();
87
       return $this->jsonNotFoundResponse();
88
     
88
     
89
     if (!($playlist = $this->getPlaylistManager()->findOneAccessiblePlaylistWithId($playlist_id, $this->getUser())))
89
     if (!($playlist = $this->getPlaylistManager()->findOneAccessiblePlaylistWithId($playlist_id, $this->getUser())))
102
     if (($uncondition = $this->userHaveNonConditionToMakeAction(SecurityContext::ACTION_PLAYLIST_DELETE)) !== false)
102
     if (($uncondition = $this->userHaveNonConditionToMakeAction(SecurityContext::ACTION_PLAYLIST_DELETE)) !== false)
103
       throw $this->createNotFoundException();
103
       throw $this->createNotFoundException();
104
     
104
     
105
-    if (!($playlist = $this->getPlaylistManager()->findOwnedPlaylistWithId($playlist_id, $this->getUser())))
105
+    if (!$this->tokenIsCorrect() || !($playlist = $this->getPlaylistManager()->findOwnedPlaylistWithId($playlist_id, $this->getUser())))
106
       throw $this->createNotFoundException();
106
       throw $this->createNotFoundException();
107
     
107
     
108
     $this->getPlaylistManager()->deletePlaylist($playlist);
108
     $this->getPlaylistManager()->deletePlaylist($playlist);
118
     
118
     
119
     $playlist_manager = $this->getPlaylistManager();
119
     $playlist_manager = $this->getPlaylistManager();
120
     
120
     
121
-    if (!($playlist = $playlist_manager->findPlaylistWithId($playlist_id, $this->getUser())))
121
+    if (!$this->tokenIsCorrect() || !($playlist = $playlist_manager->findPlaylistWithId($playlist_id, $this->getUser())))
122
       throw $this->createNotFoundException();
122
       throw $this->createNotFoundException();
123
     
123
     
124
     $playlist_manager->removePickedPlaylistToUser($this->getUser(), $playlist);
124
     $playlist_manager->removePickedPlaylistToUser($this->getUser(), $playlist);
132
     if (($uncondition = $this->userHaveNonConditionToMakeAction(SecurityContext::ACTION_PLAYLIST_PICK)) !== false)
132
     if (($uncondition = $this->userHaveNonConditionToMakeAction(SecurityContext::ACTION_PLAYLIST_PICK)) !== false)
133
       return $this->jsonResponseError($uncondition);
133
       return $this->jsonResponseError($uncondition);
134
     
134
     
135
-    if (!($playlist = $this->getPlaylistManager()->findOneAccessiblePlaylistWithId($playlist_id)))
135
+    if (!$this->tokenIsCorrect() || !($playlist = $this->getPlaylistManager()->findOneAccessiblePlaylistWithId($playlist_id)))
136
       return $this->jsonNotFoundResponse();
136
       return $this->jsonNotFoundResponse();
137
     
137
     
138
     $this->getPlaylistManager()->addPickedPlaylistToUser($this->getUser(), $playlist);
138
     $this->getPlaylistManager()->addPickedPlaylistToUser($this->getUser(), $playlist);

+ 7 - 7
src/Muzich/PlaylistBundle/Resources/config/routing.yml 查看文件

7
   defaults: { _controller: MuzichPlaylistBundle:Show:show }
7
   defaults: { _controller: MuzichPlaylistBundle:Show:show }
8
 
8
 
9
 playlist_delete:
9
 playlist_delete:
10
-  pattern: /playlist/delete/{playlist_id}
10
+  pattern: /playlist/delete/{playlist_id}/{token}
11
   defaults: { _controller: MuzichPlaylistBundle:Edit:delete }
11
   defaults: { _controller: MuzichPlaylistBundle:Edit:delete }
12
 
12
 
13
 playlist_unpick:
13
 playlist_unpick:
14
-  pattern: /playlist/unpick/{playlist_id}
14
+  pattern: /playlist/unpick/{playlist_id}/{token}
15
   defaults: { _controller: MuzichPlaylistBundle:Edit:unpick }
15
   defaults: { _controller: MuzichPlaylistBundle:Edit:unpick }
16
 
16
 
17
 playlist_pick:
17
 playlist_pick:
18
-  pattern: /playlist/pick/{playlist_id}
18
+  pattern: /playlist/pick/{playlist_id}/{token}
19
   defaults: { _controller: MuzichPlaylistBundle:Edit:pick }
19
   defaults: { _controller: MuzichPlaylistBundle:Edit:pick }
20
 
20
 
21
 playlist_datas_for_autoplay:
21
 playlist_datas_for_autoplay:
23
   defaults: { _controller: MuzichPlaylistBundle:Show:getAutoplayData, offset: null }
23
   defaults: { _controller: MuzichPlaylistBundle:Show:getAutoplayData, offset: null }
24
 
24
 
25
 playlist_update_order:
25
 playlist_update_order:
26
-  pattern: /ajax/playlist/order/update/{playlist_id}
26
+  pattern: /ajax/playlist/order/update/{playlist_id}/{token}
27
   defaults: { _controller: MuzichPlaylistBundle:Edit:updateOrder }
27
   defaults: { _controller: MuzichPlaylistBundle:Edit:updateOrder }
28
 
28
 
29
 playlist_remove_element:
29
 playlist_remove_element:
30
-  pattern: /ajax/playlist/element/remove/{playlist_id}/{element_id}
30
+  pattern: /ajax/playlist/element/remove/{playlist_id}/{element_id}/{token}
31
   defaults: { _controller: MuzichPlaylistBundle:Edit:removeElement }
31
   defaults: { _controller: MuzichPlaylistBundle:Edit:removeElement }
32
 
32
 
33
 playlists_add_element_prompt:
33
 playlists_add_element_prompt:
35
   defaults: { _controller: MuzichPlaylistBundle:Show:getAddElementPrompt }
35
   defaults: { _controller: MuzichPlaylistBundle:Show:getAddElementPrompt }
36
 
36
 
37
 playlists_add_element:
37
 playlists_add_element:
38
-  pattern: /ajax/playlist/element/add/{playlist_id}/{element_id}
38
+  pattern: /ajax/playlist/element/add/{playlist_id}/{element_id}/{token}
39
   defaults: { _controller: MuzichPlaylistBundle:Edit:addElement }
39
   defaults: { _controller: MuzichPlaylistBundle:Edit:addElement }
40
   
40
   
41
 playlists_add_element_and_copy:
41
 playlists_add_element_and_copy:
42
-  pattern: /ajax/playlist/element/add-and-copy/{playlist_id}/{element_id}
42
+  pattern: /ajax/playlist/element/add-and-copy/{playlist_id}/{element_id}/{token}
43
   defaults: { _controller: MuzichPlaylistBundle:Edit:addElementAndCopy }
43
   defaults: { _controller: MuzichPlaylistBundle:Edit:addElementAndCopy }
44
 
44
 
45
 playlist_add_element_and_create:
45
 playlist_add_element_and_create:

+ 2 - 2
src/Muzich/PlaylistBundle/Resources/views/Show/prompt.html.twig 查看文件

12
         <li class="playlist">
12
         <li class="playlist">
13
           <a class="add_element_to_playlist"
13
           <a class="add_element_to_playlist"
14
             {% if playlist.owned(app.user) %}
14
             {% if playlist.owned(app.user) %}
15
-              href="{{ path('playlists_add_element', {
15
+              href="{{ path_token('playlists_add_element', {
16
                 'playlist_id' : playlist.id,
16
                 'playlist_id' : playlist.id,
17
                 'element_id'  : element_id
17
                 'element_id'  : element_id
18
               }) }}"
18
               }) }}"
19
             {% else %}
19
             {% else %}
20
-              href="{{ path('playlists_add_element_and_copy', {
20
+              href="{{ path_token('playlists_add_element_and_copy', {
21
                 'playlist_id' : playlist.id,
21
                 'playlist_id' : playlist.id,
22
                 'element_id'  : element_id
22
                 'element_id'  : element_id
23
               }) }}"
23
               }) }}"

+ 4 - 4
src/Muzich/PlaylistBundle/Resources/views/Show/show.html.twig 查看文件

14
     {% if app.user %}
14
     {% if app.user %}
15
       {% if not playlist.owned(app.user) and viewed_user.id != app.user.id %}
15
       {% if not playlist.owned(app.user) and viewed_user.id != app.user.id %}
16
         {% if not app.user.havePlaylistPicked(playlist) %}
16
         {% if not app.user.havePlaylistPicked(playlist) %}
17
-          <a class="playlist_pick" href="{{ path('playlist_pick', { 'playlist_id' : playlist.id }) }}" >
17
+          <a class="playlist_pick" href="{{ path_token('playlist_pick', { 'playlist_id' : playlist.id }) }}" >
18
             P
18
             P
19
           </a>
19
           </a>
20
         {% else %}
20
         {% else %}
21
-          <a class="playlist_unpick" href="{{ path('playlist_unpick', { 'playlist_id' : playlist.id }) }}" >
21
+          <a class="playlist_unpick" href="{{ path_token('playlist_unpick', { 'playlist_id' : playlist.id }) }}" >
22
             uP
22
             uP
23
           </a>
23
           </a>
24
         {% endif %}
24
         {% endif %}
32
     } %}
32
     } %}
33
     
33
     
34
     {% if playlist.elements|length %}
34
     {% if playlist.elements|length %}
35
-      <form action="{{ path('playlist_update_order', { 'playlist_id' : playlist.id }) }}" method="post">
35
+      <form action="{{ path_token('playlist_update_order', { 'playlist_id' : playlist.id }) }}" method="post">
36
         <ul class="playlist_elements">
36
         <ul class="playlist_elements">
37
           {% for element in playlist.elements %}
37
           {% for element in playlist.elements %}
38
             <li class="playlist_element">
38
             <li class="playlist_element">
43
               <a class="open_element" href="{{ path('element_get_one', { 'element_id' : element.id }) }}" data-id="{{ element.id }}">
43
               <a class="open_element" href="{{ path('element_get_one', { 'element_id' : element.id }) }}" data-id="{{ element.id }}">
44
                 {{ element.name }}
44
                 {{ element.name }}
45
               </a>
45
               </a>
46
-              <a class="remove_element" href="{{ path('playlist_remove_element', { 'playlist_id' : playlist.id, 'element_id' : element.id }) }}">
46
+              <a class="remove_element" href="{{ path_token('playlist_remove_element', { 'playlist_id' : playlist.id, 'element_id' : element.id }) }}">
47
                 X
47
                 X
48
               </a>
48
               </a>
49
             </li>
49
             </li>

+ 4 - 4
src/Muzich/PlaylistBundle/Resources/views/Show/user.html.twig 查看文件

21
         {% if app.user %}
21
         {% if app.user %}
22
           {% if viewed_user.id == app.user.id %}
22
           {% if viewed_user.id == app.user.id %}
23
             {% if playlist.owned(app.user) %}
23
             {% if playlist.owned(app.user) %}
24
-              <a class="playlist_delete" href="{{ path('playlist_delete', { 'playlist_id' : playlist.id }) }}" >
24
+              <a class="playlist_delete" href="{{ path_token('playlist_delete', { 'playlist_id' : playlist.id }) }}" >
25
                 X
25
                 X
26
               </a>
26
               </a>
27
             {% else %}
27
             {% else %}
28
-              <a class="playlist_unpick" href="{{ path('playlist_unpick', { 'playlist_id' : playlist.id }) }}" >
28
+              <a class="playlist_unpick" href="{{ path_token('playlist_unpick', { 'playlist_id' : playlist.id }) }}" >
29
                 X
29
                 X
30
               </a>
30
               </a>
31
             {% endif %}
31
             {% endif %}
35
         {% if app.user %}
35
         {% if app.user %}
36
           {% if not playlist.owned(app.user) and viewed_user.id != app.user.id %}
36
           {% if not playlist.owned(app.user) and viewed_user.id != app.user.id %}
37
             {% if not app.user.havePlaylistPicked(playlist) %}
37
             {% if not app.user.havePlaylistPicked(playlist) %}
38
-              <a class="playlist_pick" href="{{ path('playlist_pick', { 'playlist_id' : playlist.id }) }}" >
38
+              <a class="playlist_pick" href="{{ path_token('playlist_pick', { 'playlist_id' : playlist.id }) }}" >
39
                 P
39
                 P
40
               </a>
40
               </a>
41
             {% else %}
41
             {% else %}
42
-              <a class="playlist_unpick" href="{{ path('playlist_unpick', { 'playlist_id' : playlist.id }) }}" >
42
+              <a class="playlist_unpick" href="{{ path_token('playlist_unpick', { 'playlist_id' : playlist.id }) }}" >
43
                 uP
43
                 uP
44
               </a>
44
               </a>
45
             {% endif %}
45
             {% endif %}