Merge pull request #5326 from lest/patch-2

configure how unverified request will be handled
This commit is contained in:
Michael Koziarski 2012-03-10 16:16:35 -08:00
commit 411a826583
4 changed files with 37 additions and 9 deletions

View File

@ -37,6 +37,10 @@ module ActionController #:nodoc:
config_accessor :request_forgery_protection_token
self.request_forgery_protection_token ||= :authenticity_token
# Controls how unverified request will be handled
config_accessor :request_forgery_protection_method
self.request_forgery_protection_method ||= :reset_session
# Controls whether request forgery protection is turned on or not. Turned off by default only in test mode.
config_accessor :allow_forgery_protection
self.allow_forgery_protection = true if allow_forgery_protection.nil?
@ -64,8 +68,10 @@ module ActionController #:nodoc:
# Valid Options:
#
# * <tt>:only/:except</tt> - Passed to the <tt>before_filter</tt> call. Set which actions are verified.
# * <tt>:with</tt> - Set the method to handle unverified request. Valid values: <tt>:exception</tt> and <tt>:reset_session</tt> (default).
def protect_from_forgery(options = {})
self.request_forgery_protection_token ||= :authenticity_token
self.request_forgery_protection_method = options.delete(:with) if options.key?(:with)
prepend_before_filter :verify_authenticity_token, options
end
end
@ -80,9 +86,19 @@ module ActionController #:nodoc:
end
# This is the method that defines the application behavior when a request is found to be unverified.
# By default, \Rails resets the session when it finds an unverified request.
# By default, \Rails uses <tt>request_forgery_protection_method</tt> when it finds an unverified request:
#
# * <tt>:reset_session</tt> - Resets the session.
# * <tt>:exception</tt>: - Raises ActionController::InvalidAuthenticityToken exception.
def handle_unverified_request
reset_session
case request_forgery_protection_method
when :exception
raise ActionController::InvalidAuthenticityToken
when :reset_session
reset_session
else
raise ArgumentError, 'Invalid request forgery protection method, use :exception or :reset_session'
end
end
# Returns true or false if a request is verified. Checks:

View File

@ -43,7 +43,7 @@ class RequestForgeryProtectionController < ActionController::Base
protect_from_forgery :only => %w(index meta)
end
class RequestForgeryProtectionControllerUsingOldBehaviour < ActionController::Base
class RequestForgeryProtectionControllerUsingException < ActionController::Base
include RequestForgeryProtectionActions
protect_from_forgery :only => %w(index meta)
@ -215,7 +215,7 @@ class RequestForgeryProtectionControllerTest < ActionController::TestCase
end
end
class RequestForgeryProtectionControllerUsingOldBehaviourTest < ActionController::TestCase
class RequestForgeryProtectionControllerUsingExceptionTest < ActionController::TestCase
include RequestForgeryProtectionTests
def assert_blocked
assert_raises(ActionController::InvalidAuthenticityToken) do

View File

@ -1,3 +1,5 @@
class ApplicationController < ActionController::Base
protect_from_forgery
# prevent CSRF attacks by raising an exception,
# if your application has an API, you'll probably need to use :reset_session
protect_from_forgery :with => :exception
end

View File

@ -275,19 +275,23 @@ module ApplicationTests
require "#{app_path}/config/environment"
token = "cf50faa3fe97702ca1ae"
PostsController.any_instance.stubs(:form_authenticity_token).returns(token)
params = {:authenticity_token => token}
get "/posts/1"
assert_match /patch/, last_response.body
patch "/posts/1"
patch "/posts/1", params
assert_match /update/, last_response.body
patch "/posts/1"
patch "/posts/1", params
assert_equal 200, last_response.status
put "/posts/1"
put "/posts/1", params
assert_match /update/, last_response.body
put "/posts/1"
put "/posts/1", params
assert_equal 200, last_response.status
end
@ -528,6 +532,12 @@ module ApplicationTests
end
RUBY
app_file 'app/controllers/application_controller.rb', <<-RUBY
class ApplicationController < ActionController::Base
protect_from_forgery :with => :reset_session # as we are testing API here
end
RUBY
app_file 'app/controllers/posts_controller.rb', <<-RUBY
class PostsController < ApplicationController
def create