summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Speller <alex@alexspeller.com>2020-02-01 03:16:31 +0000
committerJeremy Evans <code@jeremyevans.net>2020-02-04 07:43:16 -0800
commitdbd33f7e8c2149332636e32301c295197f046490 (patch)
tree119f3560ba2afb0ebd4731cabf06befb81e736ef
parent59985351196ad348dbe53b799333ad24d8d64404 (diff)
downloadrack-dbd33f7e8c2149332636e32301c295197f046490.tar.gz
Allow passing through same_site option to session cookie when using Rack::Session::Cookie middleware
Recently, rack added support for SameSite=None cookies: https://github.com/rack/rack/pull/1358 However there is currently no way to set these cookies using the Rack::Session::Cookie middleware without monkeypatching. This pull request allows setting the SameSite value either by direct, literal passthrough to the add_cookie_to_header method, or by passing a callable. The callable option is required because some browsers are incompatible with some values of the header, so it needs to be [different per-browser](https://www.chromium.org/updates/same-site/incompatible-clients). Static usage: ```ruby use Rack::Session::Cookie, secret: 'supersecret', same_site: :none ``` Dynamic usage: ```ruby use Rack::Session::Cookie, secret: 'supersecret', same_site: lambda { |req, res| SameSite.value(req.user_agent) } ```
-rw-r--r--lib/rack/session/abstract/id.rb6
-rw-r--r--lib/rack/session/cookie.rb1
-rw-r--r--test/spec_session_cookie.rb17
3 files changed, 24 insertions, 0 deletions
diff --git a/lib/rack/session/abstract/id.rb b/lib/rack/session/abstract/id.rb
index 74fd98f9..cb011359 100644
--- a/lib/rack/session/abstract/id.rb
+++ b/lib/rack/session/abstract/id.rb
@@ -393,6 +393,12 @@ module Rack
cookie[:value] = cookie_value(data)
cookie[:expires] = Time.now + options[:expire_after] if options[:expire_after]
cookie[:expires] = Time.now + options[:max_age] if options[:max_age]
+
+ if @same_site.respond_to? :call
+ cookie[:same_site] = @same_site.call(req, res)
+ else
+ cookie[:same_site] = @same_site
+ end
set_cookie(req, res, cookie.merge!(options))
end
end
diff --git a/lib/rack/session/cookie.rb b/lib/rack/session/cookie.rb
index bb541396..3b82b41d 100644
--- a/lib/rack/session/cookie.rb
+++ b/lib/rack/session/cookie.rb
@@ -118,6 +118,7 @@ module Rack
Called from: #{caller[0]}.
MSG
@coder = options[:coder] ||= Base64::Marshal.new
+ @same_site = options.delete :same_site
super(app, options.merge!(cookie_only: true))
end
diff --git a/test/spec_session_cookie.rb b/test/spec_session_cookie.rb
index 0a240b9f..ce85ba32 100644
--- a/test/spec_session_cookie.rb
+++ b/test/spec_session_cookie.rb
@@ -196,6 +196,23 @@ describe Rack::Session::Cookie do
response.body.must_equal '{"counter"=>1}'
end
+ it "passes through same_site option to session cookie" do
+ response = response_for(app: [incrementor, same_site: :none])
+ response["Set-Cookie"].must_include "SameSite=None"
+ end
+
+ it "allows using a lambda to specify same_site option, because some browsers require different settings" do
+ # Details of why this might need to be set dynamically:
+ # https://www.chromium.org/updates/same-site/incompatible-clients
+ # https://gist.github.com/bnorton/7dee72023787f367c48b3f5c2d71540f
+
+ response = response_for(app: [incrementor, same_site: lambda { |req, res| :none }])
+ response["Set-Cookie"].must_include "SameSite=None"
+
+ response = response_for(app: [incrementor, same_site: lambda { |req, res| :lax }])
+ response["Set-Cookie"].must_include "SameSite=Lax"
+ end
+
it "loads from a cookie" do
response = response_for(app: incrementor)