Merge pull request #9978 from trevorturk/cookie-store-auto-upgrade
Cookie-base session store auto-upgrade
This commit is contained in:
commit
f9d23b3848
@ -1,5 +1,16 @@
|
||||
## Rails 4.0.0 (unreleased) ##
|
||||
|
||||
* Automatically configure cookie-based sessions to be encrypted if
|
||||
`secret_key_base` is set, falling back to signed if only `secret_token`
|
||||
is set. Automatically upgrade existing signed cookie-based sessions from
|
||||
Rails 3.x to be encrypted if both `secret_key_base` and `secret_token`
|
||||
are set, or signed with the new key generator if only `secret_token` is
|
||||
set. This leaves only the `config.session_store :cookie_store` option and
|
||||
removes the two new options introduced in 4.0.0.beta1:
|
||||
`encrypted_cookie_store` and `upgrade_signature_to_encryption_cookie_store`.
|
||||
|
||||
*Trevor Turk*
|
||||
|
||||
* Ensure consistent fallback to the default layout lookup for layouts set
|
||||
using symbols or procs that return `nil`.
|
||||
|
||||
|
@ -84,8 +84,6 @@ module Http
|
||||
module Session
|
||||
autoload :AbstractStore, 'action_dispatch/middleware/session/abstract_store'
|
||||
autoload :CookieStore, 'action_dispatch/middleware/session/cookie_store'
|
||||
autoload :EncryptedCookieStore, 'action_dispatch/middleware/session/cookie_store'
|
||||
autoload :UpgradeSignatureToEncryptionCookieStore, 'action_dispatch/middleware/session/cookie_store'
|
||||
autoload :MemCacheStore, 'action_dispatch/middleware/session/mem_cache_store'
|
||||
autoload :CacheStore, 'action_dispatch/middleware/session/cache_store'
|
||||
end
|
||||
|
@ -117,6 +117,9 @@ def permanent
|
||||
# the cookie again. This is useful for creating cookies with values that the user is not supposed to change. If a signed
|
||||
# cookie was tampered with by the user (or a 3rd party), nil will be returned.
|
||||
#
|
||||
# If +config.secret_key_base+ and +config.secret_token+ (deprecated) are both set,
|
||||
# legacy cookies signed with the old key generator will be transparently upgraded.
|
||||
#
|
||||
# This jar requires that you set a suitable secret for the verification on your app's +config.secret_key_base+.
|
||||
#
|
||||
# Example:
|
||||
@ -126,23 +129,20 @@ def permanent
|
||||
#
|
||||
# cookies.signed[:discount] # => 45
|
||||
def signed
|
||||
@signed ||= begin
|
||||
if @options[:upgrade_legacy_signed_cookie_jar]
|
||||
@signed ||=
|
||||
if @options[:upgrade_legacy_signed_cookies]
|
||||
UpgradeLegacySignedCookieJar.new(self, @key_generator, @options)
|
||||
else
|
||||
SignedCookieJar.new(self, @key_generator, @options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Only needed for supporting the +UpgradeSignatureToEncryptionCookieStore+, users and plugin authors should not use this
|
||||
def signed_using_old_secret #:nodoc:
|
||||
@signed_using_old_secret ||= SignedCookieJar.new(self, ActiveSupport::DummyKeyGenerator.new(@options[:secret_token]), @options)
|
||||
end
|
||||
|
||||
# Returns a jar that'll automatically encrypt cookie values before sending them to the client and will decrypt them for read.
|
||||
# If the cookie was tampered with by the user (or a 3rd party), nil will be returned.
|
||||
#
|
||||
# If +config.secret_key_base+ and +config.secret_token+ (deprecated) are both set,
|
||||
# legacy cookies signed with the old key generator will be transparently upgraded.
|
||||
#
|
||||
# This jar requires that you set a suitable secret for the verification on your app's +config.secret_key_base+.
|
||||
#
|
||||
# Example:
|
||||
@ -152,7 +152,38 @@ def signed_using_old_secret #:nodoc:
|
||||
#
|
||||
# cookies.encrypted[:discount] # => 45
|
||||
def encrypted
|
||||
@encrypted ||= EncryptedCookieJar.new(self, @key_generator, @options)
|
||||
@encrypted ||=
|
||||
if @options[:upgrade_legacy_signed_cookies]
|
||||
UpgradeLegacyEncryptedCookieJar.new(self, @key_generator, @options)
|
||||
else
|
||||
EncryptedCookieJar.new(self, @key_generator, @options)
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the +signed+ or +encrypted jar, preferring +encrypted+ if +secret_key_base+ is set.
|
||||
# Used by ActionDispatch::Session::CookieStore to avoid the need to introduce new cookie stores.
|
||||
def signed_or_encrypted
|
||||
@signed_or_encrypted ||=
|
||||
if @options[:secret_key_base].present?
|
||||
encrypted
|
||||
else
|
||||
signed
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module VerifyAndUpgradeLegacySignedMessage
|
||||
def initialize(*args)
|
||||
super
|
||||
@legacy_verifier = ActiveSupport::MessageVerifier.new(@options[:secret_token])
|
||||
end
|
||||
|
||||
def verify_and_upgrade_legacy_signed_message(name, signed_message)
|
||||
@legacy_verifier.verify(signed_message).tap do |value|
|
||||
self[name] = value
|
||||
end
|
||||
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
@ -179,7 +210,7 @@ def self.options_for_env(env) #:nodoc:
|
||||
encrypted_signed_cookie_salt: env[ENCRYPTED_SIGNED_COOKIE_SALT] || '',
|
||||
secret_token: env[SECRET_TOKEN],
|
||||
secret_key_base: env[SECRET_KEY_BASE],
|
||||
upgrade_legacy_signed_cookie_jar: env[SECRET_TOKEN].present? && env[SECRET_KEY_BASE].present?
|
||||
upgrade_legacy_signed_cookies: env[SECRET_TOKEN].present? && env[SECRET_KEY_BASE].present?
|
||||
}
|
||||
end
|
||||
|
||||
@ -354,10 +385,8 @@ def initialize(parent_jar, key_generator, options = {})
|
||||
|
||||
def [](name)
|
||||
if signed_message = @parent_jar[name]
|
||||
@verifier.verify(signed_message)
|
||||
verify(signed_message)
|
||||
end
|
||||
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
||||
nil
|
||||
end
|
||||
|
||||
def []=(key, options)
|
||||
@ -371,6 +400,14 @@ def []=(key, options)
|
||||
raise CookieOverflow if options[:value].size > MAX_COOKIE_SIZE
|
||||
@parent_jar[key] = options
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def verify(signed_message)
|
||||
@verifier.verify(signed_message)
|
||||
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# UpgradeLegacySignedCookieJar is used instead of SignedCookieJar if
|
||||
@ -378,30 +415,13 @@ def []=(key, options)
|
||||
# legacy cookies signed with the old dummy key generator and re-saves
|
||||
# them using the new key generator to provide a smooth upgrade path.
|
||||
class UpgradeLegacySignedCookieJar < SignedCookieJar #:nodoc:
|
||||
def initialize(*args)
|
||||
super
|
||||
@legacy_verifier = ActiveSupport::MessageVerifier.new(@options[:secret_token])
|
||||
end
|
||||
include VerifyAndUpgradeLegacySignedMessage
|
||||
|
||||
def [](name)
|
||||
if signed_message = @parent_jar[name]
|
||||
verify_signed_message(signed_message) || verify_and_upgrade_legacy_signed_message(name, signed_message)
|
||||
verify(signed_message) || verify_and_upgrade_legacy_signed_message(name, signed_message)
|
||||
end
|
||||
end
|
||||
|
||||
def verify_signed_message(signed_message)
|
||||
@verifier.verify(signed_message)
|
||||
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
||||
nil
|
||||
end
|
||||
|
||||
def verify_and_upgrade_legacy_signed_message(name, signed_message)
|
||||
@legacy_verifier.verify(signed_message).tap do |value|
|
||||
self[name] = value
|
||||
end
|
||||
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
class EncryptedCookieJar #:nodoc:
|
||||
@ -409,8 +429,8 @@ class EncryptedCookieJar #:nodoc:
|
||||
|
||||
def initialize(parent_jar, key_generator, options = {})
|
||||
if ActiveSupport::DummyKeyGenerator === key_generator
|
||||
raise "Encrypted Cookies must be used in conjunction with config.secret_key_base." +
|
||||
"Set config.secret_key_base in config/initializers/secret_token.rb"
|
||||
raise "You didn't set config.secret_key_base, which is required for this cookie jar. " +
|
||||
"Read the upgrade documentation to learn more about this new config option."
|
||||
end
|
||||
|
||||
@parent_jar = parent_jar
|
||||
@ -422,11 +442,8 @@ def initialize(parent_jar, key_generator, options = {})
|
||||
|
||||
def [](key)
|
||||
if encrypted_message = @parent_jar[key]
|
||||
@encryptor.decrypt_and_verify(encrypted_message)
|
||||
decrypt_and_verify(encrypted_message)
|
||||
end
|
||||
rescue ActiveSupport::MessageVerifier::InvalidSignature,
|
||||
ActiveSupport::MessageEncryptor::InvalidMessage
|
||||
nil
|
||||
end
|
||||
|
||||
def []=(key, options)
|
||||
@ -440,6 +457,28 @@ def []=(key, options)
|
||||
raise CookieOverflow if options[:value].size > MAX_COOKIE_SIZE
|
||||
@parent_jar[key] = options
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def decrypt_and_verify(encrypted_message)
|
||||
@encryptor.decrypt_and_verify(encrypted_message)
|
||||
rescue ActiveSupport::MessageVerifier::InvalidSignature, ActiveSupport::MessageEncryptor::InvalidMessage
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# UpgradeLegacyEncryptedCookieJar is used by ActionDispatch::Session::CookieStore
|
||||
# instead of EncryptedCookieJar if config.secret_token and config.secret_key_base
|
||||
# are both set. It reads legacy cookies signed with the old dummy key generator and
|
||||
# encrypts and re-saves them using the new key generator to provide a smooth upgrade path.
|
||||
class UpgradeLegacyEncryptedCookieJar < EncryptedCookieJar #:nodoc:
|
||||
include VerifyAndUpgradeLegacySignedMessage
|
||||
|
||||
def [](name)
|
||||
if encrypted_or_signed_message = @parent_jar[name]
|
||||
decrypt_and_verify(encrypted_or_signed_message) || verify_and_upgrade_legacy_signed_message(name, encrypted_or_signed_message)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(app)
|
||||
|
@ -100,42 +100,7 @@ def get_cookie(env)
|
||||
|
||||
def cookie_jar(env)
|
||||
request = ActionDispatch::Request.new(env)
|
||||
request.cookie_jar.signed
|
||||
end
|
||||
end
|
||||
|
||||
class EncryptedCookieStore < CookieStore
|
||||
|
||||
private
|
||||
|
||||
def cookie_jar(env)
|
||||
request = ActionDispatch::Request.new(env)
|
||||
request.cookie_jar.encrypted
|
||||
end
|
||||
end
|
||||
|
||||
# This cookie store helps you upgrading apps that use +CookieStore+ to the new default +EncryptedCookieStore+
|
||||
# To use this CookieStore set
|
||||
#
|
||||
# Myapp::Application.config.session_store :upgrade_signature_to_encryption_cookie_store, key: '_myapp_session'
|
||||
#
|
||||
# in your config/initializers/session_store.rb
|
||||
#
|
||||
# You will also need to add
|
||||
#
|
||||
# Myapp::Application.config.secret_key_base = 'some secret'
|
||||
#
|
||||
# in your config/initializers/secret_token.rb, but do not remove +Myapp::Application.config.secret_token = 'some secret'+
|
||||
class UpgradeSignatureToEncryptionCookieStore < EncryptedCookieStore
|
||||
private
|
||||
|
||||
def get_cookie(env)
|
||||
signed_using_old_secret_cookie_jar(env)[@key] || cookie_jar(env)[@key]
|
||||
end
|
||||
|
||||
def signed_using_old_secret_cookie_jar(env)
|
||||
request = ActionDispatch::Request.new(env)
|
||||
request.cookie_jar.signed_using_old_secret
|
||||
request.cookie_jar.signed_or_encrypted
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -86,6 +86,11 @@ def set_encrypted_cookie
|
||||
head :ok
|
||||
end
|
||||
|
||||
def get_encrypted_cookie
|
||||
cookies.encrypted[:foo]
|
||||
head :ok
|
||||
end
|
||||
|
||||
def set_invalid_encrypted_cookie
|
||||
cookies[:invalid_cookie] = 'invalid--9170e00a57cfc27083363b5c75b835e477bd90cf'
|
||||
head :ok
|
||||
@ -456,7 +461,42 @@ def test_signed_uses_upgrade_legacy_signed_cookie_jar_if_both_secret_token_and_s
|
||||
assert_kind_of ActionDispatch::Cookies::UpgradeLegacySignedCookieJar, cookies.signed
|
||||
end
|
||||
|
||||
def test_legacy_signed_cookie_is_read_and_transparently_upgraded_if_both_secret_token_and_secret_key_base_are_set
|
||||
def test_signed_or_encrypted_uses_signed_cookie_jar_if_only_secret_token_is_set
|
||||
@request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
|
||||
@request.env["action_dispatch.secret_key_base"] = nil
|
||||
get :get_encrypted_cookie
|
||||
assert_kind_of ActionDispatch::Cookies::SignedCookieJar, cookies.signed_or_encrypted
|
||||
end
|
||||
|
||||
def test_signed_or_encrypted_uses_encrypted_cookie_jar_if_only_secret_key_base_is_set
|
||||
@request.env["action_dispatch.secret_token"] = nil
|
||||
@request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
|
||||
get :get_encrypted_cookie
|
||||
assert_kind_of ActionDispatch::Cookies::EncryptedCookieJar, cookies.signed_or_encrypted
|
||||
end
|
||||
|
||||
def test_signed_or_encrypted_uses_upgrade_legacy_encrypted_cookie_jar_if_both_secret_token_and_secret_key_base_are_set
|
||||
@request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
|
||||
@request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
|
||||
get :get_encrypted_cookie
|
||||
assert_kind_of ActionDispatch::Cookies::UpgradeLegacyEncryptedCookieJar, cookies.signed_or_encrypted
|
||||
end
|
||||
|
||||
def test_encrypted_uses_encrypted_cookie_jar_if_only_secret_key_base_is_set
|
||||
@request.env["action_dispatch.secret_token"] = nil
|
||||
@request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
|
||||
get :get_encrypted_cookie
|
||||
assert_kind_of ActionDispatch::Cookies::EncryptedCookieJar, cookies.encrypted
|
||||
end
|
||||
|
||||
def test_encrypted_uses_upgrade_legacy_encrypted_cookie_jar_if_both_secret_token_and_secret_key_base_are_set
|
||||
@request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
|
||||
@request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
|
||||
get :get_encrypted_cookie
|
||||
assert_kind_of ActionDispatch::Cookies::UpgradeLegacyEncryptedCookieJar, cookies.encrypted
|
||||
end
|
||||
|
||||
def test_legacy_signed_cookie_is_read_and_transparently_upgraded_by_signed_cookie_jar_if_both_secret_token_and_secret_key_base_are_set
|
||||
@request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
|
||||
@request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
|
||||
|
||||
@ -473,7 +513,27 @@ def test_legacy_signed_cookie_is_read_and_transparently_upgraded_if_both_secret_
|
||||
assert_equal 45, verifier.verify(@response.cookies["user_id"])
|
||||
end
|
||||
|
||||
def test_legacy_signed_cookie_is_nil_if_tampered
|
||||
def test_legacy_signed_cookie_is_read_and_transparently_encrypted_by_encrypted_cookie_jar_if_both_secret_token_and_secret_key_base_are_set
|
||||
@request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
|
||||
@request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
|
||||
@request.env["action_dispatch.encrypted_cookie_salt"] = "4433796b79d99a7735553e316522acee"
|
||||
@request.env["action_dispatch.encrypted_signed_cookie_salt"] = "00646eb40062e1b1deff205a27cd30f9"
|
||||
|
||||
legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33").generate('bar')
|
||||
|
||||
@request.headers["Cookie"] = "foo=#{legacy_value}"
|
||||
get :get_encrypted_cookie
|
||||
|
||||
assert_equal 'bar', @controller.send(:cookies).encrypted[:foo]
|
||||
|
||||
key_generator = @request.env["action_dispatch.key_generator"]
|
||||
secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"])
|
||||
sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
|
||||
encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret)
|
||||
assert_equal 'bar', encryptor.decrypt_and_verify(@response.cookies["foo"])
|
||||
end
|
||||
|
||||
def test_legacy_signed_cookie_is_treated_as_nil_by_signed_cookie_jar_if_tampered
|
||||
@request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
|
||||
@request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
|
||||
|
||||
@ -484,6 +544,17 @@ def test_legacy_signed_cookie_is_nil_if_tampered
|
||||
assert_equal nil, @response.cookies["user_id"]
|
||||
end
|
||||
|
||||
def test_legacy_signed_cookie_is_treated_as_nil_by_encrypted_cookie_jar_if_tampered
|
||||
@request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
|
||||
@request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
|
||||
|
||||
@request.headers["Cookie"] = "foo=baz"
|
||||
get :get_encrypted_cookie
|
||||
|
||||
assert_equal nil, @controller.send(:cookies).encrypted[:foo]
|
||||
assert_equal nil, @response.cookies["foo"]
|
||||
end
|
||||
|
||||
def test_cookie_with_all_domain_option
|
||||
get :set_cookie_with_domain
|
||||
assert_response :success
|
||||
|
@ -1,3 +1,3 @@
|
||||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
Blog::Application.config.session_store :encrypted_cookie_store, key: '_blog_session'
|
||||
Blog::Application.config.session_store :cookie_store, key: '_blog_session'
|
||||
|
@ -92,17 +92,20 @@ Rails 4.0 extracted Active Resource to its own gem. If you still need the featur
|
||||
|
||||
Please note that you should wait to set `secret_key_base` until you have 100% of your userbase on Rails 4.x and are reasonably sure you will not need to rollback to Rails 3.x. This is because cookies signed based on the new `secret_key_base` in Rails 4.x are not backwards compatible with Rails 3.x. You are free to leave your existing `secret_token` in place, not set the new `secret_key_base`, and ignore the deprecation warnings until you are reasonably sure that your upgrade is otherwise complete.
|
||||
|
||||
* Rails 4.0 introduces a new `UpgradeSignatureToEncryptionCookieStore` cookie store. This is useful for upgrading apps using the old default `CookieStore` to the new default `EncryptedCookieStore` which leverages the new `ActiveSupport::KeyGenerator`. To use this transitional cookie store, you'll want to leave your existing `secret_token` in place, add a new `secret_key_base`, and change your `session_store` like so:
|
||||
If you are relying on the ability for external applications or Javascript to be able to read your Rails app's signed session cookies (or signed cookies in general) you should not set `secret_key_base` until you have decoupled these concerns.
|
||||
|
||||
* Rails 4.0 encrypts the contents of cookie-based sessions if `secret_key_base` has been set. Rails 3.x signed, but did not encrypt, the contents of cookie-based session. Signed cookies are "secure" in that they are verified to have been generated by your app and are tamper-proof. However, the contents can be viewed by end users, and encrypting the contents eliminates this caveat/concern.
|
||||
|
||||
As described above, existing signed cookies generated with Rails 3.x will be transparently upgraded if you leave your existing `secret_token` in place and add the new `secret_key_base`.
|
||||
|
||||
```ruby
|
||||
# config/initializers/session_store.rb
|
||||
Myapp::Application.config.session_store :upgrade_signature_to_encryption_cookie_store, key: 'existing session key'
|
||||
|
||||
# config/initializers/secret_token.rb
|
||||
Myapp::Application.config.secret_token = 'existing secret token'
|
||||
Myapp::Application.config.secret_key_base = 'new secret key base'
|
||||
```
|
||||
|
||||
The same caveats apply here, too. You should wait to set `secret_key_base` until you have 100% of your userbase on Rails 4.x and are reasonably sure you will not need to rollback to Rails 3.x. You should also take care to make sure you are not relying on the ability to decode signed cookies generated by your app in external applications or Javascript before upgrading.
|
||||
|
||||
* Rails 4.0 removed the `ActionController::Base.asset_path` option. Use the assets pipeline feature.
|
||||
|
||||
* Rails 4.0 has deprecated `ActionController::Base.page_cache_extension` option. Use `ActionController::Base.default_static_extension` instead.
|
||||
|
@ -1,4 +1,5 @@
|
||||
require 'fileutils'
|
||||
require 'active_support/core_ext/object/blank'
|
||||
# FIXME remove DummyKeyGenerator and this require in 4.1
|
||||
require 'active_support/key_generator'
|
||||
require 'rails/engine'
|
||||
@ -122,7 +123,8 @@ def key_generator
|
||||
#
|
||||
# * "action_dispatch.parameter_filter" => config.filter_parameters
|
||||
# * "action_dispatch.redirect_filter" => config.filter_redirect
|
||||
# * "action_dispatch.secret_token" => config.secret_token,
|
||||
# * "action_dispatch.secret_token" => config.secret_token
|
||||
# * "action_dispatch.secret_key_base" => config.secret_key_base
|
||||
# * "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions
|
||||
# * "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local
|
||||
# * "action_dispatch.logger" => Rails.logger
|
||||
@ -135,13 +137,12 @@ def key_generator
|
||||
#
|
||||
def env_config
|
||||
@app_env_config ||= begin
|
||||
if config.secret_key_base.nil?
|
||||
ActiveSupport::Deprecation.warn "You didn't set config.secret_key_base in config/initializers/secret_token.rb file. " +
|
||||
"This should be used instead of the old deprecated config.secret_token in order to use the new EncryptedCookieStore. " +
|
||||
"To convert safely to the encrypted store (without losing existing cookies and sessions), see http://guides.rubyonrails.org/upgrading_ruby_on_rails.html#action-pack"
|
||||
if config.secret_key_base.blank?
|
||||
ActiveSupport::Deprecation.warn "You didn't set config.secret_key_base. " +
|
||||
"Read the upgrade documentation to learn more about this new config option."
|
||||
|
||||
if config.secret_token.blank?
|
||||
raise "You must set config.secret_key_base in your app's config"
|
||||
raise "You must set config.secret_key_base in your app's config."
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
<%= app_const %>.config.session_store :encrypted_cookie_store, key: <%= "'_#{app_name}_session'" %>
|
||||
<%= app_const %>.config.session_store :cookie_store, key: <%= "'_#{app_name}_session'" %>
|
||||
|
@ -157,10 +157,6 @@ def read_raw_cookie
|
||||
end
|
||||
RUBY
|
||||
|
||||
add_to_config <<-RUBY
|
||||
config.session_store :encrypted_cookie_store, key: '_myapp_session'
|
||||
RUBY
|
||||
|
||||
require "#{app_path}/config/environment"
|
||||
|
||||
get '/foo/write_session'
|
||||
@ -178,7 +174,7 @@ def read_raw_cookie
|
||||
assert_equal 1, encryptor.decrypt_and_verify(last_response.body)['foo']
|
||||
end
|
||||
|
||||
test "session using upgrade signature to encryption cookie store works the same way as encrypted cookie store" do
|
||||
test "session upgrading signature to encryption cookie store works the same way as encrypted cookie store" do
|
||||
app_file 'config/routes.rb', <<-RUBY
|
||||
AppTemplate::Application.routes.draw do
|
||||
get ':controller(/:action)'
|
||||
@ -208,7 +204,6 @@ def read_raw_cookie
|
||||
|
||||
add_to_config <<-RUBY
|
||||
config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
|
||||
config.session_store :upgrade_signature_to_encryption_cookie_store, key: '_myapp_session'
|
||||
RUBY
|
||||
|
||||
require "#{app_path}/config/environment"
|
||||
@ -228,7 +223,7 @@ def read_raw_cookie
|
||||
assert_equal 1, encryptor.decrypt_and_verify(last_response.body)['foo']
|
||||
end
|
||||
|
||||
test "session using upgrade signature to encryption cookie store upgrades session to encrypted mode" do
|
||||
test "session upgrading signature to encryption cookie store upgrades session to encrypted mode" do
|
||||
app_file 'config/routes.rb', <<-RUBY
|
||||
AppTemplate::Application.routes.draw do
|
||||
get ':controller(/:action)'
|
||||
@ -264,7 +259,6 @@ def read_raw_cookie
|
||||
|
||||
add_to_config <<-RUBY
|
||||
config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
|
||||
config.session_store :upgrade_signature_to_encryption_cookie_store, key: '_myapp_session'
|
||||
RUBY
|
||||
|
||||
require "#{app_path}/config/environment"
|
||||
@ -287,5 +281,63 @@ def read_raw_cookie
|
||||
get '/foo/read_raw_cookie'
|
||||
assert_equal 2, encryptor.decrypt_and_verify(last_response.body)['foo']
|
||||
end
|
||||
|
||||
test "session upgrading legacy signed cookies to new signed cookies" do
|
||||
app_file 'config/routes.rb', <<-RUBY
|
||||
AppTemplate::Application.routes.draw do
|
||||
get ':controller(/:action)'
|
||||
end
|
||||
RUBY
|
||||
|
||||
controller :foo, <<-RUBY
|
||||
class FooController < ActionController::Base
|
||||
def write_raw_session
|
||||
# {"session_id"=>"1965d95720fffc123941bdfb7d2e6870", "foo"=>1}
|
||||
cookies[:_myapp_session] = "BAh7B0kiD3Nlc3Npb25faWQGOgZFRkkiJTE5NjVkOTU3MjBmZmZjMTIzOTQxYmRmYjdkMmU2ODcwBjsAVEkiCGZvbwY7AEZpBg==--315fb9931921a87ae7421aec96382f0294119749"
|
||||
render nothing: true
|
||||
end
|
||||
|
||||
def write_session
|
||||
session[:foo] = session[:foo] + 1
|
||||
render nothing: true
|
||||
end
|
||||
|
||||
def read_session
|
||||
render text: session[:foo]
|
||||
end
|
||||
|
||||
def read_signed_cookie
|
||||
render text: cookies.signed[:_myapp_session]['foo']
|
||||
end
|
||||
|
||||
def read_raw_cookie
|
||||
render text: cookies[:_myapp_session]
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
|
||||
add_to_config <<-RUBY
|
||||
config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
|
||||
config.secret_key_base = nil
|
||||
RUBY
|
||||
|
||||
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_signed_cookie'
|
||||
assert_equal '2', last_response.body
|
||||
|
||||
verifier = ActiveSupport::MessageVerifier.new(app.config.secret_token)
|
||||
|
||||
get '/foo/read_raw_cookie'
|
||||
assert_equal 2, verifier.verify(last_response.body)['foo']
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -346,7 +346,7 @@ def test_no_active_record_or_test_unit_if_skips_given
|
||||
def test_new_hash_style
|
||||
run_generator [destination_root]
|
||||
assert_file "config/initializers/session_store.rb" do |file|
|
||||
assert_match(/config.session_store :encrypted_cookie_store, key: '_.+_session'/, file)
|
||||
assert_match(/config.session_store :cookie_store, key: '_.+_session'/, file)
|
||||
end
|
||||
end
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user