From 5edc81dcc2e13bdce3da01745b0d1af654342aad Mon Sep 17 00:00:00 2001 From: Rick Olson Date: Fri, 28 Sep 2007 15:55:45 +0000 Subject: Allow ability to disable request forgery protection, disable it in test mode by default. Closes #9693 [lifofifo] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@7668 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- actionpack/CHANGELOG | 2 ++ actionpack/lib/action_controller/base.rb | 5 ++- .../request_forgery_protection.rb | 14 ++++++-- .../lib/action_view/helpers/form_tag_helper.rb | 4 +-- .../lib/action_view/helpers/prototype_helper.rb | 2 +- actionpack/lib/action_view/helpers/url_helper.rb | 4 +-- .../controller/request_forgery_protection_test.rb | 38 ++++++++++++++++++++++ actionpack/test/template/form_helper_test.rb | 6 ++-- actionpack/test/template/form_tag_helper_test.rb | 7 ++-- actionpack/test/template/prototype_helper_test.rb | 4 +++ .../test/template/scriptaculous_helper_test.rb | 6 ++-- actionpack/test/template/url_helper_test.rb | 4 +-- 12 files changed, 75 insertions(+), 21 deletions(-) (limited to 'actionpack') diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 0d3cc564c4..13db84720c 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Allow ability to disable request forgery protection, disable it in test mode by default. Closes #9693 [lifofifo] + * Avoid calling is_missing on LoadErrors. Closes #7460. [ntalbott] * Move Railties' Dispatcher to ActionController::Dispatcher, introduce before_ and after_dispatch callbacks, and warm up to non-CGI requests. [Jeremy Kemper] diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index fd7e9e5244..9ac728e96a 100755 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -328,8 +328,11 @@ module ActionController #:nodoc: cattr_accessor :resource_action_separator # Sets the token parameter name for RequestForgery. Calling #protect_from_forgery sets it to :authenticity_token by default - @@request_forgery_protection_token = nil cattr_accessor :request_forgery_protection_token + + # Controls whether request forgergy protection is turned on or not. Turned off by default only in test mode. + class_inheritable_accessor :allow_forgery_protection + self.allow_forgery_protection = true # Holds the request object that's primarily used to get environment variables through access like # request.env["REQUEST_URI"]. diff --git a/actionpack/lib/action_controller/request_forgery_protection.rb b/actionpack/lib/action_controller/request_forgery_protection.rb index 803782113d..3a7eb789c4 100644 --- a/actionpack/lib/action_controller/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/request_forgery_protection.rb @@ -8,6 +8,7 @@ module ActionController #:nodoc: class_inheritable_accessor :request_forgery_protection_options self.request_forgery_protection_options = {} helper_method :form_authenticity_token + helper_method :protect_against_forgery? end base.extend(ClassMethods) end @@ -48,6 +49,9 @@ module ActionController #:nodoc: # # # uses one of the other session stores that uses a session_id value. # protect_from_forgery :secret => 'my-little-pony', :except => :index + # + # # you can disable csrf protection on controller-by-controller basis: + # skip_before_filter :verify_authenticity_token # end # # Valid Options: @@ -75,9 +79,9 @@ module ActionController #:nodoc: # * is it a GET request? Gets should be safe and idempotent # * Does the form_authenticity_token match the given _token value from the params? def verified_request? - request_forgery_protection_token.nil? || - request.method == :get || - !verifiable_request_format? || + !protect_against_forgery? || + request.method == :get || + !verifiable_request_format? || form_authenticity_token == params[request_forgery_protection_token] end @@ -110,5 +114,9 @@ module ActionController #:nodoc: session[:csrf_id] ||= CGI::Session.generate_unique_id session.dbman.generate_digest(session[:csrf_id]) end + + def protect_against_forgery? + allow_forgery_protection && request_forgery_protection_token + end end end \ No newline at end of file diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index db74df26bf..fdc0d10c6c 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -401,7 +401,7 @@ module ActionView '' when /^post$/i, "", nil html_options["method"] = "post" - request_forgery_protection_token ? content_tag(:div, token_tag, :style => 'margin:0;padding:0') : '' + protect_against_forgery? ? content_tag(:div, token_tag, :style => 'margin:0;padding:0') : '' else html_options["method"] = "post" content_tag(:div, tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag, :style => 'margin:0;padding:0') @@ -421,7 +421,7 @@ module ActionView end def token_tag - if request_forgery_protection_token.nil? + unless protect_against_forgery? '' else tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token) diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index def33b9ee1..7dcc92a674 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -739,7 +739,7 @@ module ActionView js_options['parameters'] = options[:with] end - if request_forgery_protection_token + if protect_against_forgery? if js_options['parameters'] js_options['parameters'] << " + '&" else diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 490b2c1215..70d3ddd403 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -203,7 +203,7 @@ module ActionView form_method = method.to_s == 'get' ? 'get' : 'post' request_token_tag = '' - if form_method == 'post' && request_forgery_protection_token + if form_method == 'post' && protect_against_forgery? request_token_tag = tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token) end @@ -477,7 +477,7 @@ module ActionView submit_function << "m.setAttribute('name', '_method'); m.setAttribute('value', '#{method}'); f.appendChild(m);" end - if request_forgery_protection_token + if protect_against_forgery? submit_function << "var s = document.createElement('input'); s.setAttribute('type', 'hidden'); " submit_function << "s.setAttribute('name', '#{request_forgery_protection_token}'); s.setAttribute('value', '#{escape_javascript form_authenticity_token}'); f.appendChild(s);" end diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb index a9b674405d..0711ecf90c 100644 --- a/actionpack/test/controller/request_forgery_protection_test.rb +++ b/actionpack/test/controller/request_forgery_protection_test.rb @@ -125,6 +125,18 @@ class CsrfCookieMonsterController < ActionController::Base protect_from_forgery :only => :index end +class FreeCookieController < CsrfCookieMonsterController + self.allow_forgery_protection = false + + def index + render :inline => "<%= form_tag('/') {} %>" + end + + def show_button + render :inline => "<%= button_to('New', '/') {} %>" + end +end + class FakeSessionDbMan def self.generate_digest(data) Digest::SHA1.hexdigest("secure") @@ -147,3 +159,29 @@ class CsrfCookieMonsterControllerTest < Test::Unit::TestCase end end +class FreeCookieControllerTest < Test::Unit::TestCase + + def setup + @controller = FreeCookieController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + @token = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('SHA1'), 'abc', '123') + 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 + +end diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 9b22d4cef3..1c842fc307 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -711,8 +711,8 @@ class FormHelperTest < Test::Unit::TestCase def post_path(post) "/posts/#{post.id}" end - - def request_forgery_protection_token - nil + + def protect_against_forgery? + false end end diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index f2c6678ddd..ebf8f7058f 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -177,9 +177,8 @@ class FormTagHelperTest < Test::Unit::TestCase expected = %(
Hello world!
) assert_dom_equal expected, _erbout end - - def request_forgery_protection_token - nil - + + def protect_against_forgery? + false end end diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb index 48f947910f..3df1502f12 100644 --- a/actionpack/test/template/prototype_helper_test.rb +++ b/actionpack/test/template/prototype_helper_test.rb @@ -65,6 +65,10 @@ protected nil end + def protect_against_forgery? + false + end + def create_generator block = Proc.new { |*args| yield *args if block_given? } JavaScriptGenerator.new self, &block diff --git a/actionpack/test/template/scriptaculous_helper_test.rb b/actionpack/test/template/scriptaculous_helper_test.rb index 722839f15e..04fbe33d5d 100644 --- a/actionpack/test/template/scriptaculous_helper_test.rb +++ b/actionpack/test/template/scriptaculous_helper_test.rb @@ -89,8 +89,8 @@ class ScriptaculousHelperTest < Test::Unit::TestCase assert_dom_equal %(), drop_receiving_element("droptarget1", :accept => ['tshirts','mugs'], :update => 'infobox') end - - def request_forgery_protection_token - nil + + def protect_against_forgery? + false end end diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index 5707beeab1..dc0186f9df 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -268,8 +268,8 @@ class UrlHelperTest < Test::Unit::TestCase assert_dom_equal "", mail_to("me@domain.com", "My email", :encode => "javascript", :replace_at => "(at)", :replace_dot => "(dot)") end - def request_forgery_protection_token - nil + def protect_against_forgery? + false end end -- cgit v1.2.3