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:
commit
20ced4757e
2 changed files with 56 additions and 4 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue