Skip to content
This repository
Browse code

Protect button_to behind protect_from_forgery (closes #9675) [lifo]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@7636 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
commit 82c1fed89fe6dae8f44b6647dd94fc68f01eaa81 1 parent 106b236
David Heinemeier Hansson authored September 25, 2007
9  actionpack/lib/action_view/helpers/url_helper.rb
@@ -201,7 +201,12 @@ def button_to(name, options = {}, html_options = {})
201 201
         end
202 202
 
203 203
         form_method = method.to_s == 'get' ? 'get' : 'post'
204  
-
  204
+        
  205
+        request_token_tag = ''
  206
+        if form_method == 'post' && request_forgery_protection_token
  207
+          request_token_tag = tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token)
  208
+        end
  209
+        
205 210
         if confirm = html_options.delete("confirm")
206 211
           html_options["onclick"] = "return #{confirm_javascript_function(confirm)};"
207 212
         end
@@ -212,7 +217,7 @@ def button_to(name, options = {}, html_options = {})
212 217
         html_options.merge!("type" => "submit", "value" => name)
213 218
 
214 219
         "<form method=\"#{form_method}\" action=\"#{escape_once url}\" class=\"button-to\"><div>" +
215  
-          method_tag + tag("input", html_options) + "</div></form>"
  220
+          method_tag + tag("input", html_options) + request_token_tag + "</div></form>"
216 221
       end
217 222
 
218 223
 
144  actionpack/test/controller/request_forgery_protection_test.rb
@@ -4,42 +4,21 @@
4 4
   map.connect ':controller/:action/:id'
5 5
 end
6 6
 
7  
-class RequestForgeryProtectionController < ActionController::Base
8  
-  protect_from_forgery :only => :index, :secret => 'abc'
9  
-
10  
-  def index
11  
-    render :inline => "<%= form_tag('/') {} %>"
12  
-  end
13  
-  
14  
-  def unsafe
15  
-    render :text => 'pwn'
16  
-  end
17  
-  
18  
-  def rescue_action(e) raise e end
19  
-end
20  
-
21  
-class RequestForgeryProtectionControllerTest < Test::Unit::TestCase
22  
-  def setup
23  
-    @controller = RequestForgeryProtectionController.new
24  
-    @request    = ActionController::TestRequest.new
25  
-    @response   = ActionController::TestResponse.new
26  
-    class << @request.session
27  
-      def session_id() '123' end
28  
-    end
29  
-    @token = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('SHA1'), 'abc', '123')
30  
-    ActionController::Base.request_forgery_protection_token = :authenticity_token
31  
-  end
32  
-  
  7
+module RequestForgeryProtectionTests
33 8
   def teardown
34 9
     ActionController::Base.request_forgery_protection_token = nil
35 10
   end
36  
-
  11
+  
37 12
   def test_should_render_form_with_token_tag
38 13
     get :index
39 14
     assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
40 15
   end
  16
+  
  17
+  def test_should_render_button_to_with_token_tag
  18
+    get :show_button
  19
+    assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
  20
+  end
41 21
 
42  
-  # Replace this with your real tests.
43 22
   def test_should_allow_get
44 23
     get :index
45 24
     assert_response :success
@@ -105,14 +84,15 @@ def test_should_allow_delete_with_xml
105 84
   end
106 85
 end
107 86
 
108  
-# no token is given, assume the cookie store is used
109  
-class CsrfCookieMonsterController < ActionController::Base
110  
-  protect_from_forgery :only => :index
111  
-
  87
+module RequestForgeryProtectionActions
112 88
   def index
113 89
     render :inline => "<%= form_tag('/') {} %>"
114 90
   end
115 91
   
  92
+  def show_button
  93
+    render :inline => "<%= button_to('New', '/') {} %>"
  94
+  end
  95
+  
116 96
   def unsafe
117 97
     render :text => 'pwn'
118 98
   end
@@ -120,6 +100,31 @@ def unsafe
120 100
   def rescue_action(e) raise e end
121 101
 end
122 102
 
  103
+class RequestForgeryProtectionController < ActionController::Base
  104
+  include RequestForgeryProtectionActions
  105
+  protect_from_forgery :only => :index, :secret => 'abc'
  106
+end
  107
+
  108
+class RequestForgeryProtectionControllerTest < Test::Unit::TestCase
  109
+  include RequestForgeryProtectionTests
  110
+  def setup
  111
+    @controller = RequestForgeryProtectionController.new
  112
+    @request    = ActionController::TestRequest.new
  113
+    @response   = ActionController::TestResponse.new
  114
+    class << @request.session
  115
+      def session_id() '123' end
  116
+    end
  117
+    @token = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('SHA1'), 'abc', '123')
  118
+    ActionController::Base.request_forgery_protection_token = :authenticity_token
  119
+  end
  120
+end
  121
+
  122
+# no token is given, assume the cookie store is used
  123
+class CsrfCookieMonsterController < ActionController::Base
  124
+  include RequestForgeryProtectionActions
  125
+  protect_from_forgery :only => :index
  126
+end
  127
+
123 128
 class FakeSessionDbMan
124 129
   def self.generate_digest(data)
125 130
     Digest::SHA1.hexdigest("secure")
@@ -127,6 +132,7 @@ def self.generate_digest(data)
127 132
 end
128 133
 
129 134
 class CsrfCookieMonsterControllerTest < Test::Unit::TestCase
  135
+  include RequestForgeryProtectionTests
130 136
   def setup
131 137
     @controller = CsrfCookieMonsterController.new
132 138
     @request    = ActionController::TestRequest.new
@@ -139,79 +145,5 @@ class << @request.session
139 145
     @token = Digest::SHA1.hexdigest("secure")
140 146
     ActionController::Base.request_forgery_protection_token = :authenticity_token
141 147
   end
142  
-  
143  
-  def teardown
144  
-    ActionController::Base.request_forgery_protection_token = nil
145  
-  end
146  
-
147  
-  def test_should_render_form_with_token_tag
148  
-    get :index
149  
-    assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
150  
-  end
151  
-
152  
-  # Replace this with your real tests.
153  
-  def test_should_allow_get
154  
-    get :index
155  
-    assert_response :success
156  
-  end
157  
-  
158  
-  def test_should_allow_post_without_token_on_unsafe_action
159  
-    post :unsafe
160  
-    assert_response :success
161  
-  end
162  
-  
163  
-  def test_should_not_allow_post_without_token
164  
-    assert_raises(ActionController::InvalidAuthenticityToken) { post :index }
165  
-  end
166  
-  
167  
-  def test_should_not_allow_put_without_token
168  
-    assert_raises(ActionController::InvalidAuthenticityToken) { put :index }
169  
-  end
170  
-  
171  
-  def test_should_not_allow_delete_without_token
172  
-    assert_raises(ActionController::InvalidAuthenticityToken) { delete :index }
173  
-  end
174  
-  
175  
-  def test_should_not_allow_xhr_post_without_token
176  
-    assert_raises(ActionController::InvalidAuthenticityToken) { xhr :post, :index }
177  
-  end
178  
-  
179  
-  def test_should_not_allow_xhr_put_without_token
180  
-    assert_raises(ActionController::InvalidAuthenticityToken) { xhr :put, :index }
181  
-  end
182  
-  
183  
-  def test_should_not_allow_xhr_delete_without_token
184  
-    assert_raises(ActionController::InvalidAuthenticityToken) { xhr :delete, :index }
185  
-  end
186  
-  
187  
-  def test_should_allow_post_with_token
188  
-    post :index, :authenticity_token => @token
189  
-    assert_response :success
190  
-  end
191  
-  
192  
-  def test_should_allow_put_with_token
193  
-    put :index, :authenticity_token => @token
194  
-    assert_response :success
195  
-  end
196  
-  
197  
-  def test_should_allow_delete_with_token
198  
-    delete :index, :authenticity_token => @token
199  
-    assert_response :success
200  
-  end
201  
-  
202  
-  def test_should_allow_post_with_xml
203  
-    post :index, :format => 'xml'
204  
-    assert_response :success
205  
-  end
206  
-  
207  
-  def test_should_allow_put_with_xml
208  
-    put :index, :format => 'xml'
209  
-    assert_response :success
210  
-  end
211  
-  
212  
-  def test_should_allow_delete_with_xml
213  
-    delete :index, :format => 'xml'
214  
-    assert_response :success
215  
-  end
216 148
 end
217 149
 

0 notes on commit 82c1fed

Please sign in to comment.
Something went wrong with that request. Please try again.