Rename config.cookie_secret to config.secret_token and pass it as configuration in request.env. This is another step forward removing global configuration.
This commit is contained in:
parent
5c8b4c6e23
commit
6690d66292
3
Gemfile
3
Gemfile
@ -1,8 +1,7 @@
|
||||
path File.dirname(__FILE__)
|
||||
source 'http://rubygems.org'
|
||||
|
||||
gem "arel", :git => "git://github.com/rails/arel.git"
|
||||
gem "rails", "3.0.0.beta2"
|
||||
gem "rails", :path => File.dirname(__FILE__)
|
||||
|
||||
gem "rake", ">= 0.8.7"
|
||||
gem "mocha", ">= 0.9.8"
|
||||
|
@ -2,7 +2,7 @@ module ActionController
|
||||
class Base < Metal
|
||||
abstract!
|
||||
|
||||
def self.modules_without(*modules)
|
||||
def self.without_modules(*modules)
|
||||
modules = modules.map do |m|
|
||||
m.is_a?(Symbol) ? ActionController.const_get(m) : m
|
||||
end
|
||||
|
@ -77,14 +77,11 @@ def ip_spoofing_check
|
||||
|
||||
def cookie_verifier_secret=(value)
|
||||
ActiveSupport::Deprecation.warn "ActionController::Base.cookie_verifier_secret= is deprecated. " <<
|
||||
"Please configure it on your application with config.cookie_secret=", caller
|
||||
ActionController::Base.config.secret = value
|
||||
"Please configure it on your application with config.secret_token=", caller
|
||||
end
|
||||
|
||||
def cookie_verifier_secret
|
||||
ActiveSupport::Deprecation.warn "ActionController::Base.cookie_verifier_secret is deprecated. " <<
|
||||
"Please use ActionController::Base.config.secret instead.", caller
|
||||
ActionController::Base.config.secret
|
||||
ActiveSupport::Deprecation.warn "ActionController::Base.cookie_verifier_secret is deprecated.", caller
|
||||
end
|
||||
|
||||
def trusted_proxies=(value)
|
||||
|
@ -10,8 +10,7 @@ module Cookies
|
||||
|
||||
private
|
||||
def cookies
|
||||
raise "You must set config.cookie_secret in your app's config" if config.secret.blank?
|
||||
request.cookie_jar(:signing_secret => config.secret)
|
||||
request.cookie_jar
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -159,7 +159,7 @@ def authenticate_or_request_with_http_digest(realm = "Application", &password_pr
|
||||
|
||||
# Authenticate with HTTP Digest, returns true or false
|
||||
def authenticate_with_http_digest(realm = "Application", &password_procedure)
|
||||
HttpAuthentication::Digest.authenticate(config.secret, request, realm, &password_procedure)
|
||||
HttpAuthentication::Digest.authenticate(request, realm, &password_procedure)
|
||||
end
|
||||
|
||||
# Render output including the HTTP Digest authentication header
|
||||
@ -169,14 +169,15 @@ def request_http_digest_authentication(realm = "Application", message = nil)
|
||||
end
|
||||
|
||||
# Returns false on a valid response, true otherwise
|
||||
def authenticate(secret_key, request, realm, &password_procedure)
|
||||
request.authorization && validate_digest_response(secret_key, request, realm, &password_procedure)
|
||||
def authenticate(request, realm, &password_procedure)
|
||||
request.authorization && validate_digest_response(request, realm, &password_procedure)
|
||||
end
|
||||
|
||||
# Returns false unless the request credentials response value matches the expected value.
|
||||
# First try the password as a ha1 digest password. If this fails, then try it as a plain
|
||||
# text password.
|
||||
def validate_digest_response(secret_key, request, realm, &password_procedure)
|
||||
def validate_digest_response(request, realm, &password_procedure)
|
||||
secret_key = secret_token(request)
|
||||
credentials = decode_credentials_header(request)
|
||||
valid_nonce = validate_nonce(secret_key, request, credentials[:nonce])
|
||||
|
||||
@ -225,7 +226,7 @@ def decode_credentials(header)
|
||||
end
|
||||
|
||||
def authentication_header(controller, realm)
|
||||
secret_key = controller.config.secret
|
||||
secret_key = secret_token(controller.request)
|
||||
nonce = self.nonce(secret_key)
|
||||
opaque = opaque(secret_key)
|
||||
controller.headers["WWW-Authenticate"] = %(Digest realm="#{realm}", qop="auth", algorithm=MD5, nonce="#{nonce}", opaque="#{opaque}")
|
||||
@ -238,6 +239,12 @@ def authentication_request(controller, realm, message = nil)
|
||||
controller.status = 401
|
||||
end
|
||||
|
||||
def secret_token(request)
|
||||
secret = request.env["action_dispatch.secret_token"]
|
||||
raise "You must set config.secret_token in your app's config" if secret.blank?
|
||||
secret
|
||||
end
|
||||
|
||||
# Uses an MD5 digest based on time to generate a value to be used only once.
|
||||
#
|
||||
# A server-specified data string which should be uniquely generated each time a 401 response is made.
|
||||
|
@ -51,7 +51,6 @@ class Railtie < Rails::Railtie
|
||||
ac.assets_dir = paths.public.to_a.first
|
||||
ac.javascripts_dir = paths.public.javascripts.to_a.first
|
||||
ac.stylesheets_dir = paths.public.stylesheets.to_a.first
|
||||
ac.secret = app.config.cookie_secret
|
||||
|
||||
ActiveSupport.on_load(:action_controller) do
|
||||
self.config.merge!(ac)
|
||||
|
@ -1,7 +1,9 @@
|
||||
require "active_support/core_ext/object/blank"
|
||||
|
||||
module ActionDispatch
|
||||
class Request
|
||||
def cookie_jar(config = {})
|
||||
env['action_dispatch.cookies'] ||= Cookies::CookieJar.build(self, config)
|
||||
def cookie_jar
|
||||
env['action_dispatch.cookies'] ||= Cookies::CookieJar.build(self)
|
||||
end
|
||||
end
|
||||
|
||||
@ -51,17 +53,17 @@ def cookie_jar(config = {})
|
||||
# only HTTP. Defaults to +false+.
|
||||
class Cookies
|
||||
class CookieJar < Hash #:nodoc:
|
||||
def self.build(request, config = {})
|
||||
new(config).tap do |hash|
|
||||
def self.build(request)
|
||||
secret = request.env["action_dispatch.secret_token"]
|
||||
new(secret).tap do |hash|
|
||||
hash.update(request.cookies)
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(config = {})
|
||||
@config = config
|
||||
def initialize(secret=nil)
|
||||
@secret = secret
|
||||
@set_cookies = {}
|
||||
@delete_cookies = {}
|
||||
|
||||
super()
|
||||
end
|
||||
|
||||
@ -112,7 +114,7 @@ def delete(key, options = {})
|
||||
# cookies.permanent.signed[:remember_me] = current_user.id
|
||||
# # => Set-Cookie: discount=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
|
||||
def permanent
|
||||
@permanent ||= PermanentCookieJar.new(self, @config)
|
||||
@permanent ||= PermanentCookieJar.new(self, @secret)
|
||||
end
|
||||
|
||||
# Returns a jar that'll automatically generate a signed representation of cookie value and verify it when reading from
|
||||
@ -120,7 +122,7 @@ def permanent
|
||||
# cookie was tampered with by the user (or a 3rd party), an ActiveSupport::MessageVerifier::InvalidSignature exception will
|
||||
# be raised.
|
||||
#
|
||||
# This jar requires that you set a suitable secret for the verification on your app's config.cookie_secret.
|
||||
# This jar requires that you set a suitable secret for the verification on your app's config.secret_token.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
@ -129,7 +131,7 @@ def permanent
|
||||
#
|
||||
# cookies.signed[:discount] # => 45
|
||||
def signed
|
||||
@signed ||= SignedCookieJar.new(self, @config)
|
||||
@signed ||= SignedCookieJar.new(self, @secret)
|
||||
end
|
||||
|
||||
def write(response)
|
||||
@ -139,9 +141,8 @@ def write(response)
|
||||
end
|
||||
|
||||
class PermanentCookieJar < CookieJar #:nodoc:
|
||||
def initialize(parent_jar, config = {})
|
||||
@parent_jar = parent_jar
|
||||
@config = config
|
||||
def initialize(parent_jar, secret)
|
||||
@parent_jar, @secret = parent_jar, secret
|
||||
end
|
||||
|
||||
def []=(key, options)
|
||||
@ -156,7 +157,7 @@ def []=(key, options)
|
||||
end
|
||||
|
||||
def signed
|
||||
@signed ||= SignedCookieJar.new(self, @config)
|
||||
@signed ||= SignedCookieJar.new(self, @secret)
|
||||
end
|
||||
|
||||
def method_missing(method, *arguments, &block)
|
||||
@ -165,11 +166,10 @@ def method_missing(method, *arguments, &block)
|
||||
end
|
||||
|
||||
class SignedCookieJar < CookieJar #:nodoc:
|
||||
def initialize(parent_jar, config = {})
|
||||
raise 'Missing cookie signing secret' if config[:signing_secret].blank?
|
||||
def initialize(parent_jar, secret)
|
||||
raise "You must set config.secret_token in your app's config" if secret.blank?
|
||||
@parent_jar = parent_jar
|
||||
@config = config
|
||||
@verifier = ActiveSupport::MessageVerifier.new(config[:signing_secret])
|
||||
@verifier = ActiveSupport::MessageVerifier.new(secret)
|
||||
end
|
||||
|
||||
def [](name)
|
||||
|
@ -192,7 +192,7 @@ def ensure_secret_secure(secret)
|
||||
if secret.blank?
|
||||
raise ArgumentError, "A secret is required to generate an " +
|
||||
"integrity hash for cookie session data. Use " +
|
||||
"config.cookie_secret = \"some secret phrase of at " +
|
||||
"config.secret_token = \"some secret phrase of at " +
|
||||
"least #{SECRET_MIN_LENGTH} characters\"" +
|
||||
"in config/application.rb"
|
||||
end
|
||||
|
@ -1,4 +1,5 @@
|
||||
require 'active_support/core_ext/object/blank'
|
||||
require 'active_support/core_ext/hash/reverse_merge'
|
||||
|
||||
module ActionDispatch
|
||||
class TestRequest < Request
|
||||
@ -9,6 +10,7 @@ def self.new(env = {})
|
||||
end
|
||||
|
||||
def initialize(env = {})
|
||||
env = Rails.application.env_defaults.merge(env) if defined?(Rails.application)
|
||||
super(DEFAULT_ENV.merge(env))
|
||||
|
||||
self.host = 'test.host'
|
||||
|
@ -192,10 +192,6 @@ def with_routing(&block)
|
||||
|
||||
# Temporary base class
|
||||
class Rack::TestCase < ActionController::IntegrationTest
|
||||
setup do
|
||||
ActionController::Base.config.secret = "abc" * 30
|
||||
end
|
||||
|
||||
def self.testing(klass = nil)
|
||||
if klass
|
||||
@testing = "/#{klass.name.underscore}".sub!(/_controller$/, '')
|
||||
|
@ -1,7 +1,5 @@
|
||||
require 'abstract_unit'
|
||||
|
||||
ActionController::Base.config.secret = "thisISverySECRET123"
|
||||
|
||||
class CookieTest < ActionController::TestCase
|
||||
class TestController < ActionController::Base
|
||||
def authenticate
|
||||
@ -76,6 +74,7 @@ def delete_and_set_cookie
|
||||
|
||||
def setup
|
||||
super
|
||||
@request.env["action_dispatch.secret_token"] = "thisISverySECRET123"
|
||||
@request.host = "www.nextangle.com"
|
||||
end
|
||||
|
||||
|
@ -41,8 +41,7 @@ def authenticate_with_request
|
||||
setup do
|
||||
# Used as secret in generating nonce to prevent tampering of timestamp
|
||||
@secret = "session_options_secret"
|
||||
@controller.config.secret = @secret
|
||||
# @old_secret, ActionController::Base.config.secret[:secret] = ActionController::Base.session_options[:secret], @secret
|
||||
@request.env["action_dispatch.secret_token"] = @secret
|
||||
end
|
||||
|
||||
teardown do
|
||||
@ -206,7 +205,7 @@ def authenticate_with_request
|
||||
|
||||
test "validate_digest_response should fail with nil returning password_procedure" do
|
||||
@request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => nil, :password => nil)
|
||||
assert !ActionController::HttpAuthentication::Digest.validate_digest_response(@secret, @request, "SuperSecret"){nil}
|
||||
assert !ActionController::HttpAuthentication::Digest.validate_digest_response(@request, "SuperSecret"){nil}
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -1,3 +1,5 @@
|
||||
* Renamed config.cookie_secret to config.secret_token and pass it as env key. [JV]
|
||||
|
||||
*Rails 3.0.0 [beta 2] (April 1st, 2010)*
|
||||
|
||||
* Session store configuration has changed [YK & CL]
|
||||
@ -6,12 +8,11 @@
|
||||
config.cookie_secret = "fdsfhisdghfidugnfdlg"
|
||||
|
||||
* railtie_name and engine_name are deprecated. You can now add any object to
|
||||
the configuration object: config.your_plugin = {} [JK]
|
||||
the configuration object: config.your_plugin = {} [JV]
|
||||
|
||||
* Added config.generators.templates to provide alternative paths for the generators
|
||||
to look for templates [JV]
|
||||
|
||||
|
||||
*Rails 3.0.0 [beta 1] (February 4, 2010)*
|
||||
|
||||
* Added "rake about" as a replacement for script/about [DHH]
|
||||
|
@ -1,3 +1,4 @@
|
||||
require 'active_support/core_ext/hash/reverse_merge'
|
||||
require 'fileutils'
|
||||
require 'rails/plugin'
|
||||
require 'rails/engine'
|
||||
@ -128,8 +129,14 @@ def app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
env["action_dispatch.parameter_filter"] = config.filter_parameters
|
||||
app.call(env)
|
||||
app.call(env.reverse_merge!(env_defaults))
|
||||
end
|
||||
|
||||
def env_defaults
|
||||
@env_defaults ||= {
|
||||
"action_dispatch.parameter_filter" => config.filter_parameters,
|
||||
"action_dispatch.secret_token" => config.secret_token
|
||||
}
|
||||
end
|
||||
|
||||
def initializers
|
||||
|
@ -6,7 +6,7 @@ class Configuration < ::Rails::Engine::Configuration
|
||||
include ::Rails::Configuration::Deprecated
|
||||
|
||||
attr_accessor :allow_concurrency, :cache_classes, :cache_store,
|
||||
:cookie_secret, :consider_all_requests_local, :dependency_loading,
|
||||
:secret_token, :consider_all_requests_local, :dependency_loading,
|
||||
:filter_parameters, :log_level, :logger, :metals,
|
||||
:plugins, :preload_frameworks, :reload_engines, :reload_plugins,
|
||||
:serve_static_assets, :time_zone, :whiny_nils
|
||||
@ -37,6 +37,7 @@ def paths
|
||||
paths.app.controllers << builtin_controller if builtin_controller
|
||||
paths.config.database "config/database.yml"
|
||||
paths.config.environment "config/environments", :glob => "#{Rails.env}.rb"
|
||||
paths.lib.templates "lib/templates"
|
||||
paths.log "log/#{Rails.env}.log"
|
||||
paths.tmp "tmp"
|
||||
paths.tmp.cache "tmp/cache"
|
||||
@ -123,7 +124,7 @@ def session_store(*args)
|
||||
|
||||
def session_options
|
||||
return @session_options unless @session_store == :cookie_store
|
||||
@session_options.merge(:secret => @cookie_secret)
|
||||
@session_options.merge(:secret => @secret_token)
|
||||
end
|
||||
|
||||
def default_middleware_stack
|
||||
|
@ -3,6 +3,10 @@ class Application
|
||||
module Finisher
|
||||
include Initializable
|
||||
|
||||
initializer :add_generator_templates do
|
||||
config.generators.templates.unshift(*paths.lib.templates.to_a)
|
||||
end
|
||||
|
||||
initializer :ensure_load_once_paths_as_subset do
|
||||
extra = ActiveSupport::Dependencies.load_once_paths -
|
||||
ActiveSupport::Dependencies.load_paths
|
||||
|
@ -104,6 +104,18 @@ def controller_paths
|
||||
"please do paths.app.controllers instead", caller
|
||||
paths.app.controllers.to_a.uniq
|
||||
end
|
||||
|
||||
def cookie_secret=(value)
|
||||
ActiveSupport::Deprecation.warn "config.cookie_secret= is deprecated, " <<
|
||||
"please use config.secret_token= instead", caller
|
||||
self.secret_token = value
|
||||
end
|
||||
|
||||
def cookie_secret
|
||||
ActiveSupport::Deprecation.warn "config.cookie_secret is deprecated, " <<
|
||||
"please use config.secret_token instead", caller
|
||||
self.secret_token
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -193,17 +193,13 @@ def load_tasks
|
||||
app.metal_loader.paths.unshift(*paths.app.metals.to_a)
|
||||
end
|
||||
|
||||
initializer :add_generator_templates do |app|
|
||||
config.generators.templates.unshift(*paths.lib.templates.to_a)
|
||||
end
|
||||
|
||||
initializer :load_application_initializers do
|
||||
initializer :load_config_initializers do
|
||||
paths.config.initializers.to_a.sort.each do |initializer|
|
||||
load(initializer)
|
||||
end
|
||||
end
|
||||
|
||||
initializer :load_application_classes do |app|
|
||||
initializer :load_app_classes do |app|
|
||||
next if $rails_rake_task
|
||||
|
||||
if app.config.cache_classes
|
||||
|
@ -23,7 +23,6 @@ def paths
|
||||
paths.app.views "app/views", :eager_load => true
|
||||
paths.lib "lib", :load_path => true
|
||||
paths.lib.tasks "lib/tasks", :glob => "**/*.rake"
|
||||
paths.lib.templates "lib/templates"
|
||||
paths.config "config"
|
||||
paths.config.initializers "config/initializers", :glob => "**/*.rb"
|
||||
paths.config.locales "config/locales", :glob => "*.{rb,yml}"
|
||||
|
@ -4,4 +4,4 @@
|
||||
# If you change this key, all old signed cookies will become invalid!
|
||||
# Make sure the secret is at least 30 characters and all random,
|
||||
# no regular words or you'll be exposed to dictionary attacks.
|
||||
Rails.application.config.cookie_secret = '<%= app_secret %>'
|
||||
Rails.application.config.secret_token = '<%= app_secret %>'
|
@ -1,8 +1,6 @@
|
||||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
Rails.application.config.session_store :cookie_store, {
|
||||
:key => '_<%= app_name %>_session',
|
||||
}
|
||||
Rails.application.config.session_store :cookie_store, :key => '_<%= app_name %>_session'
|
||||
|
||||
# Use the database for sessions instead of the cookie-based default,
|
||||
# which shouldn't be used to store highly confidential information
|
||||
|
@ -61,7 +61,7 @@ def config
|
||||
@config ||= Engine::Configuration.new
|
||||
end
|
||||
|
||||
initializer :load_init_rb, :before => :load_application_initializers do |app|
|
||||
initializer :load_init_rb, :before => :load_config_initializers do |app|
|
||||
files = %w(rails/init.rb init.rb).map { |path| File.expand_path path, root }
|
||||
if initrb = files.find { |path| File.file? path }
|
||||
if initrb == files.first
|
||||
|
@ -234,6 +234,22 @@ def index
|
||||
assert_equal File.expand_path(__FILE__), last_response.headers["X-Lighttpd-Send-File"]
|
||||
end
|
||||
|
||||
test "config.secret_token is sent in env" do
|
||||
make_basic_app do |app|
|
||||
app.config.secret_token = 'ThisIsASECRET123'
|
||||
end
|
||||
|
||||
class ::OmgController < ActionController::Base
|
||||
def index
|
||||
cookies.signed[:some_key] = "some_value"
|
||||
render :text => env["action_dispatch.secret_token"]
|
||||
end
|
||||
end
|
||||
|
||||
get "/"
|
||||
assert_equal 'ThisIsASECRET123', last_response.body
|
||||
end
|
||||
|
||||
test "protect from forgery is the default in a new app" do
|
||||
make_basic_app
|
||||
|
||||
|
@ -10,7 +10,7 @@ def setup
|
||||
|
||||
Object.const_set(:MyApplication, Class.new(Rails::Application))
|
||||
MyApplication.class_eval do
|
||||
config.cookie_secret = "3b7cd727ee24e8444053437c36cc66c4"
|
||||
config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
|
||||
config.session_store :cookie_store, :key => "_myapp_session"
|
||||
end
|
||||
end
|
||||
|
@ -14,7 +14,7 @@ def app
|
||||
require "action_controller/railtie"
|
||||
|
||||
class MyApp < Rails::Application
|
||||
config.cookie_secret = "3b7cd727ee24e8444053437c36cc66c4"
|
||||
config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
|
||||
config.session_store :cookie_store, :key => "_myapp_session"
|
||||
end
|
||||
|
||||
|
@ -100,7 +100,7 @@ def build_app(options = {})
|
||||
end
|
||||
end
|
||||
|
||||
add_to_config 'config.cookie_secret = "3b7cd727ee24e8444053437c36cc66c4"; config.session_store :cookie_store, :key => "_myapp_session"'
|
||||
add_to_config 'config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"; config.session_store :cookie_store, :key => "_myapp_session"'
|
||||
end
|
||||
|
||||
class Bukkit
|
||||
|
Loading…
Reference in New Issue
Block a user