Allow a proc to be used in addition to a static value for cookies_same_site_protection

Add documentation of Proc usage for SameSite property to configuring.md

Address PR comments

Co-authored-by: Adrianna Chang <adrianna.chang@shopify.com>
This commit is contained in:
Jack McCracken 2020-01-15 16:39:35 -05:00 committed by Adrianna Chang
parent c774da7ebe
commit 7459672fb0
4 changed files with 43 additions and 8 deletions

View File

@ -70,7 +70,7 @@ module ActionDispatch
end
def cookies_same_site_protection
get_header Cookies::COOKIES_SAME_SITE_PROTECTION
get_header(Cookies::COOKIES_SAME_SITE_PROTECTION) || Proc.new { }
end
def cookies_digest
@ -444,7 +444,9 @@ module ActionDispatch
end
options[:path] ||= "/"
options[:same_site] ||= request.cookies_same_site_protection
cookies_same_site_protection = request.cookies_same_site_protection
options[:same_site] ||= cookies_same_site_protection.call(request)
if options[:domain] == :all || options[:domain] == "all"
# If there is a provided tld length then we use it otherwise default domain regexp.

View File

@ -358,20 +358,41 @@ class CookiesTest < ActionController::TestCase
@request.env["action_dispatch.encrypted_signed_cookie_salt"] = ENCRYPTED_SIGNED_COOKIE_SALT
@request.env["action_dispatch.authenticated_encrypted_cookie_salt"] = AUTHENTICATED_ENCRYPTED_COOKIE_SALT
@request.env["action_dispatch.cookies_same_site_protection"] = :lax
@request.env["action_dispatch.cookies_same_site_protection"] = proc { :lax }
@request.host = "www.nextangle.com"
end
def test_setting_cookie_with_no_protection
@request.env["action_dispatch.cookies_same_site_protection"] = :none
@request.env["action_dispatch.cookies_same_site_protection"] = proc { :none }
get :authenticate
assert_cookie_header "user_name=david; path=/; SameSite=None"
assert_equal({ "user_name" => "david" }, @response.cookies)
end
def test_setting_cookie_with_protection_proc_normal_user_agent
@request.env["action_dispatch.cookies_same_site_protection"] = Proc.new do |request|
:strict unless request.user_agent == "spooky browser"
end
get :authenticate
assert_cookie_header "user_name=david; path=/; SameSite=Strict"
assert_equal({ "user_name" => "david" }, @response.cookies)
end
def test_setting_cookie_with_protection_proc_special_user_agent
@request.env["action_dispatch.cookies_same_site_protection"] = Proc.new do |request|
:strict unless request.user_agent == "spooky browser"
end
request.user_agent = "spooky browser"
get :authenticate
assert_cookie_header "user_name=david; path=/"
assert_equal({ "user_name" => "david" }, @response.cookies)
end
def test_setting_cookie_with_misspelled_protection_raises
@request.env["action_dispatch.cookies_same_site_protection"] = :funky
@request.env["action_dispatch.cookies_same_site_protection"] = proc { :funky }
error = assert_raise ArgumentError do
get :authenticate
@ -380,7 +401,7 @@ class CookiesTest < ActionController::TestCase
end
def test_setting_cookie_with_strict
@request.env["action_dispatch.cookies_same_site_protection"] = :strict
@request.env["action_dispatch.cookies_same_site_protection"] = proc { :strict }
get :authenticate
assert_cookie_header "user_name=david; path=/; SameSite=Strict"

View File

@ -629,7 +629,15 @@ Defaults to `'signed cookie'`.
* `config.action_dispatch.cookies_same_site_protection` configures the default
value of the `SameSite` attribute when setting cookies. When set to `nil`, the
`SameSite` attribute is not added.
`SameSite` attribute is not added. To allow the value of the `SameSite` attribute
to be configured dynamically based on the request, a proc may be specified.
For example:
```ruby
config.action_dispatch.cookies_same_site_protection = ->(request) do
:strict unless request.user_agent == "TestAgent"
end
```
* `config.action_dispatch.ssl_default_redirect_status` configures the default
HTTP status code used when redirecting non-GET/HEAD requests from HTTP to HTTPS

View File

@ -281,7 +281,7 @@ module Rails
"action_dispatch.cookies_serializer" => config.action_dispatch.cookies_serializer,
"action_dispatch.cookies_digest" => config.action_dispatch.cookies_digest,
"action_dispatch.cookies_rotations" => config.action_dispatch.cookies_rotations,
"action_dispatch.cookies_same_site_protection" => config.action_dispatch.cookies_same_site_protection,
"action_dispatch.cookies_same_site_protection" => coerce_same_site_protection(config.action_dispatch.cookies_same_site_protection),
"action_dispatch.use_cookies_with_metadata" => config.action_dispatch.use_cookies_with_metadata,
"action_dispatch.content_security_policy" => config.content_security_policy,
"action_dispatch.content_security_policy_report_only" => config.content_security_policy_report_only,
@ -628,5 +628,9 @@ module Rails
def build_middleware
config.app_middleware + super
end
def coerce_same_site_protection(protection)
protection.respond_to?(:call) ? protection : proc { protection }
end
end
end