request_forgery_protection_test.rb 7.1 KB
Newer Older
1
require 'abstract_unit'
M
Michael Koziarski 已提交
2
require 'digest/sha1'
3 4 5 6 7

ActionController::Routing::Routes.draw do |map|
  map.connect ':controller/:action/:id'
end

8 9 10 11 12 13 14 15 16 17
# common controller actions
module RequestForgeryProtectionActions
  def index
    render :inline => "<%= form_tag('/') {} %>"
  end
  
  def show_button
    render :inline => "<%= button_to('New', '/') {} %>"
  end
  
18 19 20 21
  def remote_form
    render :inline => "<% form_remote_tag(:url => '/') {} %>"
  end

22 23 24 25 26 27 28 29 30 31 32 33 34
  def unsafe
    render :text => 'pwn'
  end
  
  def rescue_action(e) raise e end
end

# sample controllers
class RequestForgeryProtectionController < ActionController::Base
  include RequestForgeryProtectionActions
  protect_from_forgery :only => :index
end

35
class FreeCookieController < RequestForgeryProtectionController
36 37 38 39 40 41 42 43 44 45 46 47 48
  self.allow_forgery_protection = false
  
  def index
    render :inline => "<%= form_tag('/') {} %>"
  end
  
  def show_button
    render :inline => "<%= button_to('New', '/') {} %>"
  end
end

# common test methods

49
module RequestForgeryProtectionTests
50 51 52
  def teardown
    ActionController::Base.request_forgery_protection_token = nil
  end
53
  
54

55
  def test_should_render_form_with_token_tag
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
     get :index
     assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
   end

   def test_should_render_button_to_with_token_tag
     get :show_button
     assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
   end

   def test_should_render_remote_form_with_only_one_token_parameter
     get :remote_form
     assert_equal 1, @response.body.scan(@token).size
   end

   def test_should_allow_get
     get :index
     assert_response :success
   end

   def test_should_allow_post_without_token_on_unsafe_action
     post :unsafe
     assert_response :success
   end

  def test_should_not_allow_html_post_without_token
    @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
    assert_raises(ActionController::InvalidAuthenticityToken) { post :index, :format => :html }
83
  end
84
  
85 86 87
  def test_should_not_allow_html_put_without_token
    @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
    assert_raises(ActionController::InvalidAuthenticityToken) { put :index, :format => :html }
88 89
  end
  
90 91 92
  def test_should_not_allow_html_delete_without_token
    @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
    assert_raises(ActionController::InvalidAuthenticityToken) { delete :index, :format => :html }
93
  end
94

95 96
  def test_should_allow_api_formatted_post_without_token
    assert_nothing_raised do
97 98 99 100
      post :index, :format => 'xml'
    end
  end

101
  def test_should_not_allow_api_formatted_put_without_token
102
    assert_nothing_raised do
103 104 105 106
      put :index, :format => 'xml'
    end
  end

107 108
  def test_should_allow_api_formatted_delete_without_token
    assert_nothing_raised do
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
      delete :index, :format => 'xml'
    end
  end

  def test_should_not_allow_api_formatted_post_sent_as_url_encoded_form_without_token
    assert_raises(ActionController::InvalidAuthenticityToken) do
      @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
      post :index, :format => 'xml'
    end
  end

  def test_should_not_allow_api_formatted_put_sent_as_url_encoded_form_without_token
    assert_raises(ActionController::InvalidAuthenticityToken) do
      @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
      put :index, :format => 'xml'
    end
  end

  def test_should_not_allow_api_formatted_delete_sent_as_url_encoded_form_without_token
    assert_raises(ActionController::InvalidAuthenticityToken) do
      @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
      delete :index, :format => 'xml'
    end
  end

  def test_should_not_allow_api_formatted_post_sent_as_multipart_form_without_token
    assert_raises(ActionController::InvalidAuthenticityToken) do
      @request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
      post :index, :format => 'xml'
    end
  end

  def test_should_not_allow_api_formatted_put_sent_as_multipart_form_without_token
    assert_raises(ActionController::InvalidAuthenticityToken) do
      @request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
      put :index, :format => 'xml'
    end
  end

  def test_should_not_allow_api_formatted_delete_sent_as_multipart_form_without_token
149
    assert_raises(ActionController::InvalidAuthenticityToken) do
150
      @request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
151 152 153 154
      delete :index, :format => 'xml'
    end
  end

155 156 157 158 159 160
  def test_should_allow_xhr_post_without_token
    assert_nothing_raised { xhr :post, :index }
  end
  def test_should_not_allow_xhr_post_with_html_without_token
    @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
    assert_raise(ActionController::InvalidAuthenticityToken) { xhr :post, :index }
161 162
  end
  
163 164
  def test_should_allow_xhr_put_without_token
    assert_nothing_raised { xhr :put, :index }
165 166
  end
  
167 168
  def test_should_allow_xhr_delete_without_token
    assert_nothing_raised { xhr :delete, :index }
169 170 171
  end
  
  def test_should_allow_post_with_token
172
    post :index, :authenticity_token => @token
173 174 175 176
    assert_response :success
  end
  
  def test_should_allow_put_with_token
177
    put :index, :authenticity_token => @token
178 179 180 181
    assert_response :success
  end
  
  def test_should_allow_delete_with_token
182
    delete :index, :authenticity_token => @token
183 184 185 186
    assert_response :success
  end
  
  def test_should_allow_post_with_xml
187
    @request.env['CONTENT_TYPE'] = Mime::XML.to_s
188 189 190 191 192
    post :index, :format => 'xml'
    assert_response :success
  end
  
  def test_should_allow_put_with_xml
193
    @request.env['CONTENT_TYPE'] = Mime::XML.to_s
194 195 196 197 198
    put :index, :format => 'xml'
    assert_response :success
  end
  
  def test_should_allow_delete_with_xml
199
    @request.env['CONTENT_TYPE'] = Mime::XML.to_s
200 201 202 203 204
    delete :index, :format => 'xml'
    assert_response :success
  end
end

205
# OK let's get our test on
206

207
class RequestForgeryProtectionControllerTest < ActionController::TestCase
208 209 210 211
  include RequestForgeryProtectionTests
  def setup
    @controller = RequestForgeryProtectionController.new
    @request    = ActionController::TestRequest.new
212
    @request.format = :html
213
    @response   = ActionController::TestResponse.new
214
    @token      = "cf50faa3fe97702ca1ae"
215

216
    ActiveSupport::SecureRandom.stubs(:base64).returns(@token)
217
    ActionController::Base.request_forgery_protection_token = :authenticity_token
218 219 220
  end
end

221
class FreeCookieControllerTest < ActionController::TestCase
222 223 224 225
  def setup
    @controller = FreeCookieController.new
    @request    = ActionController::TestRequest.new
    @response   = ActionController::TestResponse.new
226 227 228
    @token      = "cf50faa3fe97702ca1ae"

    ActiveSupport::SecureRandom.stubs(:base64).returns(@token)
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
  end
  
  def test_should_not_render_form_with_token_tag
    get :index
    assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token, false
  end
  
  def test_should_not_render_button_to_with_token_tag
    get :show_button
    assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token, false
  end
  
  def test_should_allow_all_methods_without_token
    [:post, :put, :delete].each do |method|
      assert_nothing_raised { send(method, :index)}
    end
  end
246
end