aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSantiago Pastorino <santiago@wyeworks.com>2012-11-16 17:17:08 -0200
committerSantiago Pastorino <santiago@wyeworks.com>2012-11-16 17:29:26 -0200
commit8eefdb6d7056dc0d4d63a5c34a4b12701ba21c88 (patch)
tree18e732ac6913c5ee1cc211b19ce54396d569f3ef
parentd4b9a3fa706034b1ac2a6f8a479a697d071517a9 (diff)
downloadrails-8eefdb6d7056dc0d4d63a5c34a4b12701ba21c88.tar.gz
rails-8eefdb6d7056dc0d4d63a5c34a4b12701ba21c88.tar.bz2
rails-8eefdb6d7056dc0d4d63a5c34a4b12701ba21c88.zip
Add UpgradeSignatureToEncryptionCookieStore
This allows easy upgrading from the old signed Cookie Store <= 3.2 or the deprecated one in 4.0 (the ones that doesn't use key derivation) to the new one that signs using key derivation
-rw-r--r--actionpack/lib/action_dispatch.rb11
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb10
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/cookie_store.rb17
-rw-r--r--railties/lib/rails/application.rb2
-rw-r--r--railties/test/application/middleware/session_test.rb110
5 files changed, 143 insertions, 7 deletions
diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb
index ab1755acd5..1d716a3248 100644
--- a/actionpack/lib/action_dispatch.rb
+++ b/actionpack/lib/action_dispatch.rb
@@ -81,11 +81,12 @@ module ActionDispatch
end
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 :MemCacheStore, 'action_dispatch/middleware/session/mem_cache_store'
- autoload :CacheStore, 'action_dispatch/middleware/session/cache_store'
+ 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
mattr_accessor :test_app
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index 7936dcb515..2f148752cb 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -85,7 +85,7 @@ module ActionDispatch
SIGNED_COOKIE_SALT = "action_dispatch.signed_cookie_salt".freeze
ENCRYPTED_COOKIE_SALT = "action_dispatch.encrypted_cookie_salt".freeze
ENCRYPTED_SIGNED_COOKIE_SALT = "action_dispatch.encrypted_signed_cookie_salt".freeze
-
+ TOKEN_KEY = "action_dispatch.secret_token".freeze
# Raised when storing more than 4K of session data.
CookieOverflow = Class.new StandardError
@@ -112,7 +112,8 @@ module ActionDispatch
key_generator = env[GENERATOR_KEY]
options = { signed_cookie_salt: env[SIGNED_COOKIE_SALT],
encrypted_cookie_salt: env[ENCRYPTED_COOKIE_SALT],
- encrypted_signed_cookie_salt: env[ENCRYPTED_SIGNED_COOKIE_SALT] }
+ encrypted_signed_cookie_salt: env[ENCRYPTED_SIGNED_COOKIE_SALT],
+ token_key: env[TOKEN_KEY] }
host = request.host
secure = request.ssl?
@@ -251,6 +252,11 @@ module ActionDispatch
@signed ||= SignedCookieJar.new(self, @key_generator, @options)
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[:token_key]), @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), an ActiveSupport::MessageVerifier::InvalidSignature exception
# will be raised.
diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
index 55a9314524..d7f83a1cc6 100644
--- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
@@ -93,5 +93,22 @@ module ActionDispatch
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.config.session_store :upgrade_signature_to_encryption_cookie_store, key: '_myapp_session'
+ # in your config/initializers/session_store.rb
+ 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
+ end
+ end
end
end
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index b7844bbfbe..ae3993fbd8 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -123,6 +123,7 @@ module Rails
# Currently stores:
#
# * "action_dispatch.parameter_filter" => config.filter_parameters
+ # * "action_dispatch.secret_token" => config.secret_token,
# * "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions
# * "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local
# * "action_dispatch.logger" => Rails.logger
@@ -148,6 +149,7 @@ module Rails
super.merge({
"action_dispatch.parameter_filter" => config.filter_parameters,
+ "action_dispatch.secret_token" => config.secret_token,
"action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions,
"action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local,
"action_dispatch.logger" => Rails.logger,
diff --git a/railties/test/application/middleware/session_test.rb b/railties/test/application/middleware/session_test.rb
index 9c0b143b74..a5fdfbf887 100644
--- a/railties/test/application/middleware/session_test.rb
+++ b/railties/test/application/middleware/session_test.rb
@@ -177,5 +177,115 @@ module ApplicationTests
get '/foo/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
+ 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_session
+ session[:foo] = 1
+ render nothing: true
+ end
+
+ def read_session
+ render text: session[:foo]
+ end
+
+ def read_encrypted_cookie
+ render text: cookies.encrypted[:_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.session_store :upgrade_signature_to_encryption_cookie_store, key: '_myapp_session'
+ RUBY
+
+ require "#{app_path}/config/environment"
+
+ 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
+
+ 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)
+
+ get '/foo/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
+ 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_encrypted_cookie
+ render text: cookies.encrypted[:_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.session_store :upgrade_signature_to_encryption_cookie_store, key: '_myapp_session'
+ 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_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)
+
+ get '/foo/read_raw_cookie'
+ assert_equal 2, encryptor.decrypt_and_verify(last_response.body)['foo']
+ end
end
end