aboutsummaryrefslogtreecommitdiffstats
path: root/railties/test/application/middleware/session_test.rb
diff options
context:
space:
mode:
Diffstat (limited to 'railties/test/application/middleware/session_test.rb')
-rw-r--r--railties/test/application/middleware/session_test.rb272
1 files changed, 183 insertions, 89 deletions
diff --git a/railties/test/application/middleware/session_test.rb b/railties/test/application/middleware/session_test.rb
index 85e7761727..a17988235a 100644
--- a/railties/test/application/middleware/session_test.rb
+++ b/railties/test/application/middleware/session_test.rb
@@ -1,5 +1,7 @@
-require 'isolation/abstract_unit'
-require 'rack/test'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "rack/test"
module ApplicationTests
class MiddlewareSessionTest < ActiveSupport::TestCase
@@ -8,7 +10,6 @@ module ApplicationTests
def setup
build_app
- boot_rails
FileUtils.rm_rf "#{app_path}/config/environments"
end
@@ -54,7 +55,7 @@ module ApplicationTests
end
test "session is empty and isn't saved on unverified request when using :null_session protect method" do
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get ':controller(/:action)'
post ':controller(/:action)'
@@ -71,7 +72,7 @@ module ApplicationTests
end
def read_session
- render text: session[:foo].inspect
+ render plain: session[:foo].inspect
end
end
RUBY
@@ -82,20 +83,20 @@ module ApplicationTests
require "#{app_path}/config/environment"
- get '/foo/write_session'
- get '/foo/read_session'
- assert_equal '1', last_response.body
+ get "/foo/write_session"
+ get "/foo/read_session"
+ assert_equal "1", last_response.body
- post '/foo/read_session' # Read session using POST request without CSRF token
- assert_equal 'nil', last_response.body # Stored value shouldn't be accessible
+ post "/foo/read_session" # Read session using POST request without CSRF token
+ assert_equal "nil", last_response.body # Stored value shouldn't be accessible
- post '/foo/write_session' # Write session using POST request without CSRF token
- get '/foo/read_session' # Session shouldn't be changed
- assert_equal '1', last_response.body
+ post "/foo/write_session" # Write session using POST request without CSRF token
+ get "/foo/read_session" # Session shouldn't be changed
+ assert_equal "1", last_response.body
end
test "cookie jar is empty and isn't saved on unverified request when using :null_session protect method" do
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get ':controller(/:action)'
post ':controller(/:action)'
@@ -112,7 +113,7 @@ module ApplicationTests
end
def read_cookie
- render text: cookies[:foo].inspect
+ render plain: cookies[:foo].inspect
end
end
RUBY
@@ -123,20 +124,20 @@ module ApplicationTests
require "#{app_path}/config/environment"
- get '/foo/write_cookie'
- get '/foo/read_cookie'
+ get "/foo/write_cookie"
+ get "/foo/read_cookie"
assert_equal '"1"', last_response.body
- post '/foo/read_cookie' # Read cookie using POST request without CSRF token
- assert_equal 'nil', last_response.body # Stored value shouldn't be accessible
+ post "/foo/read_cookie" # Read cookie using POST request without CSRF token
+ assert_equal "nil", last_response.body # Stored value shouldn't be accessible
- post '/foo/write_cookie' # Write cookie using POST request without CSRF token
- get '/foo/read_cookie' # Cookie shouldn't be changed
+ post "/foo/write_cookie" # Write cookie using POST request without CSRF token
+ get "/foo/read_cookie" # Cookie shouldn't be changed
assert_equal '"1"', last_response.body
end
test "session using encrypted cookie store" do
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get ':controller(/:action)'
end
@@ -150,38 +151,43 @@ module ApplicationTests
end
def read_session
- render text: session[:foo]
+ render plain: session[:foo]
end
def read_encrypted_cookie
- render text: cookies.encrypted[:_myapp_session]['foo']
+ render plain: cookies.encrypted[:_myapp_session]['foo']
end
def read_raw_cookie
- render text: cookies[:_myapp_session]
+ render plain: cookies[:_myapp_session]
end
end
RUBY
+ add_to_config <<-RUBY
+ # Enable AEAD cookies
+ config.action_dispatch.use_authenticated_cookie_encryption = true
+ RUBY
+
require "#{app_path}/config/environment"
- get '/foo/write_session'
- get '/foo/read_session'
- assert_equal '1', last_response.body
+ get "/foo/write_session"
+ get "/foo/read_session"
+ assert_equal "1", last_response.body
- get '/foo/read_encrypted_cookie'
- assert_equal '1', last_response.body
+ get "/foo/read_encrypted_cookie"
+ assert_equal "1", last_response.body
- secret = app.key_generator.generate_key('encrypted cookie')
- sign_secret = app.key_generator.generate_key('signed encrypted cookie')
- encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret)
+ cipher = "aes-256-gcm"
+ secret = app.key_generator.generate_key("authenticated encrypted cookie")
+ encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len(cipher)], cipher: cipher)
- get '/foo/read_raw_cookie'
- assert_equal 1, encryptor.decrypt_and_verify(last_response.body)['foo']
+ get "/foo/read_raw_cookie"
+ assert_equal 1, encryptor.decrypt_and_verify(last_response.body)["foo"]
end
test "session upgrading signature to encryption cookie store works the same way as encrypted cookie store" do
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get ':controller(/:action)'
end
@@ -195,42 +201,45 @@ module ApplicationTests
end
def read_session
- render text: session[:foo]
+ render plain: session[:foo]
end
def read_encrypted_cookie
- render text: cookies.encrypted[:_myapp_session]['foo']
+ render plain: cookies.encrypted[:_myapp_session]['foo']
end
def read_raw_cookie
- render text: cookies[:_myapp_session]
+ render plain: cookies[:_myapp_session]
end
end
RUBY
add_to_config <<-RUBY
secrets.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
+
+ # Enable AEAD cookies
+ config.action_dispatch.use_authenticated_cookie_encryption = true
RUBY
require "#{app_path}/config/environment"
- get '/foo/write_session'
- get '/foo/read_session'
- assert_equal '1', last_response.body
+ get "/foo/write_session"
+ get "/foo/read_session"
+ assert_equal "1", last_response.body
- get '/foo/read_encrypted_cookie'
- assert_equal '1', last_response.body
+ get "/foo/read_encrypted_cookie"
+ assert_equal "1", last_response.body
- secret = app.key_generator.generate_key('encrypted cookie')
- sign_secret = app.key_generator.generate_key('signed encrypted cookie')
- encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret)
+ cipher = "aes-256-gcm"
+ secret = app.key_generator.generate_key("authenticated encrypted cookie")
+ encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len(cipher)], cipher: cipher)
- get '/foo/read_raw_cookie'
- assert_equal 1, encryptor.decrypt_and_verify(last_response.body)['foo']
+ get "/foo/read_raw_cookie"
+ assert_equal 1, encryptor.decrypt_and_verify(last_response.body)["foo"]
end
test "session upgrading signature to encryption cookie store upgrades session to encrypted mode" do
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get ':controller(/:action)'
end
@@ -250,46 +259,119 @@ module ApplicationTests
end
def read_session
- render text: session[:foo]
+ render plain: session[:foo]
end
def read_encrypted_cookie
- render text: cookies.encrypted[:_myapp_session]['foo']
+ render plain: cookies.encrypted[:_myapp_session]['foo']
end
def read_raw_cookie
- render text: cookies[:_myapp_session]
+ render plain: cookies[:_myapp_session]
end
end
RUBY
add_to_config <<-RUBY
secrets.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
+
+ # Enable AEAD cookies
+ config.action_dispatch.use_authenticated_cookie_encryption = true
RUBY
require "#{app_path}/config/environment"
- get '/foo/write_raw_session'
- get '/foo/read_session'
- assert_equal '1', last_response.body
+ get "/foo/write_raw_session"
+ get "/foo/read_session"
+ assert_equal "1", last_response.body
- get '/foo/write_session'
- get '/foo/read_session'
- assert_equal '2', last_response.body
+ get "/foo/write_session"
+ get "/foo/read_session"
+ assert_equal "2", last_response.body
- get '/foo/read_encrypted_cookie'
- assert_equal '2', last_response.body
+ get "/foo/read_encrypted_cookie"
+ assert_equal "2", last_response.body
- secret = app.key_generator.generate_key('encrypted cookie')
- sign_secret = app.key_generator.generate_key('signed encrypted cookie')
- encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret)
+ cipher = "aes-256-gcm"
+ secret = app.key_generator.generate_key("authenticated encrypted cookie")
+ encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len(cipher)], cipher: cipher)
- get '/foo/read_raw_cookie'
- assert_equal 2, encryptor.decrypt_and_verify(last_response.body)['foo']
+ get "/foo/read_raw_cookie"
+ assert_equal 2, encryptor.decrypt_and_verify(last_response.body)["foo"]
+ end
+
+ test "session upgrading from AES-CBC-HMAC encryption to AES-GCM encryption" do
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ get ':controller(/:action)'
+ end
+ RUBY
+
+ controller :foo, <<-RUBY
+ class FooController < ActionController::Base
+ def write_raw_session
+ # AES-256-CBC with SHA1 HMAC
+ # {"session_id"=>"1965d95720fffc123941bdfb7d2e6870", "foo"=>1}
+ cookies[:_myapp_session] = "TlgrdS85aUpDd1R2cDlPWlR6K0FJeGExckwySjZ2Z0pkR3d2QnRObGxZT25aalJWYWVvbFVLcHF4d0VQVDdSaFF2QjFPbG9MVjJzeWp3YjcyRUlKUUU2ZlR4bXlSNG9ZUkJPRUtld0E3dVU9LS0xNDZXbGpRZ3NjdW43N2haUEZJSUNRPT0=--3639b5ce54c09495cfeaae928cd5634e0c4b2e96"
+ head :ok
+ end
+
+ def write_session
+ session[:foo] = session[:foo] + 1
+ head :ok
+ end
+
+ def read_session
+ render plain: session[:foo]
+ end
+
+ def read_encrypted_cookie
+ render plain: cookies.encrypted[:_myapp_session]['foo']
+ end
+
+ def read_raw_cookie
+ render plain: cookies[:_myapp_session]
+ end
+ end
+ RUBY
+
+ add_to_config <<-RUBY
+ # Use a static key
+ Rails.application.credentials.secret_key_base = "known key base"
+
+ # Enable AEAD cookies
+ config.action_dispatch.use_authenticated_cookie_encryption = true
+ RUBY
+
+ begin
+ old_rails_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "production"
+
+ require "#{app_path}/config/environment"
+
+ get "/foo/write_raw_session"
+ get "/foo/read_session"
+ assert_equal "1", last_response.body
+
+ get "/foo/write_session"
+ get "/foo/read_session"
+ assert_equal "2", last_response.body
+
+ get "/foo/read_encrypted_cookie"
+ assert_equal "2", last_response.body
+
+ cipher = "aes-256-gcm"
+ secret = app.key_generator.generate_key("authenticated encrypted cookie")
+ encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len(cipher)], cipher: cipher)
+
+ get "/foo/read_raw_cookie"
+ assert_equal 2, encryptor.decrypt_and_verify(last_response.body)["foo"]
+ ensure
+ ENV["RAILS_ENV"] = old_rails_env
+ end
end
test "session upgrading legacy signed cookies to new signed cookies" do
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get ':controller(/:action)'
end
@@ -309,45 +391,51 @@ module ApplicationTests
end
def read_session
- render text: session[:foo]
+ render plain: session[:foo]
end
def read_signed_cookie
- render text: cookies.signed[:_myapp_session]['foo']
+ render plain: cookies.signed[:_myapp_session]['foo']
end
def read_raw_cookie
- render text: cookies[:_myapp_session]
+ render plain: cookies[:_myapp_session]
end
end
RUBY
add_to_config <<-RUBY
secrets.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
- secrets.secret_key_base = nil
+ Rails.application.credentials.secret_key_base = nil
RUBY
- require "#{app_path}/config/environment"
+ begin
+ old_rails_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "production"
+
+ require "#{app_path}/config/environment"
- get '/foo/write_raw_session'
- get '/foo/read_session'
- assert_equal '1', last_response.body
+ get "/foo/write_raw_session"
+ get "/foo/read_session"
+ assert_equal "1", last_response.body
- get '/foo/write_session'
- get '/foo/read_session'
- assert_equal '2', last_response.body
+ get "/foo/write_session"
+ get "/foo/read_session"
+ assert_equal "2", last_response.body
- get '/foo/read_signed_cookie'
- assert_equal '2', last_response.body
+ get "/foo/read_signed_cookie"
+ assert_equal "2", last_response.body
- verifier = ActiveSupport::MessageVerifier.new(app.secrets.secret_token)
+ verifier = ActiveSupport::MessageVerifier.new(app.secrets.secret_token)
- get '/foo/read_raw_cookie'
- assert_equal 2, verifier.verify(last_response.body)['foo']
+ get "/foo/read_raw_cookie"
+ assert_equal 2, verifier.verify(last_response.body)["foo"]
+ ensure
+ ENV["RAILS_ENV"] = old_rails_env
+ end
end
- test 'calling reset_session on request does not trigger an error for API apps' do
- add_to_config 'config.api_only = true'
+ test "calling reset_session on request does not trigger an error for API apps" do
+ add_to_config "config.api_only = true"
controller :test, <<-RUBY
class TestController < ApplicationController
@@ -358,7 +446,7 @@ module ApplicationTests
end
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get '/dump_flash' => "test#dump_flash"
end
@@ -366,12 +454,18 @@ module ApplicationTests
require "#{app_path}/config/environment"
- get '/dump_flash'
+ get "/dump_flash"
assert_equal 200, last_response.status
- assert_equal 'It worked!', last_response.body
+ assert_equal "It worked!", last_response.body
- refute Rails.application.middleware.include?(ActionDispatch::Flash)
+ assert_not_includes Rails.application.middleware, ActionDispatch::Flash
+ end
+
+ test "cookie_only is set to true even if user tries to overwrite it" do
+ add_to_config "config.session_store :cookie_store, key: '_myapp_session', cookie_only: false"
+ require "#{app_path}/config/environment"
+ assert app.config.session_options[:cookie_only], "Expected cookie_only to be set to true"
end
end
end