1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Merge pull request #43444 from sabulikia/support-custom-csrf-strategy

Add support for custom CSRF strategies.
This commit is contained in:
Rafael Mendonça França 2021-10-14 12:33:52 -04:00 committed by GitHub
commit 20ced4757e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 4 deletions

View file

@ -124,10 +124,26 @@ module ActionController # :nodoc:
# If you need to add verification to the beginning of the callback chain, use <tt>prepend: true</tt>. # If you need to add verification to the beginning of the callback chain, use <tt>prepend: true</tt>.
# * <tt>:with</tt> - Set the method to handle unverified request. # * <tt>:with</tt> - Set the method to handle unverified request.
# #
# Valid unverified request handling methods are: # Built-in unverified request handling methods are:
# * <tt>:exception</tt> - Raises ActionController::InvalidAuthenticityToken exception. # * <tt>:exception</tt> - Raises ActionController::InvalidAuthenticityToken exception.
# * <tt>:reset_session</tt> - Resets the session. # * <tt>:reset_session</tt> - Resets the session.
# * <tt>:null_session</tt> - Provides an empty session during request but doesn't reset it completely. Used as default if <tt>:with</tt> option is not specified. # * <tt>:null_session</tt> - Provides an empty session during request but doesn't reset it completely. Used as default if <tt>:with</tt> option is not specified.
#
# You can also implement custom strategy classes for unverified request handling:
#
# class CustomStrategy
# def initialize(controller)
# @controller = controller
# end
#
# def handle_unverified_request
# # Custom behaviour for unverfied request
# end
# end
#
# class ApplicationController < ActionController:x:Base
# protect_from_forgery with: CustomStrategy
# end
def protect_from_forgery(options = {}) def protect_from_forgery(options = {})
options = options.reverse_merge(prepend: false) options = options.reverse_merge(prepend: false)
@ -148,9 +164,18 @@ module ActionController # :nodoc:
private private
def protection_method_class(name) def protection_method_class(name)
ActionController::RequestForgeryProtection::ProtectionMethods.const_get(name.to_s.classify) return name if name.is_a?(Class)
rescue NameError
raise ArgumentError, "Invalid request forgery protection method, use :null_session, :exception, or :reset_session" case name
when :null_session
ProtectionMethods::NullSession
when :reset_session
ProtectionMethods::ResetSession
when :exception
ProtectionMethods::Exception
else
raise ArgumentError, "Invalid request forgery protection method, use :null_session, :exception, :reset_session, or a custom forgery protection class."
end
end end
end end

View file

@ -103,6 +103,24 @@ class RequestForgeryProtectionControllerUsingNullSession < ActionController::Bas
end end
end end
class RequestForgeryProtectionControllerUsingCustomStrategy < ActionController::Base
include RequestForgeryProtectionActions
class FakeException < Exception; end
class CustomStrategy
def initialize(controller)
@controller = controller
end
def handle_unverified_request
raise FakeException, "Raised a fake exception."
end
end
protect_from_forgery only: %w(index meta same_origin_js negotiate_same_origin), with: CustomStrategy
end
class PrependProtectForgeryBaseController < ActionController::Base class PrependProtectForgeryBaseController < ActionController::Base
before_action :custom_action before_action :custom_action
attr_accessor :called_callbacks attr_accessor :called_callbacks
@ -699,6 +717,7 @@ end
class RequestForgeryProtectionControllerUsingExceptionTest < ActionController::TestCase class RequestForgeryProtectionControllerUsingExceptionTest < ActionController::TestCase
include RequestForgeryProtectionTests include RequestForgeryProtectionTests
def assert_blocked(&block) def assert_blocked(&block)
assert_raises(ActionController::InvalidAuthenticityToken, &block) assert_raises(ActionController::InvalidAuthenticityToken, &block)
end end
@ -720,6 +739,14 @@ class RequestForgeryProtectionControllerUsingExceptionTest < ActionController::T
end end
end end
class RequestForgeryProtectionControllerUsingCustomStrategyTest < ActionController::TestCase
include RequestForgeryProtectionTests
def assert_blocked(&block)
assert_raises(RequestForgeryProtectionControllerUsingCustomStrategy::FakeException, &block)
end
end
class PrependProtectForgeryBaseControllerTest < ActionController::TestCase class PrependProtectForgeryBaseControllerTest < ActionController::TestCase
PrependTrueController = Class.new(PrependProtectForgeryBaseController) do PrependTrueController = Class.new(PrependProtectForgeryBaseController) do
protect_from_forgery prepend: true protect_from_forgery prepend: true