From e8e9948774bef6134edfc9973e9f4218e21fccda Mon Sep 17 00:00:00 2001 From: Rob Chekaluk Date: Sat, 23 Feb 2019 10:57:11 -0500 Subject: [PATCH 01/16] Optionally sign or encrypt cookie. Fixes #48 --- README.md | 17 ++ .../session/active_record_store.rb | 69 ++++++++ lib/action_dispatch/session/legacy_support.rb | 51 +++++- lib/active_record/session_store.rb | 2 + test/action_controller_test.rb | 161 ++++++++++++++++++ test/helper.rb | 1 + 6 files changed, 300 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f3978df..f8bd43d 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,23 @@ been updated in the last 30 days. The 30 days cutoff can be changed using the Configuration -------------- +A cookie is used to identify the appropriate ActiveRecord record. +By default this cookie is in cleartext. +You may optionally configure this cookie to be signed or encrypted. For example, at the end of `config/application.rb`: + +```ruby +ActiveRecord::SessionStore::Session.sign_cookie = true +ActiveRecord::SessionStore::Session.encrypt_cookie = true +``` + +Setting these configuration values has the following behaviors: +| `sign_cookie` | `encrypt_cookie` | Behavior | +| ------------- | ---------------- | ---------------- | +| false | false | Cleartext cookie | +| false | true | Encrypted cookie | +| true | false | Signed cookie | +| true | true | Encrypted cookie | + The default assumes a `sessions` tables with columns: * `id` (numeric primary key), diff --git a/lib/action_dispatch/session/active_record_store.rb b/lib/action_dispatch/session/active_record_store.rb index 76c3081..e963f0d 100644 --- a/lib/action_dispatch/session/active_record_store.rb +++ b/lib/action_dispatch/session/active_record_store.rb @@ -9,6 +9,22 @@ module Session # provided, but any object duck-typing to an Active Record Session class # with text +session_id+ and +data+ attributes is sufficient. # + # A cookie is used to identify the appropriate ActiveRecord record. + # By default this cookie is in cleartext. + # You may optionally configure this cookie to be signed or encrypted. + # For example, at the end of `config/application.rb`: + # + # ActiveRecord::SessionStore::Session.sign_cookie = true + # ActiveRecord::SessionStore::Session.encrypt_cookie = true + # + # Setting these configuration values has the following behaviors: + # sign_cookie encrypt_cookie Behavior + # ------------- ---------------- ---------------- + # false false Cleartext cookie + # false true Encrypted cookie + # true false Signed cookie + # true true Encrypted cookie + # # The default assumes a +sessions+ tables with columns: # +id+ (numeric primary key), # +session_id+ (string, usually varchar; maximum length is 255), and @@ -78,6 +94,59 @@ def get_session(request, sid) end end + def cookie_is_signed_or_encrypted? + ActiveRecord::SessionStore::Session.sign_cookie || ActiveRecord::SessionStore::Session.encrypt_cookie + end + + # Inspired by ActionDispatch::Session::CookieStore + # https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb + # (ideally should by DRY in ActionPack by migrating to ActionDispatch::Session::AbstractStore) + # (noting that ActionDispatch::Session::CookieStore does not currently respect :cookie_only) + def extract_session_id(req) + sid = stale_session_check! do + unpacked_cookie_data(req) + end + + # Inspired by Rack::Session::Abstract::Persisted + # https://github.com/rack/rack/blob/master/lib/rack/session/abstract/id.rb + sid ||= req.params[@key] unless @cookie_only + sid + end + + # Inspired by ActionDispatch::Session::CookieStore + # https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb + # (ideally should by DRY in ActionPack by migrating to ActionDispatch::Session::AbstractStore) + def unpacked_cookie_data(req) + + req.fetch_header("action_dispatch.request.unsigned_session_cookie") do |k| + v = stale_session_check! do + get_cookie(req) || nil # not empty string + end + req.set_header k, v + end + end + + # Duplicated from ActionDispatch::Session::CookieStore + # (ideally should by DRY in ActionPack by migrating to ActionDispatch::Session::AbstractStore) + def set_cookie(request, session_id, cookie) + cookie_jar(request)[@key] = cookie + end + + # Duplicated from ActionDispatch::Session::CookieStore + # (ideally should by DRY in ActionPack by migrating to ActionDispatch::Session::AbstractStore) + def get_cookie(req) + cookie_jar(req)[@key] + end + + # Inspired from ActionDispatch::Session::CookieStore + def cookie_jar(request) + if cookie_is_signed_or_encrypted? + request.cookie_jar.signed_or_encrypted + else + request.cookie_jar + end + end + def write_session(request, sid, session_data, options) logger.silence_logger do record = get_session_model(request, sid) diff --git a/lib/action_dispatch/session/legacy_support.rb b/lib/action_dispatch/session/legacy_support.rb index 48cd2e1..a1b469d 100644 --- a/lib/action_dispatch/session/legacy_support.rb +++ b/lib/action_dispatch/session/legacy_support.rb @@ -9,7 +9,12 @@ def self.included(klass) :get_session_model, :write_session, :delete_session, - :find_session + :find_session, + :extract_session_id, + :unpacked_cookie_data, + :set_cookie, + :get_cookie, + :cookie_jar ].each do |m| klass.send(:alias_method, "#{m}_rails5".to_sym, m) klass.send(:remove_method, m) @@ -46,6 +51,50 @@ def get_session_model(request, sid) def find_session(id) self.class.session_class.find_by_session_id(id) || self.class.session_class.new(:session_id => id, :data => {}) end + + # Inspired by Rails 4 ActionDispatch::Session::CookieStore + # https://github.com/rails/rails/blob/6b9a1ac484a4eda1b43aba7ed864952aac743ab9/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb + def extract_session_id(env) + sid = stale_session_check! do + unpacked_cookie_data(env) + end + + sid ||= env["action_dispatch.request.parameters"][@key] unless @cookie_only + sid + end + + # Inspired by Rails 4 ActionDispatch::Session::CookieStore + # https://github.com/rails/rails/blob/6b9a1ac484a4eda1b43aba7ed864952aac743ab9/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb + def unpacked_cookie_data(env) + env["action_dispatch.request.unsigned_session_cookie"] ||= begin + stale_session_check! do + get_cookie(env) || nil # not empty string + end + end + end + + # https://github.com/rails/rails/blob/6b9a1ac484a4eda1b43aba7ed864952aac743ab9/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb + def set_cookie(env, session_id, cookie) + cookie_jar(env)[@key] = cookie + end + + # https://github.com/rails/rails/blob/6b9a1ac484a4eda1b43aba7ed864952aac743ab9/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb + def get_cookie(env) + cookie_jar(env)[@key] + end + + # Inspired by Rails 4 ActionDispatch::Session::CookieStore + # https://github.com/rails/rails/blob/6b9a1ac484a4eda1b43aba7ed864952aac743ab9/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb + def cookie_jar(env) + request = ActionDispatch::Request.new(env) + if cookie_is_signed_or_encrypted? + request.cookie_jar.signed_or_encrypted + else + request.cookie_jar + end + end + end end end + diff --git a/lib/active_record/session_store.rb b/lib/active_record/session_store.rb index fde698d..094b715 100644 --- a/lib/active_record/session_store.rb +++ b/lib/active_record/session_store.rb @@ -8,7 +8,9 @@ module ActiveRecord module SessionStore module ClassMethods # :nodoc: + mattr_accessor :encrypt_cookie mattr_accessor :serializer + mattr_accessor :sign_cookie def serialize(data) serializer_class.dump(data) if data diff --git a/test/action_controller_test.rb b/test/action_controller_test.rb index 6289069..08c4bbc 100644 --- a/test/action_controller_test.rb +++ b/test/action_controller_test.rb @@ -1,6 +1,30 @@ require 'helper' class ActionControllerTest < ActionDispatch::IntegrationTest + SessionKey = "_session_id" + SessionSecret = "b3c631c314c0bbca50c1b2843150fe33" + SessionSalt = "signed or encrypted cookie" + + if ActiveRecord::VERSION::MAJOR == 4 + Generator = ActiveSupport::KeyGenerator.new(SessionSecret) + + Verifier = ActiveSupport::MessageVerifier.new(Generator.generate_key(SessionSalt), :digest => 'SHA1') + + Encryptor = ActiveSupport::MessageEncryptor.new(Generator.generate_key(SessionSalt, 32), Generator.generate_key(SessionSalt)) + + else + Generator = ActiveSupport::KeyGenerator.new(SessionSecret, iterations: 1000) + Rotations = ActiveSupport::Messages::RotationConfiguration.new + + Verifier = ActiveSupport::MessageVerifier.new( + Generator.generate_key(SessionSalt), serializer: Marshal + ) + + Encryptor = ActiveSupport::MessageEncryptor.new( + Generator.generate_key(SessionSalt, 32), cipher: "aes-256-gcm", serializer: Marshal + ) + end + class TestController < ActionController::Base protect_from_forgery def no_session_access @@ -46,6 +70,9 @@ def renew def setup ActionDispatch::Session::ActiveRecordStore.session_class.drop_table! rescue nil ActionDispatch::Session::ActiveRecordStore.session_class.create_table! + + ActiveRecord::SessionStore::Session.sign_cookie = false + ActiveRecord::SessionStore::Session.encrypt_cookie = false end %w{ session sql_bypass }.each do |class_name| @@ -179,6 +206,84 @@ def test_getting_session_id end end + def test_signed_cookie + ActiveRecord::SessionStore::Session.sign_cookie = true + with_test_route_set do + get '/set_session_value' + assert_response :success + assert cookies['_session_id'] + session_id_signed = cookies['_session_id'] + + if ActiveRecord::VERSION::MAJOR == 4 + session_id, time = Verifier.verify(session_id_signed) rescue nil + time = time # Suppress "warning: assigned but unused variable - time" + else + session_id = Verifier.verified(session_id_signed) rescue nil + end + + get '/get_session_id' + assert_response :success + assert_equal session_id, response.body, "should be able to read signed session id" + end + end + + def test_encrypted_cookie + ActiveRecord::SessionStore::Session.encrypt_cookie = true + with_test_route_set do + get '/set_session_value' + assert_response :success + assert cookies['_session_id'] + session_id_encrypted = cookies['_session_id'] + session_id = Encryptor.decrypt_and_verify(session_id_encrypted) rescue nil + + get '/get_session_id' + assert_response :success + assert_equal session_id, response.body, "should be able to read encrypted session id" + end + end + + # From https://github.com/rails/rails/blob/master/actionpack/test/dispatch/session/cookie_store_test.rb + def test_signed_cookie_disregards_tampered_sessions + ActiveRecord::SessionStore::Session.sign_cookie = true + with_test_route_set do + bad_key = Generator.generate_key(SessionSalt).reverse + + if ActiveRecord::VERSION::MAJOR == 4 + verifier = ActiveSupport::MessageVerifier.new(bad_key, :digest => 'SHA1') + else + verifier = ActiveSupport::MessageVerifier.new(bad_key, serializer: Marshal) + end + + cookies[SessionKey] = verifier.generate("foo" => "bar", "session_id" => "abc") + + get "/get_session_value" + + assert_response :success + assert_equal "foo: nil", response.body + end + end + + # From https://github.com/rails/rails/blob/master/actionpack/test/dispatch/session/cookie_store_test.rb + def test_encrypted_cookie_disregards_tampered_sessions + ActiveRecord::SessionStore::Session.encrypt_cookie = true + with_test_route_set do + + if ActiveRecord::VERSION::MAJOR == 4 + bad_sign_secret = Generator.generate_key(SessionSalt).reverse + encryptor = ActiveSupport::MessageEncryptor.new(Generator.generate_key(SessionSalt, 32), bad_sign_secret) + else + encryptor = ActiveSupport::MessageEncryptor.new("A" * 32, cipher: "aes-256-gcm", serializer: Marshal) + end + + cookies[SessionKey] = encryptor.encrypt_and_sign("foo" => "bar", "session_id" => "abc") + + get "/get_session_value" + + assert_response :success + assert_equal "foo: nil", response.body + end + end + def test_doesnt_write_session_cookie_if_session_id_is_already_exists with_test_route_set do get '/set_session_value' @@ -285,4 +390,60 @@ def test_session_store_with_all_domains assert_response :success end end + + private + + if ActiveRecord::VERSION::MAJOR == 4 + # Overwrite get to send SessionSecret in env hash + # Inspired by https://github.com/rails/rails/blob/6b9a1ac484a4eda1b43aba7ed864952aac743ab9/actionpack/test/dispatch/session/cookie_store_test.rb + def get(path, parameters = nil, env = {}) + signed = ActiveRecord::SessionStore::Session.sign_cookie + encrypted = ActiveRecord::SessionStore::Session.encrypt_cookie + + if signed || encrypted + env["action_dispatch.key_generator"] ||= Generator + end + + if signed && ! encrypted + env["action_dispatch.signed_cookie_salt"] = SessionSalt + + elsif encrypted + env["action_dispatch.encrypted_cookie_salt"] = SessionSalt + env["action_dispatch.encrypted_signed_cookie_salt"] = SessionSalt + env["action_dispatch.secret_key_base"] = SessionSecret + end + + super + end + + else + # Overwrite get to send SessionSecret in env hash + # Inspired by https://github.com/rails/rails/blob/master/actionpack/test/dispatch/session/cookie_store_test.rb + def get(path, *args) + args[0] ||= {} + args[0][:headers] ||= {} + args[0][:headers].tap do |config| + signed = ActiveRecord::SessionStore::Session.sign_cookie + encrypted = ActiveRecord::SessionStore::Session.encrypt_cookie + + if signed || encrypted + config["action_dispatch.key_generator"] ||= Generator + config["action_dispatch.cookies_rotations"] ||= Rotations unless ActiveRecord::VERSION::MAJOR == 4 + end + + if signed && ! encrypted + config["action_dispatch.signed_cookie_salt"] = SessionSalt + + elsif encrypted + config["action_dispatch.authenticated_encrypted_cookie_salt"] = SessionSalt + config["action_dispatch.secret_key_base"] = SessionSecret + config["action_dispatch.use_authenticated_cookie_encryption"] = true + end + + end + + super(path, *args) + end + end + end diff --git a/test/helper.rb b/test/helper.rb index 6af2dcc..812afc8 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -6,6 +6,7 @@ require 'minitest/autorun' require 'active_record/session_store' +require 'active_support/messages/rotation_configuration' unless ActiveRecord::VERSION::MAJOR == 4 ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:') From 8a38c4940f53227664e4f3b9c240c5ba1ecda113 Mon Sep 17 00:00:00 2001 From: Rob Chekaluk Date: Mon, 25 Feb 2019 04:19:58 -0500 Subject: [PATCH 02/16] Support Rails 5.1 and 5.0 --- test/action_controller_test.rb | 42 +++++++++++++++++++++++++++------- test/helper.rb | 2 +- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/test/action_controller_test.rb b/test/action_controller_test.rb index 08c4bbc..19cfa61 100644 --- a/test/action_controller_test.rb +++ b/test/action_controller_test.rb @@ -14,15 +14,23 @@ class ActionControllerTest < ActionDispatch::IntegrationTest else Generator = ActiveSupport::KeyGenerator.new(SessionSecret, iterations: 1000) - Rotations = ActiveSupport::Messages::RotationConfiguration.new + Rotations = ActiveSupport::Messages::RotationConfiguration.new unless ActiveRecord::VERSION::STRING < '5.2' Verifier = ActiveSupport::MessageVerifier.new( Generator.generate_key(SessionSalt), serializer: Marshal ) - Encryptor = ActiveSupport::MessageEncryptor.new( - Generator.generate_key(SessionSalt, 32), cipher: "aes-256-gcm", serializer: Marshal - ) + Cipher = (ActiveRecord::VERSION::STRING < '5.2' ? "aes-256-cbc" : "aes-256-gcm") # Rails < 5.2 must use non-AEAD aes-256-cbc + + if ActiveRecord::VERSION::STRING < '5.2' || Cipher != "aes-256-gcm" + Encryptor = ActiveSupport::MessageEncryptor.new( + Generator.generate_key(SessionSalt, 32), Generator.generate_key(SessionSalt), cipher: Cipher, serializer: Marshal + ) + else + Encryptor = ActiveSupport::MessageEncryptor.new( + Generator.generate_key(SessionSalt, 32), cipher: Cipher, serializer: Marshal + ) + end end class TestController < ActionController::Base @@ -272,7 +280,7 @@ def test_encrypted_cookie_disregards_tampered_sessions bad_sign_secret = Generator.generate_key(SessionSalt).reverse encryptor = ActiveSupport::MessageEncryptor.new(Generator.generate_key(SessionSalt, 32), bad_sign_secret) else - encryptor = ActiveSupport::MessageEncryptor.new("A" * 32, cipher: "aes-256-gcm", serializer: Marshal) + encryptor = ActiveSupport::MessageEncryptor.new("A" * 32, cipher: Cipher, serializer: Marshal) end cookies[SessionKey] = encryptor.encrypt_and_sign("foo" => "bar", "session_id" => "abc") @@ -425,19 +433,37 @@ def get(path, *args) args[0][:headers].tap do |config| signed = ActiveRecord::SessionStore::Session.sign_cookie encrypted = ActiveRecord::SessionStore::Session.encrypt_cookie + aead_mode = (Cipher == "aes-256-gcm") if signed || encrypted config["action_dispatch.key_generator"] ||= Generator - config["action_dispatch.cookies_rotations"] ||= Rotations unless ActiveRecord::VERSION::MAJOR == 4 + config["action_dispatch.cookies_rotations"] ||= Rotations unless ActiveRecord::VERSION::STRING < '5.2' end if signed && ! encrypted config["action_dispatch.signed_cookie_salt"] = SessionSalt elsif encrypted - config["action_dispatch.authenticated_encrypted_cookie_salt"] = SessionSalt config["action_dispatch.secret_key_base"] = SessionSecret - config["action_dispatch.use_authenticated_cookie_encryption"] = true + + if ActiveRecord::VERSION::STRING < '5.2' + config["action_dispatch.encrypted_cookie_salt"] = SessionSalt + config["action_dispatch.encrypted_signed_cookie_salt"] = SessionSalt + + else + config["action_dispatch.encrypted_cookie_cipher"] = Cipher + + if aead_mode + config["action_dispatch.authenticated_encrypted_cookie_salt"] = SessionSalt + config["action_dispatch.use_authenticated_cookie_encryption"] = true + + else + config["action_dispatch.encrypted_cookie_salt"] = SessionSalt + config["action_dispatch.encrypted_signed_cookie_salt"] = SessionSalt + config["action_dispatch.use_authenticated_cookie_encryption"] = false + end + + end end end diff --git a/test/helper.rb b/test/helper.rb index 812afc8..8291499 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -6,7 +6,7 @@ require 'minitest/autorun' require 'active_record/session_store' -require 'active_support/messages/rotation_configuration' unless ActiveRecord::VERSION::MAJOR == 4 +require 'active_support/messages/rotation_configuration' unless ActiveRecord::VERSION::STRING < '5.2' ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:') From 321faa3a801cdce9ebed67e6badd2174c5e4a3c8 Mon Sep 17 00:00:00 2001 From: Rob Chekaluk Date: Mon, 25 Feb 2019 04:37:33 -0500 Subject: [PATCH 03/16] sqlite3: match activerecord dependency --- activerecord-session_store.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord-session_store.gemspec b/activerecord-session_store.gemspec index 181c9ac..6711754 100644 --- a/activerecord-session_store.gemspec +++ b/activerecord-session_store.gemspec @@ -25,6 +25,6 @@ Gem::Specification.new do |s| s.add_dependency('rack', '>= 1.5.2', '< 3') s.add_dependency('multi_json', '~> 1.11', '>= 1.11.2') - s.add_development_dependency('sqlite3') + s.add_development_dependency('sqlite3', '~> 1.3.6') # match activerecord dependency s.add_development_dependency('appraisal', '~> 2.1.0') end From 4c115eb3ba9942a76d247f10441bd744fa5c804b Mon Sep 17 00:00:00 2001 From: Rob Chekaluk Date: Mon, 25 Feb 2019 04:51:16 -0500 Subject: [PATCH 04/16] Revert "sqlite3: match activerecord dependency" This reverts commit 321faa3a801cdce9ebed67e6badd2174c5e4a3c8. --- activerecord-session_store.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord-session_store.gemspec b/activerecord-session_store.gemspec index 6711754..181c9ac 100644 --- a/activerecord-session_store.gemspec +++ b/activerecord-session_store.gemspec @@ -25,6 +25,6 @@ Gem::Specification.new do |s| s.add_dependency('rack', '>= 1.5.2', '< 3') s.add_dependency('multi_json', '~> 1.11', '>= 1.11.2') - s.add_development_dependency('sqlite3', '~> 1.3.6') # match activerecord dependency + s.add_development_dependency('sqlite3') s.add_development_dependency('appraisal', '~> 2.1.0') end From c2b4ad14b97219f8e8cd59c2c3198cee00e2e3eb Mon Sep 17 00:00:00 2001 From: Rob Chekaluk Date: Mon, 25 Feb 2019 05:46:21 -0500 Subject: [PATCH 05/16] Force no signing or encryption in original tests. --- test/destroy_session_test.rb | 5 ++++- test/logger_silencer_test.rb | 3 +++ test/session_test.rb | 3 +++ test/sql_bypass_test.rb | 3 +++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/test/destroy_session_test.rb b/test/destroy_session_test.rb index c3b299c..48c08a9 100644 --- a/test/destroy_session_test.rb +++ b/test/destroy_session_test.rb @@ -11,6 +11,9 @@ def setup @req = ActionDispatch::Request.empty ActionDispatch::Session::ActiveRecordStore.session_class.drop_table! rescue nil ActionDispatch::Session::ActiveRecordStore.session_class.create_table! + + ActiveRecord::SessionStore::Session.sign_cookie = false + ActiveRecord::SessionStore::Session.encrypt_cookie = false end def record_key @@ -50,4 +53,4 @@ def store end end end -end \ No newline at end of file +end diff --git a/test/logger_silencer_test.rb b/test/logger_silencer_test.rb index 787d058..eb598ce 100644 --- a/test/logger_silencer_test.rb +++ b/test/logger_silencer_test.rb @@ -23,6 +23,9 @@ def setup session_class.drop_table! rescue nil session_class.create_table! ActionDispatch::Session::ActiveRecordStore.session_class = session_class + + ActiveRecord::SessionStore::Session.sign_cookie = false + ActiveRecord::SessionStore::Session.encrypt_cookie = false end %w{ session sql_bypass }.each do |class_name| diff --git a/test/session_test.rb b/test/session_test.rb index e904e34..6fc31dc 100644 --- a/test/session_test.rb +++ b/test/session_test.rb @@ -14,6 +14,9 @@ def setup Session.drop_table! if Session.table_exists? @session_klass = Class.new(Session) ActiveRecord::SessionStore::Session.serializer = :json + + ActiveRecord::SessionStore::Session.sign_cookie = false + ActiveRecord::SessionStore::Session.encrypt_cookie = false end def test_data_column_name diff --git a/test/sql_bypass_test.rb b/test/sql_bypass_test.rb index 3fc1dc2..6ad3524 100644 --- a/test/sql_bypass_test.rb +++ b/test/sql_bypass_test.rb @@ -16,6 +16,9 @@ def test_create_table assert Session.table_exists? SqlBypass.drop_table! assert !Session.table_exists? + + ActiveRecord::SessionStore::Session.sign_cookie = false + ActiveRecord::SessionStore::Session.encrypt_cookie = false end def test_new_record? From c27331899ec9ba8ba38d291d112fc306e5477106 Mon Sep 17 00:00:00 2001 From: Rob Chekaluk Date: Mon, 25 Feb 2019 19:46:50 -0500 Subject: [PATCH 06/16] Formatting --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f8bd43d..4eddb0e 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ ActiveRecord::SessionStore::Session.encrypt_cookie = true ``` Setting these configuration values has the following behaviors: + | `sign_cookie` | `encrypt_cookie` | Behavior | | ------------- | ---------------- | ---------------- | | false | false | Cleartext cookie | From 55058db43bdd797af30a5d96575387e7f269537c Mon Sep 17 00:00:00 2001 From: Rob Chekaluk Date: Sun, 18 Sep 2022 05:11:32 -0400 Subject: [PATCH 07/16] Support Rails 6.1 --- test/destroy_session_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/destroy_session_test.rb b/test/destroy_session_test.rb index 48c08a9..a97caa1 100644 --- a/test/destroy_session_test.rb +++ b/test/destroy_session_test.rb @@ -25,7 +25,7 @@ def test_destroy_without_renew s['set_something_so_it_loads'] = true session_model = req.env[record_key] - session_model.update_attributes(:data => {'rails' => 'ftw'}) + session_model.update(:data => {'rails' => 'ftw'}) s.destroy @@ -38,7 +38,7 @@ def test_destroy_with_renew s['set_something_so_it_loads'] = true session_model = req.env[record_key] - session_model.update_attributes(:data => {'rails' => 'ftw'}) + session_model.update(:data => {'rails' => 'ftw'}) s.destroy From 0b21310403bcec85bbfa7f915728a924ceb4b141 Mon Sep 17 00:00:00 2001 From: Rob Chekaluk Date: Sun, 18 Sep 2022 05:55:40 -0400 Subject: [PATCH 08/16] Support Ruby 3 --- test/action_controller_test.rb | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/test/action_controller_test.rb b/test/action_controller_test.rb index 19cfa61..d807be9 100644 --- a/test/action_controller_test.rb +++ b/test/action_controller_test.rb @@ -262,7 +262,7 @@ def test_signed_cookie_disregards_tampered_sessions verifier = ActiveSupport::MessageVerifier.new(bad_key, serializer: Marshal) end - cookies[SessionKey] = verifier.generate("foo" => "bar", "session_id" => "abc") + cookies[SessionKey] = verifier.generate({ "foo" => "bar", "session_id" => "abc" }) get "/get_session_value" @@ -283,7 +283,7 @@ def test_encrypted_cookie_disregards_tampered_sessions encryptor = ActiveSupport::MessageEncryptor.new("A" * 32, cipher: Cipher, serializer: Marshal) end - cookies[SessionKey] = encryptor.encrypt_and_sign("foo" => "bar", "session_id" => "abc") + cookies[SessionKey] = encryptor.encrypt_and_sign({ "foo" => "bar", "session_id" => "abc" }) get "/get_session_value" @@ -427,10 +427,9 @@ def get(path, parameters = nil, env = {}) else # Overwrite get to send SessionSecret in env hash # Inspired by https://github.com/rails/rails/blob/master/actionpack/test/dispatch/session/cookie_store_test.rb - def get(path, *args) - args[0] ||= {} - args[0][:headers] ||= {} - args[0][:headers].tap do |config| + def get(path, **options) + options[:headers] ||= {} + options[:headers].tap do |config| signed = ActiveRecord::SessionStore::Session.sign_cookie encrypted = ActiveRecord::SessionStore::Session.encrypt_cookie aead_mode = (Cipher == "aes-256-gcm") @@ -468,7 +467,7 @@ def get(path, *args) end - super(path, *args) + super end end From 65c80c534dc07c0bee94598593c31c5a702067ef Mon Sep 17 00:00:00 2001 From: Rob Chekaluk Date: Sun, 18 Sep 2022 08:13:07 -0400 Subject: [PATCH 09/16] Remove all code to support old Rails versions (emulating 45ad879a) --- .../session/active_record_store.rb | 11 +- lib/action_dispatch/session/legacy_support.rb | 100 ----------- lib/active_record/session_store.rb | 12 +- lib/active_record/session_store/session.rb | 9 - .../session_migration_generator.rb | 2 +- test/action_controller_test.rb | 167 ++++-------------- test/helper.rb | 6 +- test/logger_silencer_test.rb | 6 +- 8 files changed, 46 insertions(+), 267 deletions(-) delete mode 100644 lib/action_dispatch/session/legacy_support.rb diff --git a/lib/action_dispatch/session/active_record_store.rb b/lib/action_dispatch/session/active_record_store.rb index e963f0d..33c7356 100644 --- a/lib/action_dispatch/session/active_record_store.rb +++ b/lib/action_dispatch/session/active_record_store.rb @@ -74,11 +74,7 @@ class ActiveRecordStore < ActionDispatch::Session::AbstractStore cattr_accessor :session_class SESSION_RECORD_KEY = 'rack.session.record' - if Rack.const_defined?(:RACK_SESSION_OPTIONS) - ENV_SESSION_OPTIONS_KEY = Rack::RACK_SESSION_OPTIONS - else - ENV_SESSION_OPTIONS_KEY = Rack::Session::Abstract::ENV_SESSION_OPTIONS_KEY - end + ENV_SESSION_OPTIONS_KEY = Rack::RACK_SESSION_OPTIONS private def get_session(request, sid) @@ -216,8 +212,3 @@ def logger end end end - -if ActiveRecord::VERSION::MAJOR == 4 - require 'action_dispatch/session/legacy_support' - ActionDispatch::Session::ActiveRecordStore.send(:include, ActionDispatch::Session::LegacySupport) -end diff --git a/lib/action_dispatch/session/legacy_support.rb b/lib/action_dispatch/session/legacy_support.rb deleted file mode 100644 index a1b469d..0000000 --- a/lib/action_dispatch/session/legacy_support.rb +++ /dev/null @@ -1,100 +0,0 @@ -module ActionDispatch - module Session - module LegacySupport - EnvWrapper = Struct.new(:env) - - def self.included(klass) - [ - :get_session, - :get_session_model, - :write_session, - :delete_session, - :find_session, - :extract_session_id, - :unpacked_cookie_data, - :set_cookie, - :get_cookie, - :cookie_jar - ].each do |m| - klass.send(:alias_method, "#{m}_rails5".to_sym, m) - klass.send(:remove_method, m) - end - end - - def get_session(env, sid) - request = EnvWrapper.new(env) - get_session_rails5(request, sid) - end - - def set_session(env, sid, session_data, options) - request = EnvWrapper.new(env) - write_session_rails5(request, sid, session_data, options) - end - - def destroy_session(env, session_id, options) - request = EnvWrapper.new(env) - if sid = current_session_id(request.env) - get_session_model(request, sid).destroy - request.env[self.class::SESSION_RECORD_KEY] = nil - end - generate_sid unless options[:drop] - end - - def get_session_model(request, sid) - if request.env[self.class::ENV_SESSION_OPTIONS_KEY][:id].nil? - request.env[self.class::SESSION_RECORD_KEY] = find_session(sid) - else - request.env[self.class::SESSION_RECORD_KEY] ||= find_session(sid) - end - end - - def find_session(id) - self.class.session_class.find_by_session_id(id) || self.class.session_class.new(:session_id => id, :data => {}) - end - - # Inspired by Rails 4 ActionDispatch::Session::CookieStore - # https://github.com/rails/rails/blob/6b9a1ac484a4eda1b43aba7ed864952aac743ab9/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb - def extract_session_id(env) - sid = stale_session_check! do - unpacked_cookie_data(env) - end - - sid ||= env["action_dispatch.request.parameters"][@key] unless @cookie_only - sid - end - - # Inspired by Rails 4 ActionDispatch::Session::CookieStore - # https://github.com/rails/rails/blob/6b9a1ac484a4eda1b43aba7ed864952aac743ab9/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb - def unpacked_cookie_data(env) - env["action_dispatch.request.unsigned_session_cookie"] ||= begin - stale_session_check! do - get_cookie(env) || nil # not empty string - end - end - end - - # https://github.com/rails/rails/blob/6b9a1ac484a4eda1b43aba7ed864952aac743ab9/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb - def set_cookie(env, session_id, cookie) - cookie_jar(env)[@key] = cookie - end - - # https://github.com/rails/rails/blob/6b9a1ac484a4eda1b43aba7ed864952aac743ab9/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb - def get_cookie(env) - cookie_jar(env)[@key] - end - - # Inspired by Rails 4 ActionDispatch::Session::CookieStore - # https://github.com/rails/rails/blob/6b9a1ac484a4eda1b43aba7ed864952aac743ab9/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb - def cookie_jar(env) - request = ActionDispatch::Request.new(env) - if cookie_is_signed_or_encrypted? - request.cookie_jar.signed_or_encrypted - else - request.cookie_jar - end - end - - end - end -end - diff --git a/lib/active_record/session_store.rb b/lib/active_record/session_store.rb index 094b715..c857b37 100644 --- a/lib/active_record/session_store.rb +++ b/lib/active_record/session_store.rb @@ -21,20 +21,12 @@ def deserialize(data) end def drop_table! - if connection.schema_cache.respond_to?(:clear_data_source_cache!) - connection.schema_cache.clear_data_source_cache!(table_name) - else - connection.schema_cache.clear_table_cache!(table_name) - end + connection.schema_cache.clear_data_source_cache!(table_name) connection.drop_table table_name end def create_table! - if connection.schema_cache.respond_to?(:clear_data_source_cache!) - connection.schema_cache.clear_data_source_cache!(table_name) - else - connection.schema_cache.clear_table_cache!(table_name) - end + connection.schema_cache.clear_data_source_cache!(table_name) connection.create_table(table_name) do |t| t.string session_id_column, :limit => 255 t.text data_column_name diff --git a/lib/active_record/session_store/session.rb b/lib/active_record/session_store/session.rb index 3fafe5e..e31ea96 100644 --- a/lib/active_record/session_store/session.rb +++ b/lib/active_record/session_store/session.rb @@ -17,13 +17,6 @@ class Session < ActiveRecord::Base before_save :serialize_data! before_save :raise_on_session_data_overflow! - # This method is defiend in `protected_attributes` gem. We can't check for - # `attr_accessible` as Rails also define this and raise `RuntimeError` - # telling you to use the gem. - if respond_to?(:accessible_attributes) - attr_accessible :session_id, :data - end - class << self def data_column_size_limit @data_column_size_limit ||= columns_hash[data_column_name].limit @@ -81,7 +74,6 @@ def loaded? private def serialize_data! unless loaded? - return false if Rails::VERSION::MAJOR < 5 throw :abort end write_attribute(@@data_column_name, self.class.serialize(data)) @@ -92,7 +84,6 @@ def serialize_data! # ActionController::SessionOverflowError. def raise_on_session_data_overflow! unless loaded? - return false if Rails::VERSION::MAJOR < 5 throw :abort end limit = self.class.data_column_size_limit diff --git a/lib/generators/active_record/session_migration_generator.rb b/lib/generators/active_record/session_migration_generator.rb index b827d8c..8551a2a 100644 --- a/lib/generators/active_record/session_migration_generator.rb +++ b/lib/generators/active_record/session_migration_generator.rb @@ -21,7 +21,7 @@ def session_table_name end def migration_version - "[#{ActiveRecord::Migration.current_version}]" if ActiveRecord::Migration.respond_to?(:current_version) + "[#{ActiveRecord::Migration.current_version}]" end end end diff --git a/test/action_controller_test.rb b/test/action_controller_test.rb index d807be9..a3107d9 100644 --- a/test/action_controller_test.rb +++ b/test/action_controller_test.rb @@ -5,33 +5,18 @@ class ActionControllerTest < ActionDispatch::IntegrationTest SessionSecret = "b3c631c314c0bbca50c1b2843150fe33" SessionSalt = "signed or encrypted cookie" - if ActiveRecord::VERSION::MAJOR == 4 - Generator = ActiveSupport::KeyGenerator.new(SessionSecret) + Generator = ActiveSupport::KeyGenerator.new(SessionSecret, iterations: 1000) + Rotations = ActiveSupport::Messages::RotationConfiguration.new - Verifier = ActiveSupport::MessageVerifier.new(Generator.generate_key(SessionSalt), :digest => 'SHA1') + Verifier = ActiveSupport::MessageVerifier.new( + Generator.generate_key(SessionSalt), serializer: Marshal + ) - Encryptor = ActiveSupport::MessageEncryptor.new(Generator.generate_key(SessionSalt, 32), Generator.generate_key(SessionSalt)) + Cipher = "aes-256-gcm" - else - Generator = ActiveSupport::KeyGenerator.new(SessionSecret, iterations: 1000) - Rotations = ActiveSupport::Messages::RotationConfiguration.new unless ActiveRecord::VERSION::STRING < '5.2' - - Verifier = ActiveSupport::MessageVerifier.new( - Generator.generate_key(SessionSalt), serializer: Marshal - ) - - Cipher = (ActiveRecord::VERSION::STRING < '5.2' ? "aes-256-cbc" : "aes-256-gcm") # Rails < 5.2 must use non-AEAD aes-256-cbc - - if ActiveRecord::VERSION::STRING < '5.2' || Cipher != "aes-256-gcm" - Encryptor = ActiveSupport::MessageEncryptor.new( - Generator.generate_key(SessionSalt, 32), Generator.generate_key(SessionSalt), cipher: Cipher, serializer: Marshal - ) - else - Encryptor = ActiveSupport::MessageEncryptor.new( - Generator.generate_key(SessionSalt, 32), cipher: Cipher, serializer: Marshal - ) - end - end + Encryptor = ActiveSupport::MessageEncryptor.new( + Generator.generate_key(SessionSalt, 32), cipher: Cipher, serializer: Marshal + ) class TestController < ActionController::Base protect_from_forgery @@ -46,19 +31,11 @@ def set_session_value end def get_session_value - if ActiveRecord::VERSION::MAJOR == 4 - render :text => "foo: #{session[:foo].inspect}" - else - render :plain => "foo: #{session[:foo].inspect}" - end + render :plain => "foo: #{session[:foo].inspect}" end def get_session_id - if ActiveRecord::VERSION::MAJOR == 4 - render :text => "#{request.session.id}" - else - render :plain => "#{request.session.id}" - end + render :plain => "#{request.session.id}" end def call_reset_session @@ -95,11 +72,7 @@ def setup assert_response :success assert_equal 'foo: "bar"', response.body - if ActiveRecord::VERSION::MAJOR == 4 - get '/set_session_value', :foo => "baz" - else - get '/set_session_value', :params => { :foo => "baz" } - end + get '/set_session_value', :params => { :foo => "baz" } assert_response :success assert cookies['_session_id'] @@ -139,11 +112,7 @@ def test_getting_nil_session_value def test_calling_reset_session_twice_does_not_raise_errors with_test_route_set do - if ActiveRecord::VERSION::MAJOR == 4 - get '/call_reset_session', :twice => "true" - else - get '/call_reset_session', :params => { :twice => "true" } - end + get '/call_reset_session', :params => { :twice => "true" } assert_response :success get '/get_session_value' @@ -222,12 +191,7 @@ def test_signed_cookie assert cookies['_session_id'] session_id_signed = cookies['_session_id'] - if ActiveRecord::VERSION::MAJOR == 4 - session_id, time = Verifier.verify(session_id_signed) rescue nil - time = time # Suppress "warning: assigned but unused variable - time" - else - session_id = Verifier.verified(session_id_signed) rescue nil - end + session_id = Verifier.verified(session_id_signed) rescue nil get '/get_session_id' assert_response :success @@ -256,11 +220,7 @@ def test_signed_cookie_disregards_tampered_sessions with_test_route_set do bad_key = Generator.generate_key(SessionSalt).reverse - if ActiveRecord::VERSION::MAJOR == 4 - verifier = ActiveSupport::MessageVerifier.new(bad_key, :digest => 'SHA1') - else - verifier = ActiveSupport::MessageVerifier.new(bad_key, serializer: Marshal) - end + verifier = ActiveSupport::MessageVerifier.new(bad_key, serializer: Marshal) cookies[SessionKey] = verifier.generate({ "foo" => "bar", "session_id" => "abc" }) @@ -276,12 +236,7 @@ def test_encrypted_cookie_disregards_tampered_sessions ActiveRecord::SessionStore::Session.encrypt_cookie = true with_test_route_set do - if ActiveRecord::VERSION::MAJOR == 4 - bad_sign_secret = Generator.generate_key(SessionSalt).reverse - encryptor = ActiveSupport::MessageEncryptor.new(Generator.generate_key(SessionSalt, 32), bad_sign_secret) - else - encryptor = ActiveSupport::MessageEncryptor.new("A" * 32, cipher: Cipher, serializer: Marshal) - end + encryptor = ActiveSupport::MessageEncryptor.new("A" * 32, cipher: Cipher, serializer: Marshal) cookies[SessionKey] = encryptor.encrypt_and_sign({ "foo" => "bar", "session_id" => "abc" }) @@ -318,11 +273,7 @@ def test_prevents_session_fixation reset! - if ActiveRecord::VERSION::MAJOR == 4 - get '/get_session_value', :_session_id => session_id - else - get '/get_session_value', :params => { :_session_id => session_id } - end + get '/get_session_value', :params => { :_session_id => session_id } assert_response :success assert_equal 'foo: nil', response.body assert_not_equal session_id, cookies['_session_id'] @@ -343,11 +294,7 @@ def test_allows_session_fixation reset! - if ActiveRecord::VERSION::MAJOR == 4 - get '/set_session_value', :_session_id => session_id, :foo => "baz" - else - get '/set_session_value', :params => { :_session_id => session_id, :foo => "baz" } - end + get '/set_session_value', :params => { :_session_id => session_id, :foo => "baz" } assert_response :success assert_equal session_id, cookies['_session_id'] @@ -377,11 +324,7 @@ def test_incoming_invalid_session_id_via_cookie_should_be_ignored def test_incoming_invalid_session_id_via_parameter_should_be_ignored with_test_route_set(:cookie_only => false) do open_session do |sess| - if ActiveRecord::VERSION::MAJOR == 4 - sess.get '/set_session_value', :_session_id => 'INVALID' - else - sess.get '/set_session_value', :params => { :_session_id => 'INVALID' } - end + sess.get '/set_session_value', :params => { :_session_id => 'INVALID' } new_session_id = sess.cookies['_session_id'] assert_not_equal 'INVALID', new_session_id @@ -401,74 +344,42 @@ def test_session_store_with_all_domains private - if ActiveRecord::VERSION::MAJOR == 4 - # Overwrite get to send SessionSecret in env hash - # Inspired by https://github.com/rails/rails/blob/6b9a1ac484a4eda1b43aba7ed864952aac743ab9/actionpack/test/dispatch/session/cookie_store_test.rb - def get(path, parameters = nil, env = {}) + # Overwrite get to send SessionSecret in env hash + # Inspired by https://github.com/rails/rails/blob/master/actionpack/test/dispatch/session/cookie_store_test.rb + def get(path, **options) + options[:headers] ||= {} + options[:headers].tap do |config| signed = ActiveRecord::SessionStore::Session.sign_cookie encrypted = ActiveRecord::SessionStore::Session.encrypt_cookie + aead_mode = (Cipher == "aes-256-gcm") if signed || encrypted - env["action_dispatch.key_generator"] ||= Generator + config["action_dispatch.key_generator"] ||= Generator + config["action_dispatch.cookies_rotations"] ||= Rotations end if signed && ! encrypted - env["action_dispatch.signed_cookie_salt"] = SessionSalt + config["action_dispatch.signed_cookie_salt"] = SessionSalt elsif encrypted - env["action_dispatch.encrypted_cookie_salt"] = SessionSalt - env["action_dispatch.encrypted_signed_cookie_salt"] = SessionSalt - env["action_dispatch.secret_key_base"] = SessionSecret - end - - super - end - - else - # Overwrite get to send SessionSecret in env hash - # Inspired by https://github.com/rails/rails/blob/master/actionpack/test/dispatch/session/cookie_store_test.rb - def get(path, **options) - options[:headers] ||= {} - options[:headers].tap do |config| - signed = ActiveRecord::SessionStore::Session.sign_cookie - encrypted = ActiveRecord::SessionStore::Session.encrypt_cookie - aead_mode = (Cipher == "aes-256-gcm") - - if signed || encrypted - config["action_dispatch.key_generator"] ||= Generator - config["action_dispatch.cookies_rotations"] ||= Rotations unless ActiveRecord::VERSION::STRING < '5.2' - end + config["action_dispatch.secret_key_base"] = SessionSecret - if signed && ! encrypted - config["action_dispatch.signed_cookie_salt"] = SessionSalt + config["action_dispatch.encrypted_cookie_cipher"] = Cipher - elsif encrypted - config["action_dispatch.secret_key_base"] = SessionSecret + if aead_mode + config["action_dispatch.authenticated_encrypted_cookie_salt"] = SessionSalt + config["action_dispatch.use_authenticated_cookie_encryption"] = true - if ActiveRecord::VERSION::STRING < '5.2' - config["action_dispatch.encrypted_cookie_salt"] = SessionSalt - config["action_dispatch.encrypted_signed_cookie_salt"] = SessionSalt - - else - config["action_dispatch.encrypted_cookie_cipher"] = Cipher - - if aead_mode - config["action_dispatch.authenticated_encrypted_cookie_salt"] = SessionSalt - config["action_dispatch.use_authenticated_cookie_encryption"] = true - - else - config["action_dispatch.encrypted_cookie_salt"] = SessionSalt - config["action_dispatch.encrypted_signed_cookie_salt"] = SessionSalt - config["action_dispatch.use_authenticated_cookie_encryption"] = false - end - - end + else + config["action_dispatch.encrypted_cookie_salt"] = SessionSalt + config["action_dispatch.encrypted_signed_cookie_salt"] = SessionSalt + config["action_dispatch.use_authenticated_cookie_encryption"] = false end - end - super end + + super end end diff --git a/test/helper.rb b/test/helper.rb index 8291499..14b0961 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -6,7 +6,7 @@ require 'minitest/autorun' require 'active_record/session_store' -require 'active_support/messages/rotation_configuration' unless ActiveRecord::VERSION::STRING < '5.2' +require 'active_support/messages/rotation_configuration' ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:') @@ -77,6 +77,4 @@ def call(env) end end -if ActiveSupport::TestCase.respond_to?(:test_order=) - ActiveSupport::TestCase.test_order = :random -end +ActiveSupport::TestCase.test_order = :random diff --git a/test/logger_silencer_test.rb b/test/logger_silencer_test.rb index eb598ce..8292b0f 100644 --- a/test/logger_silencer_test.rb +++ b/test/logger_silencer_test.rb @@ -10,11 +10,7 @@ def set_session_value end def get_session_value - if ActiveRecord::VERSION::MAJOR == 4 - render :text => "foo: #{session[:foo].inspect}" - else - render :plain => "foo: #{session[:foo].inspect}" - end + render :plain => "foo: #{session[:foo].inspect}" end end From dcfafed945f83be9e3094ac84c0f851efb0fda18 Mon Sep 17 00:00:00 2001 From: Rob Chekaluk Date: Wed, 21 Sep 2022 08:45:22 -0400 Subject: [PATCH 10/16] Support secure session store (following 81f551ac0) --- lib/action_dispatch/session/active_record_store.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/action_dispatch/session/active_record_store.rb b/lib/action_dispatch/session/active_record_store.rb index 6a18494..ab04ec1 100644 --- a/lib/action_dispatch/session/active_record_store.rb +++ b/lib/action_dispatch/session/active_record_store.rb @@ -100,12 +100,13 @@ def cookie_is_signed_or_encrypted? # (noting that ActionDispatch::Session::CookieStore does not currently respect :cookie_only) def extract_session_id(req) sid = stale_session_check! do - unpacked_cookie_data(req) + sid_str = unpacked_cookie_data(req) + sid_str && Rack::Session::SessionId.new(sid_str) end # Inspired by Rack::Session::Abstract::Persisted # https://github.com/rack/rack/blob/abca7d59c566320f1b60d1f5224beac9d201fa3b/lib/rack/session/abstract/id.rb - sid ||= req.params[@key] unless @cookie_only + sid ||= Rack::Session::SessionId.new(req.params[@key]) unless @cookie_only || ! req.params[@key] sid end From 234f659b2a53655fad7d6948c6e6246bf45f47d8 Mon Sep 17 00:00:00 2001 From: Rob Chekaluk Date: Sat, 24 Sep 2022 08:31:16 -0400 Subject: [PATCH 11/16] Fix test with rack test 2 --- test/action_controller_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/action_controller_test.rb b/test/action_controller_test.rb index 06badbd..694a85f 100644 --- a/test/action_controller_test.rb +++ b/test/action_controller_test.rb @@ -127,7 +127,7 @@ def test_getting_session_value_after_session_reset get '/set_session_value' assert_response :success assert cookies['_session_id'] - session_cookie = cookies.send(:hash_for)['_session_id'] + session_cookie = cookies.get_cookie("_session_id") get '/call_reset_session' assert_response :success From 01d15a928ba7cc6bcd4b901f4f555e45f6966d05 Mon Sep 17 00:00:00 2001 From: Rob Chekaluk Date: Sat, 24 Sep 2022 09:03:23 -0400 Subject: [PATCH 12/16] Rails edge is not yet using rack 3 --- gemfiles/rails_edge.gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gemfiles/rails_edge.gemfile b/gemfiles/rails_edge.gemfile index b78671f..a1b5342 100644 --- a/gemfiles/rails_edge.gemfile +++ b/gemfiles/rails_edge.gemfile @@ -6,7 +6,7 @@ git "https://github.com/rails/rails.git", :branch => "main" do gem "railties" end -gem "rack", :git => "https://github.com/rack/rack.git", :branch => "main" +gem "rack", :git => "https://github.com/rack/rack.git", "< 3" gem "rack-session", :git => "https://github.com/rack/rack-session.git", :branch => "main" gemspec :path => "../" From 5b831d1544d6276b74a49a3931fa6d9f015449a0 Mon Sep 17 00:00:00 2001 From: Rob Chekaluk Date: Sat, 24 Sep 2022 09:08:27 -0400 Subject: [PATCH 13/16] Fix syntax error --- gemfiles/rails_edge.gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gemfiles/rails_edge.gemfile b/gemfiles/rails_edge.gemfile index a1b5342..0350eda 100644 --- a/gemfiles/rails_edge.gemfile +++ b/gemfiles/rails_edge.gemfile @@ -6,7 +6,7 @@ git "https://github.com/rails/rails.git", :branch => "main" do gem "railties" end -gem "rack", :git => "https://github.com/rack/rack.git", "< 3" +gem "rack", "< 3", :git => "https://github.com/rack/rack.git" gem "rack-session", :git => "https://github.com/rack/rack-session.git", :branch => "main" gemspec :path => "../" From 049b0791ab6a28907e80885f04b2e2e9328b9401 Mon Sep 17 00:00:00 2001 From: Rob Chekaluk Date: Sat, 24 Sep 2022 09:23:32 -0400 Subject: [PATCH 14/16] Adjust Rails edge dependencies for success --- gemfiles/rails_edge.gemfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gemfiles/rails_edge.gemfile b/gemfiles/rails_edge.gemfile index 0350eda..e26a768 100644 --- a/gemfiles/rails_edge.gemfile +++ b/gemfiles/rails_edge.gemfile @@ -6,7 +6,7 @@ git "https://github.com/rails/rails.git", :branch => "main" do gem "railties" end -gem "rack", "< 3", :git => "https://github.com/rack/rack.git" -gem "rack-session", :git => "https://github.com/rack/rack-session.git", :branch => "main" +gem "rack", "~> 2.0", ">= 2.2.4" +gem "rack-session", "< 0.2" gemspec :path => "../" From 6653bf04bcd2978918bee4f6934daec3f2c97451 Mon Sep 17 00:00:00 2001 From: Rob Chekaluk Date: Sun, 25 Sep 2022 07:09:05 -0400 Subject: [PATCH 15/16] Revert "Adjust Rails edge dependencies for success" This reverts commit 049b0791ab6a28907e80885f04b2e2e9328b9401. --- gemfiles/rails_edge.gemfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gemfiles/rails_edge.gemfile b/gemfiles/rails_edge.gemfile index e26a768..0350eda 100644 --- a/gemfiles/rails_edge.gemfile +++ b/gemfiles/rails_edge.gemfile @@ -6,7 +6,7 @@ git "https://github.com/rails/rails.git", :branch => "main" do gem "railties" end -gem "rack", "~> 2.0", ">= 2.2.4" -gem "rack-session", "< 0.2" +gem "rack", "< 3", :git => "https://github.com/rack/rack.git" +gem "rack-session", :git => "https://github.com/rack/rack-session.git", :branch => "main" gemspec :path => "../" From 28368769e2e2aa59ce5d4c573c352e2f06dd3d0b Mon Sep 17 00:00:00 2001 From: Rob Chekaluk Date: Sun, 25 Sep 2022 07:10:55 -0400 Subject: [PATCH 16/16] Emulate Rails edge actionpack rack dependency --- gemfiles/rails_edge.gemfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gemfiles/rails_edge.gemfile b/gemfiles/rails_edge.gemfile index 0350eda..26eb457 100644 --- a/gemfiles/rails_edge.gemfile +++ b/gemfiles/rails_edge.gemfile @@ -6,7 +6,6 @@ git "https://github.com/rails/rails.git", :branch => "main" do gem "railties" end -gem "rack", "< 3", :git => "https://github.com/rack/rack.git" -gem "rack-session", :git => "https://github.com/rack/rack-session.git", :branch => "main" +gem "rack", "~> 2.0", ">= 2.2.4" gemspec :path => "../"