Skip to content

Commit

Permalink
Rename config.cookie_secret to config.secret_token and pass it as con…
Browse files Browse the repository at this point in the history
…figuration in request.env. This is another step forward removing global configuration.
  • Loading branch information
josevalim committed Apr 5, 2010
1 parent 5c8b4c6 commit 6690d66
Show file tree
Hide file tree
Showing 26 changed files with 96 additions and 65 deletions.
3 changes: 1 addition & 2 deletions Gemfile
@@ -1,8 +1,7 @@
path File.dirname(__FILE__)
source 'http://rubygems.org' source 'http://rubygems.org'


gem "arel", :git => "git://github.com/rails/arel.git" 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 "rake", ">= 0.8.7"
gem "mocha", ">= 0.9.8" gem "mocha", ">= 0.9.8"
Expand Down
2 changes: 1 addition & 1 deletion actionpack/lib/action_controller/base.rb
Expand Up @@ -2,7 +2,7 @@ module ActionController
class Base < Metal class Base < Metal
abstract! abstract!


def self.modules_without(*modules) def self.without_modules(*modules)
modules = modules.map do |m| modules = modules.map do |m|
m.is_a?(Symbol) ? ActionController.const_get(m) : m m.is_a?(Symbol) ? ActionController.const_get(m) : m
end end
Expand Down
7 changes: 2 additions & 5 deletions actionpack/lib/action_controller/deprecated/base.rb
Expand Up @@ -77,14 +77,11 @@ def ip_spoofing_check


def cookie_verifier_secret=(value) def cookie_verifier_secret=(value)
ActiveSupport::Deprecation.warn "ActionController::Base.cookie_verifier_secret= is deprecated. " << ActiveSupport::Deprecation.warn "ActionController::Base.cookie_verifier_secret= is deprecated. " <<
"Please configure it on your application with config.cookie_secret=", caller "Please configure it on your application with config.secret_token=", caller
ActionController::Base.config.secret = value
end end


def cookie_verifier_secret def cookie_verifier_secret
ActiveSupport::Deprecation.warn "ActionController::Base.cookie_verifier_secret is deprecated. " << ActiveSupport::Deprecation.warn "ActionController::Base.cookie_verifier_secret is deprecated.", caller
"Please use ActionController::Base.config.secret instead.", caller
ActionController::Base.config.secret
end end


def trusted_proxies=(value) def trusted_proxies=(value)
Expand Down
3 changes: 1 addition & 2 deletions actionpack/lib/action_controller/metal/cookies.rb
Expand Up @@ -10,8 +10,7 @@ module Cookies


private private
def cookies def cookies
raise "You must set config.cookie_secret in your app's config" if config.secret.blank? request.cookie_jar
request.cookie_jar(:signing_secret => config.secret)
end end
end end
end end
17 changes: 12 additions & 5 deletions actionpack/lib/action_controller/metal/http_authentication.rb
Expand Up @@ -159,7 +159,7 @@ def authenticate_or_request_with_http_digest(realm = "Application", &password_pr


# Authenticate with HTTP Digest, returns true or false # Authenticate with HTTP Digest, returns true or false
def authenticate_with_http_digest(realm = "Application", &password_procedure) 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 end


# Render output including the HTTP Digest authentication header # Render output including the HTTP Digest authentication header
Expand All @@ -169,14 +169,15 @@ def request_http_digest_authentication(realm = "Application", message = nil)
end end


# Returns false on a valid response, true otherwise # Returns false on a valid response, true otherwise
def authenticate(secret_key, request, realm, &password_procedure) def authenticate(request, realm, &password_procedure)
request.authorization && validate_digest_response(secret_key, request, realm, &password_procedure) request.authorization && validate_digest_response(request, realm, &password_procedure)
end end


# Returns false unless the request credentials response value matches the expected value. # 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 # First try the password as a ha1 digest password. If this fails, then try it as a plain
# text password. # 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) credentials = decode_credentials_header(request)
valid_nonce = validate_nonce(secret_key, request, credentials[:nonce]) valid_nonce = validate_nonce(secret_key, request, credentials[:nonce])


Expand Down Expand Up @@ -225,7 +226,7 @@ def decode_credentials(header)
end end


def authentication_header(controller, realm) def authentication_header(controller, realm)
secret_key = controller.config.secret secret_key = secret_token(controller.request)
nonce = self.nonce(secret_key) nonce = self.nonce(secret_key)
opaque = opaque(secret_key) opaque = opaque(secret_key)
controller.headers["WWW-Authenticate"] = %(Digest realm="#{realm}", qop="auth", algorithm=MD5, nonce="#{nonce}", opaque="#{opaque}") controller.headers["WWW-Authenticate"] = %(Digest realm="#{realm}", qop="auth", algorithm=MD5, nonce="#{nonce}", opaque="#{opaque}")
Expand All @@ -238,6 +239,12 @@ def authentication_request(controller, realm, message = nil)
controller.status = 401 controller.status = 401
end 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. # 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. # A server-specified data string which should be uniquely generated each time a 401 response is made.
Expand Down
1 change: 0 additions & 1 deletion actionpack/lib/action_controller/railtie.rb
Expand Up @@ -51,7 +51,6 @@ class Railtie < Rails::Railtie
ac.assets_dir = paths.public.to_a.first ac.assets_dir = paths.public.to_a.first
ac.javascripts_dir = paths.public.javascripts.to_a.first ac.javascripts_dir = paths.public.javascripts.to_a.first
ac.stylesheets_dir = paths.public.stylesheets.to_a.first ac.stylesheets_dir = paths.public.stylesheets.to_a.first
ac.secret = app.config.cookie_secret


ActiveSupport.on_load(:action_controller) do ActiveSupport.on_load(:action_controller) do
self.config.merge!(ac) self.config.merge!(ac)
Expand Down
36 changes: 18 additions & 18 deletions actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -1,7 +1,9 @@
require "active_support/core_ext/object/blank"

module ActionDispatch module ActionDispatch
class Request class Request
def cookie_jar(config = {}) def cookie_jar
env['action_dispatch.cookies'] ||= Cookies::CookieJar.build(self, config) env['action_dispatch.cookies'] ||= Cookies::CookieJar.build(self)
end end
end end


Expand Down Expand Up @@ -51,17 +53,17 @@ def cookie_jar(config = {})
# only HTTP. Defaults to +false+. # only HTTP. Defaults to +false+.
class Cookies class Cookies
class CookieJar < Hash #:nodoc: class CookieJar < Hash #:nodoc:
def self.build(request, config = {}) def self.build(request)
new(config).tap do |hash| secret = request.env["action_dispatch.secret_token"]
new(secret).tap do |hash|
hash.update(request.cookies) hash.update(request.cookies)
end end
end end


def initialize(config = {}) def initialize(secret=nil)
@config = config @secret = secret
@set_cookies = {} @set_cookies = {}
@delete_cookies = {} @delete_cookies = {}

super() super()
end end


Expand Down Expand Up @@ -112,15 +114,15 @@ def delete(key, options = {})
# cookies.permanent.signed[:remember_me] = current_user.id # cookies.permanent.signed[:remember_me] = current_user.id
# # => Set-Cookie: discount=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT # # => Set-Cookie: discount=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
def permanent def permanent
@permanent ||= PermanentCookieJar.new(self, @config) @permanent ||= PermanentCookieJar.new(self, @secret)
end end


# Returns a jar that'll automatically generate a signed representation of cookie value and verify it when reading from # Returns a jar that'll automatically generate a signed representation of cookie value and verify it when reading from
# the cookie again. This is useful for creating cookies with values that the user is not supposed to change. If a signed # 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), an ActiveSupport::MessageVerifier::InvalidSignature exception will # cookie was tampered with by the user (or a 3rd party), an ActiveSupport::MessageVerifier::InvalidSignature exception will
# be raised. # 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: # Example:
# #
Expand All @@ -129,7 +131,7 @@ def permanent
# #
# cookies.signed[:discount] # => 45 # cookies.signed[:discount] # => 45
def signed def signed
@signed ||= SignedCookieJar.new(self, @config) @signed ||= SignedCookieJar.new(self, @secret)
end end


def write(response) def write(response)
Expand All @@ -139,9 +141,8 @@ def write(response)
end end


class PermanentCookieJar < CookieJar #:nodoc: class PermanentCookieJar < CookieJar #:nodoc:
def initialize(parent_jar, config = {}) def initialize(parent_jar, secret)
@parent_jar = parent_jar @parent_jar, @secret = parent_jar, secret
@config = config
end end


def []=(key, options) def []=(key, options)
Expand All @@ -156,7 +157,7 @@ def []=(key, options)
end end


def signed def signed
@signed ||= SignedCookieJar.new(self, @config) @signed ||= SignedCookieJar.new(self, @secret)
end end


def method_missing(method, *arguments, &block) def method_missing(method, *arguments, &block)
Expand All @@ -165,11 +166,10 @@ def method_missing(method, *arguments, &block)
end end


class SignedCookieJar < CookieJar #:nodoc: class SignedCookieJar < CookieJar #:nodoc:
def initialize(parent_jar, config = {}) def initialize(parent_jar, secret)
raise 'Missing cookie signing secret' if config[:signing_secret].blank? raise "You must set config.secret_token in your app's config" if secret.blank?
@parent_jar = parent_jar @parent_jar = parent_jar
@config = config @verifier = ActiveSupport::MessageVerifier.new(secret)
@verifier = ActiveSupport::MessageVerifier.new(config[:signing_secret])
end end


def [](name) def [](name)
Expand Down
Expand Up @@ -192,7 +192,7 @@ def ensure_secret_secure(secret)
if secret.blank? if secret.blank?
raise ArgumentError, "A secret is required to generate an " + raise ArgumentError, "A secret is required to generate an " +
"integrity hash for cookie session data. Use " + "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\"" + "least #{SECRET_MIN_LENGTH} characters\"" +
"in config/application.rb" "in config/application.rb"
end end
Expand Down
2 changes: 2 additions & 0 deletions actionpack/lib/action_dispatch/testing/test_request.rb
@@ -1,4 +1,5 @@
require 'active_support/core_ext/object/blank' require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/hash/reverse_merge'


module ActionDispatch module ActionDispatch
class TestRequest < Request class TestRequest < Request
Expand All @@ -9,6 +10,7 @@ def self.new(env = {})
end end


def initialize(env = {}) def initialize(env = {})
env = Rails.application.env_defaults.merge(env) if defined?(Rails.application)
super(DEFAULT_ENV.merge(env)) super(DEFAULT_ENV.merge(env))


self.host = 'test.host' self.host = 'test.host'
Expand Down
4 changes: 0 additions & 4 deletions actionpack/test/abstract_unit.rb
Expand Up @@ -192,10 +192,6 @@ def with_routing(&block)


# Temporary base class # Temporary base class
class Rack::TestCase < ActionController::IntegrationTest class Rack::TestCase < ActionController::IntegrationTest
setup do
ActionController::Base.config.secret = "abc" * 30
end

def self.testing(klass = nil) def self.testing(klass = nil)
if klass if klass
@testing = "/#{klass.name.underscore}".sub!(/_controller$/, '') @testing = "/#{klass.name.underscore}".sub!(/_controller$/, '')
Expand Down
3 changes: 1 addition & 2 deletions actionpack/test/controller/cookie_test.rb
@@ -1,7 +1,5 @@
require 'abstract_unit' require 'abstract_unit'


ActionController::Base.config.secret = "thisISverySECRET123"

class CookieTest < ActionController::TestCase class CookieTest < ActionController::TestCase
class TestController < ActionController::Base class TestController < ActionController::Base
def authenticate def authenticate
Expand Down Expand Up @@ -76,6 +74,7 @@ def delete_and_set_cookie


def setup def setup
super super
@request.env["action_dispatch.secret_token"] = "thisISverySECRET123"
@request.host = "www.nextangle.com" @request.host = "www.nextangle.com"
end end


Expand Down
5 changes: 2 additions & 3 deletions actionpack/test/controller/http_digest_authentication_test.rb
Expand Up @@ -41,8 +41,7 @@ def authenticate_with_request
setup do setup do
# Used as secret in generating nonce to prevent tampering of timestamp # Used as secret in generating nonce to prevent tampering of timestamp
@secret = "session_options_secret" @secret = "session_options_secret"
@controller.config.secret = @secret @request.env["action_dispatch.secret_token"] = @secret
# @old_secret, ActionController::Base.config.secret[:secret] = ActionController::Base.session_options[:secret], @secret
end end


teardown do teardown do
Expand Down Expand Up @@ -206,7 +205,7 @@ def authenticate_with_request


test "validate_digest_response should fail with nil returning password_procedure" do test "validate_digest_response should fail with nil returning password_procedure" do
@request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => nil, :password => nil) @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 end


private private
Expand Down
5 changes: 3 additions & 2 deletions railties/CHANGELOG
@@ -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)* *Rails 3.0.0 [beta 2] (April 1st, 2010)*


* Session store configuration has changed [YK & CL] * Session store configuration has changed [YK & CL]
Expand All @@ -6,12 +8,11 @@
config.cookie_secret = "fdsfhisdghfidugnfdlg" config.cookie_secret = "fdsfhisdghfidugnfdlg"


* railtie_name and engine_name are deprecated. You can now add any object to * 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 * Added config.generators.templates to provide alternative paths for the generators
to look for templates [JV] to look for templates [JV]



*Rails 3.0.0 [beta 1] (February 4, 2010)* *Rails 3.0.0 [beta 1] (February 4, 2010)*


* Added "rake about" as a replacement for script/about [DHH] * Added "rake about" as a replacement for script/about [DHH]
Expand Down
11 changes: 9 additions & 2 deletions railties/lib/rails/application.rb
@@ -1,3 +1,4 @@
require 'active_support/core_ext/hash/reverse_merge'
require 'fileutils' require 'fileutils'
require 'rails/plugin' require 'rails/plugin'
require 'rails/engine' require 'rails/engine'
Expand Down Expand Up @@ -128,8 +129,14 @@ def app
end end


def call(env) def call(env)
env["action_dispatch.parameter_filter"] = config.filter_parameters app.call(env.reverse_merge!(env_defaults))
app.call(env) end

def env_defaults
@env_defaults ||= {
"action_dispatch.parameter_filter" => config.filter_parameters,
"action_dispatch.secret_token" => config.secret_token
}
end end


def initializers def initializers
Expand Down
5 changes: 3 additions & 2 deletions railties/lib/rails/application/configuration.rb
Expand Up @@ -6,7 +6,7 @@ class Configuration < ::Rails::Engine::Configuration
include ::Rails::Configuration::Deprecated include ::Rails::Configuration::Deprecated


attr_accessor :allow_concurrency, :cache_classes, :cache_store, 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, :filter_parameters, :log_level, :logger, :metals,
:plugins, :preload_frameworks, :reload_engines, :reload_plugins, :plugins, :preload_frameworks, :reload_engines, :reload_plugins,
:serve_static_assets, :time_zone, :whiny_nils :serve_static_assets, :time_zone, :whiny_nils
Expand Down Expand Up @@ -37,6 +37,7 @@ def paths
paths.app.controllers << builtin_controller if builtin_controller paths.app.controllers << builtin_controller if builtin_controller
paths.config.database "config/database.yml" paths.config.database "config/database.yml"
paths.config.environment "config/environments", :glob => "#{Rails.env}.rb" paths.config.environment "config/environments", :glob => "#{Rails.env}.rb"
paths.lib.templates "lib/templates"
paths.log "log/#{Rails.env}.log" paths.log "log/#{Rails.env}.log"
paths.tmp "tmp" paths.tmp "tmp"
paths.tmp.cache "tmp/cache" paths.tmp.cache "tmp/cache"
Expand Down Expand Up @@ -123,7 +124,7 @@ def session_store(*args)


def session_options def session_options
return @session_options unless @session_store == :cookie_store return @session_options unless @session_store == :cookie_store
@session_options.merge(:secret => @cookie_secret) @session_options.merge(:secret => @secret_token)
end end


def default_middleware_stack def default_middleware_stack
Expand Down
4 changes: 4 additions & 0 deletions railties/lib/rails/application/finisher.rb
Expand Up @@ -3,6 +3,10 @@ class Application
module Finisher module Finisher
include Initializable 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 initializer :ensure_load_once_paths_as_subset do
extra = ActiveSupport::Dependencies.load_once_paths - extra = ActiveSupport::Dependencies.load_once_paths -
ActiveSupport::Dependencies.load_paths ActiveSupport::Dependencies.load_paths
Expand Down
12 changes: 12 additions & 0 deletions railties/lib/rails/configuration.rb
Expand Up @@ -104,6 +104,18 @@ def controller_paths
"please do paths.app.controllers instead", caller "please do paths.app.controllers instead", caller
paths.app.controllers.to_a.uniq paths.app.controllers.to_a.uniq
end 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 end
end end
8 changes: 2 additions & 6 deletions railties/lib/rails/engine.rb
Expand Up @@ -193,17 +193,13 @@ def load_tasks
app.metal_loader.paths.unshift(*paths.app.metals.to_a) app.metal_loader.paths.unshift(*paths.app.metals.to_a)
end end


initializer :add_generator_templates do |app| initializer :load_config_initializers do
config.generators.templates.unshift(*paths.lib.templates.to_a)
end

initializer :load_application_initializers do
paths.config.initializers.to_a.sort.each do |initializer| paths.config.initializers.to_a.sort.each do |initializer|
load(initializer) load(initializer)
end end
end end


initializer :load_application_classes do |app| initializer :load_app_classes do |app|
next if $rails_rake_task next if $rails_rake_task


if app.config.cache_classes if app.config.cache_classes
Expand Down
1 change: 0 additions & 1 deletion railties/lib/rails/engine/configuration.rb
Expand Up @@ -23,7 +23,6 @@ def paths
paths.app.views "app/views", :eager_load => true paths.app.views "app/views", :eager_load => true
paths.lib "lib", :load_path => true paths.lib "lib", :load_path => true
paths.lib.tasks "lib/tasks", :glob => "**/*.rake" paths.lib.tasks "lib/tasks", :glob => "**/*.rake"
paths.lib.templates "lib/templates"
paths.config "config" paths.config "config"
paths.config.initializers "config/initializers", :glob => "**/*.rb" paths.config.initializers "config/initializers", :glob => "**/*.rb"
paths.config.locales "config/locales", :glob => "*.{rb,yml}" paths.config.locales "config/locales", :glob => "*.{rb,yml}"
Expand Down

0 comments on commit 6690d66

Please sign in to comment.