f8a1e0500d
As a fallback for Rails's token-based mechanism. To use Sec-Fetch-Site exclusively, we'll wait until Rails offers that (when we upstream this).
113 lines
3.3 KiB
Ruby
113 lines
3.3 KiB
Ruby
require "test_helper"
|
|
|
|
class RequestForgeryProtectionTest < ActionDispatch::IntegrationTest
|
|
setup do
|
|
sign_in_as :kevin
|
|
|
|
@original_allow_forgery_protection = ActionController::Base.allow_forgery_protection
|
|
ActionController::Base.allow_forgery_protection = true
|
|
end
|
|
|
|
teardown do
|
|
ActionController::Base.allow_forgery_protection = @original_allow_forgery_protection
|
|
end
|
|
|
|
test "succeeds when CSRF token is valid" do
|
|
assert_difference -> { Board.count }, +1 do
|
|
post boards_path,
|
|
params: { board: { name: "Test Board" }, authenticity_token: csrf_token },
|
|
headers: { "Sec-Fetch-Site" => "cross-site" }
|
|
end
|
|
|
|
assert_response :redirect
|
|
end
|
|
|
|
test "succeeds with same-origin Sec-Fetch-Site even without CSRF token" do
|
|
assert_difference -> { Board.count }, +1 do
|
|
post boards_path,
|
|
params: { board: { name: "Test Board" } },
|
|
headers: { "Sec-Fetch-Site" => "same-origin" }
|
|
end
|
|
|
|
assert_response :redirect
|
|
end
|
|
|
|
test "succeeds with same-site Sec-Fetch-Site even without CSRF token" do
|
|
assert_difference -> { Board.count }, +1 do
|
|
post boards_path,
|
|
params: { board: { name: "Test Board" } },
|
|
headers: { "Sec-Fetch-Site" => "same-site" }
|
|
end
|
|
|
|
assert_response :redirect
|
|
end
|
|
|
|
test "fails with cross-site Sec-Fetch-Site and no CSRF token" do
|
|
assert_no_difference -> { Board.count } do
|
|
post boards_path,
|
|
params: { board: { name: "Test Board" } },
|
|
headers: { "Sec-Fetch-Site" => "cross-site" }
|
|
end
|
|
|
|
assert_response :unprocessable_entity
|
|
end
|
|
|
|
test "fails with none Sec-Fetch-Site and no CSRF token" do
|
|
assert_no_difference -> { Board.count } do
|
|
post boards_path,
|
|
params: { board: { name: "Test Board" } },
|
|
headers: { "Sec-Fetch-Site" => "none" }
|
|
end
|
|
|
|
assert_response :unprocessable_entity
|
|
end
|
|
|
|
test "fails when Sec-Fetch-Site header is missing and no CSRF token" do
|
|
assert_no_difference -> { Board.count } do
|
|
post boards_path, params: { board: { name: "Test Board" } }
|
|
end
|
|
|
|
assert_response :unprocessable_entity
|
|
end
|
|
|
|
test "fails with invalid CSRF token and cross-site Sec-Fetch-Site" do
|
|
assert_no_difference -> { Board.count } do
|
|
post boards_path,
|
|
params: { board: { name: "Test Board" }, authenticity_token: "invalid-token" },
|
|
headers: { "Sec-Fetch-Site" => "cross-site" }
|
|
end
|
|
|
|
assert_response :unprocessable_entity
|
|
end
|
|
|
|
test "GET requests succeed regardless of Sec-Fetch-Site header" do
|
|
get board_path(boards(:writebook)), headers: { "Sec-Fetch-Site" => "cross-site" }
|
|
|
|
assert_response :success
|
|
end
|
|
|
|
test "appends Sec-Fetch-Site to Vary header on GET requests" do
|
|
get board_path(boards(:writebook))
|
|
|
|
assert_response :success
|
|
assert_includes response.headers["Vary"], "Sec-Fetch-Site"
|
|
end
|
|
|
|
test "appends Sec-Fetch-Site to Vary header on POST requests" do
|
|
post boards_path,
|
|
params: { board: { name: "Test Board" } },
|
|
headers: { "Sec-Fetch-Site" => "same-origin" }
|
|
|
|
assert_response :redirect
|
|
assert_includes response.headers["Vary"], "Sec-Fetch-Site"
|
|
end
|
|
|
|
private
|
|
def csrf_token
|
|
@csrf_token ||= begin
|
|
get new_board_path
|
|
response.body[/name="authenticity_token" value="([^"]+)"/, 1]
|
|
end
|
|
end
|
|
end
|