diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb index 1537b8b806..d3b5bafee1 100644 --- a/actionpack/lib/action_controller/metal/http_authentication.rb +++ b/actionpack/lib/action_controller/metal/http_authentication.rb @@ -249,8 +249,9 @@ module ActionController end def secret_token(request) - key_generator = request.env["action_dispatch.key_generator"] - key_generator.generate_key('http authentication') + key_generator = request.env["action_dispatch.key_generator"] + http_auth_salt = request.env["action_dispatch.http_auth_salt"] + key_generator.generate_key(http_auth_salt) end # Uses an MD5 digest based on time to generate a value to be used only once. diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index 7206306b94..daad64d041 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -82,6 +82,10 @@ module ActionDispatch class Cookies HTTP_HEADER = "Set-Cookie".freeze GENERATOR_KEY = "action_dispatch.key_generator".freeze + 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 + # Raised when storing more than 4K of session data. CookieOverflow = Class.new StandardError @@ -106,21 +110,25 @@ module ActionDispatch def self.build(request) env = request.env 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] } host = request.host secure = request.ssl? - new(key_generator, host, secure).tap do |hash| + new(key_generator, host, secure, options).tap do |hash| hash.update(request.cookies) end end - def initialize(key_generator, host = nil, secure = false) + def initialize(key_generator, host = nil, secure = false, options = {}) @key_generator = key_generator @set_cookies = {} @delete_cookies = {} @host = host @secure = secure + @options = options @cookies = {} end @@ -223,7 +231,7 @@ module ActionDispatch # cookies.permanent.signed[:remember_me] = current_user.id # # => Set-Cookie: remember_me=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT def permanent - @permanent ||= PermanentCookieJar.new(self, @key_generator) + @permanent ||= PermanentCookieJar.new(self, @key_generator, @options) end # Returns a jar that'll automatically generate a signed representation of cookie value and verify it when reading from @@ -240,7 +248,7 @@ module ActionDispatch # # cookies.signed[:discount] # => 45 def signed - @signed ||= SignedCookieJar.new(self, @key_generator) + @signed ||= SignedCookieJar.new(self, @key_generator, @options) end # Returns a jar that'll automatically encrypt cookie values before sending them to the client and will decrypt them for read. @@ -256,7 +264,7 @@ module ActionDispatch # # cookies.encrypted[:discount] # => 45 def encrypted - @encrypted ||= EncryptedCookieJar.new(self, @key_generator) + @encrypted ||= EncryptedCookieJar.new(self, @key_generator, @options) end def write(headers) @@ -280,9 +288,10 @@ module ActionDispatch end class PermanentCookieJar < CookieJar #:nodoc: - def initialize(parent_jar, key_generator) + def initialize(parent_jar, key_generator, options = {}) @parent_jar = parent_jar @key_generator = key_generator + @options = options end def []=(key, options) @@ -305,9 +314,10 @@ module ActionDispatch MAX_COOKIE_SIZE = 4096 # Cookies can typically store 4096 bytes. SECRET_MIN_LENGTH = 30 # Characters - def initialize(parent_jar, key_generator) + def initialize(parent_jar, key_generator, options = {}) @parent_jar = parent_jar - secret = key_generator.generate_key('signed cookie') + @options = options + secret = key_generator.generate_key(@options[:signed_cookie_salt]) ensure_secret_secure(secret) @verifier = ActiveSupport::MessageVerifier.new(secret) end @@ -359,10 +369,11 @@ module ActionDispatch end class EncryptedCookieJar < SignedCookieJar #:nodoc: - def initialize(parent_jar, key_generator) + def initialize(parent_jar, key_generator, options = {}) @parent_jar = parent_jar - secret = key_generator.generate_key('encrypted cookie') - sign_secret = key_generator.generate_key('signed encrypted cookie') + @options = options + secret = key_generator.generate_key(@options[:encrypted_cookie_salt]) + sign_secret = key_generator.generate_key(@options[:encrypted_signed_cookie_salt]) @encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret) ensure_secret_secure(secret) end diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb index 284dd180db..98c87d9b2d 100644 --- a/actionpack/lib/action_dispatch/railtie.rb +++ b/actionpack/lib/action_dispatch/railtie.rb @@ -13,6 +13,10 @@ module ActionDispatch config.action_dispatch.rescue_responses = { } config.action_dispatch.default_charset = nil config.action_dispatch.rack_cache = false + config.action_dispatch.http_auth_salt = 'http authentication' + config.action_dispatch.signed_cookie_salt = 'signed cookie' + config.action_dispatch.encrypted_cookie_salt = 'encrypted cookie' + config.action_dispatch.encrypted_signed_cookie_salt = 'signed encrypted cookie' config.action_dispatch.default_headers = { 'X-Frame-Options' => 'SAMEORIGIN', diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb index 0b6f4cb03f..ffa91d63c4 100644 --- a/actionpack/test/dispatch/cookies_test.rb +++ b/actionpack/test/dispatch/cookies_test.rb @@ -153,7 +153,10 @@ class CookiesTest < ActionController::TestCase def setup super - @request.env["action_dispatch.key_generator"] = ActiveSupport::DummyKeyGenerator.new("b3c631c314c0bbca50c1b2843150fe33") + @request.env["action_dispatch.key_generator"] = ActiveSupport::KeyGenerator.new("b3c631c314c0bbca50c1b2843150fe33") + @request.env["action_dispatch.signed_cookie_salt"] = "b3c631c314c0bbca50c1b2843150fe33" + @request.env["action_dispatch.encrypted_cookie_salt"] = "b3c631c314c0bbca50c1b2843150fe33" + @request.env["action_dispatch.encrypted_signed_cookie_salt"] = "b3c631c314c0bbca50c1b2843150fe33" @request.host = "www.nextangle.com" end diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index f9867721a2..3ec29e1dd6 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -119,12 +119,16 @@ module Rails # will be used by middlewares and engines to configure themselves. # Currently stores: # - # * "action_dispatch.parameter_filter" => config.filter_parameters, - # * "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions, - # * "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local, - # * "action_dispatch.logger" => Rails.logger, - # * "action_dispatch.backtrace_cleaner" => Rails.backtrace_cleaner - # * "action_dispatch.key_generator" => key_generator + # * "action_dispatch.parameter_filter" => config.filter_parameters + # * "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions + # * "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local + # * "action_dispatch.logger" => Rails.logger + # * "action_dispatch.backtrace_cleaner" => Rails.backtrace_cleaner + # * "action_dispatch.key_generator" => key_generator + # * "action_dispatch.http_auth_salt" => config.action_dispatch.http_auth_salt + # * "action_dispatch.signed_cookie_salt" => config.action_dispatch.signed_cookie_salt + # * "action_dispatch.encrypted_cookie_salt" => config.action_dispatch.encrypted_cookie_salt + # * "action_dispatch.encrypted_signed_cookie_salt" => config.action_dispatch.encrypted_signed_cookie_salt # # These parameters will be used by middlewares and engines to configure themselves # @@ -145,7 +149,11 @@ module Rails "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local, "action_dispatch.logger" => Rails.logger, "action_dispatch.backtrace_cleaner" => Rails.backtrace_cleaner, - "action_dispatch.key_generator" => key_generator + "action_dispatch.key_generator" => key_generator, + "action_dispatch.http_auth_salt" => config.action_dispatch.http_auth_salt, + "action_dispatch.signed_cookie_salt" => config.action_dispatch.signed_cookie_salt, + "action_dispatch.encrypted_cookie_salt" => config.action_dispatch.encrypted_cookie_salt, + "action_dispatch.encrypted_signed_cookie_salt" => config.action_dispatch.encrypted_signed_cookie_salt }) end end