aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/action_controller/metal.rb17
-rw-r--r--actionpack/lib/action_controller/metal/compatibility.rb3
-rw-r--r--actionpack/lib/action_controller/metal/http_authentication.rb28
-rw-r--r--actionpack/lib/action_controller/metal/session_management.rb35
-rw-r--r--actionpack/test/controller/http_digest_authentication_test.rb5
5 files changed, 57 insertions, 31 deletions
diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb
index 5e0ed201cb..fbc8a9a15e 100644
--- a/actionpack/lib/action_controller/metal.rb
+++ b/actionpack/lib/action_controller/metal.rb
@@ -1,4 +1,13 @@
require 'active_support/core_ext/class/attribute'
+require 'active_support/ordered_options'
+
+module ActiveSupport
+ class InheritableOptions < OrderedOptions
+ def initialize(parent)
+ super() { |h,k| parent[k] }
+ end
+ end
+end
module ActionController
# ActionController::Metal provides a way to get a valid Rack application from a controller.
@@ -10,6 +19,14 @@ module ActionController
class Metal < AbstractController::Base
abstract!
+ def self.config
+ @config ||= ActiveSupport::InheritableOptions.new(superclass < Metal ? superclass.config : {})
+ end
+
+ def config
+ self.class.config
+ end
+
# :api: public
attr_internal :params, :env
diff --git a/actionpack/lib/action_controller/metal/compatibility.rb b/actionpack/lib/action_controller/metal/compatibility.rb
index 2b1ada1426..d1c86b296d 100644
--- a/actionpack/lib/action_controller/metal/compatibility.rb
+++ b/actionpack/lib/action_controller/metal/compatibility.rb
@@ -12,9 +12,6 @@ module ActionController
::ActionController::UnknownAction = ::AbstractController::ActionNotFound
::ActionController::DoubleRenderError = ::AbstractController::DoubleRenderError
- cattr_accessor :session_options
- self.session_options = {}
-
cattr_accessor :relative_url_root
self.relative_url_root = ENV['RAILS_RELATIVE_URL_ROOT']
diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb
index 0f35a7c040..5c6641c948 100644
--- a/actionpack/lib/action_controller/metal/http_authentication.rb
+++ b/actionpack/lib/action_controller/metal/http_authentication.rb
@@ -165,7 +165,7 @@ module ActionController
# Authenticate with HTTP Digest, returns true or false
def authenticate_with_http_digest(realm = "Application", &password_procedure)
- HttpAuthentication::Digest.authenticate(request, realm, &password_procedure)
+ HttpAuthentication::Digest.authenticate(config.session_options[:secret], request, realm, &password_procedure)
end
# Render output including the HTTP Digest authentication header
@@ -175,8 +175,8 @@ module ActionController
end
# Returns false on a valid response, true otherwise
- def authenticate(request, realm, &password_procedure)
- authorization(request) && validate_digest_response(request, realm, &password_procedure)
+ def authenticate(secret_key, request, realm, &password_procedure)
+ authorization(request) && validate_digest_response(secret_key, request, realm, &password_procedure)
end
def authorization(request)
@@ -189,11 +189,11 @@ module ActionController
# 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(request, realm, &password_procedure)
+ def validate_digest_response(secret_key, request, realm, &password_procedure)
credentials = decode_credentials_header(request)
- valid_nonce = validate_nonce(request, credentials[:nonce])
+ valid_nonce = validate_nonce(secret_key, request, credentials[:nonce])
- if valid_nonce && realm == credentials[:realm] && opaque == credentials[:opaque]
+ if valid_nonce && realm == credentials[:realm] && opaque(secret_key) == credentials[:opaque]
password = password_procedure.call(credentials[:username])
return false unless password
@@ -238,6 +238,9 @@ module ActionController
end
def authentication_header(controller, realm)
+ secret_key = controller.config.session_options[:secret]
+ nonce = self.nonce(secret_key)
+ opaque = opaque(secret_key)
controller.headers["WWW-Authenticate"] = %(Digest realm="#{realm}", qop="auth", algorithm=MD5, nonce="#{nonce}", opaque="#{opaque}")
end
@@ -280,7 +283,7 @@ module ActionController
# The nonce is opaque to the client. Composed of Time, and hash of Time with secret
# key from the Rails session secret generated upon creation of project. Ensures
# the time cannot be modified by client.
- def nonce(time = Time.now)
+ def nonce(secret_key, time = Time.now)
t = time.to_i
hashed = [t, secret_key]
digest = ::Digest::MD5.hexdigest(hashed.join(":"))
@@ -292,21 +295,16 @@ module ActionController
# Can be much shorter if the Stale directive is implemented. This would
# allow a user to use new nonce without prompting user again for their
# username and password.
- def validate_nonce(request, value, seconds_to_timeout=5*60)
+ def validate_nonce(secret_key, request, value, seconds_to_timeout=5*60)
t = ActiveSupport::Base64.decode64(value).split(":").first.to_i
- nonce(t) == value && (t - Time.now.to_i).abs <= seconds_to_timeout
+ nonce(secret_key, t) == value && (t - Time.now.to_i).abs <= seconds_to_timeout
end
# Opaque based on random generation - but changing each request?
- def opaque()
+ def opaque(secret_key)
::Digest::MD5.hexdigest(secret_key)
end
- # Set in /initializers/session_store.rb, and loaded even if sessions are not in use.
- def secret_key
- ActionController::Base.session_options[:secret]
- end
-
end
end
end
diff --git a/actionpack/lib/action_controller/metal/session_management.rb b/actionpack/lib/action_controller/metal/session_management.rb
index 6997257844..264250db1a 100644
--- a/actionpack/lib/action_controller/metal/session_management.rb
+++ b/actionpack/lib/action_controller/metal/session_management.rb
@@ -2,27 +2,40 @@ module ActionController #:nodoc:
module SessionManagement #:nodoc:
extend ActiveSupport::Concern
+ included do
+ self.config.session_store ||= :cookie_store
+ self.config.session_options ||= {}
+ end
+
module ClassMethods
# Set the session store to be used for keeping the session data between requests.
# By default, sessions are stored in browser cookies (<tt>:cookie_store</tt>),
# but you can also specify one of the other included stores (<tt>:active_record_store</tt>,
# <tt>:mem_cache_store</tt>, or your own custom class.
def session_store=(store)
- if store == :active_record_store
- self.session_store = ActiveRecord::SessionStore
- else
- @@session_store = store.is_a?(Symbol) ?
- ActionDispatch::Session.const_get(store.to_s.camelize) :
- store
- end
+ ActiveSupport::Deprecation.warn "Setting session_store directly on ActionController::Base is deprecated. " \
+ "Please set it on config.action_controller.session_store"
+ config.session_store = store
+ end
+
+ def session_options=(opts)
+ ActiveSupport::Deprecation.warn "Setting seession_options directly on ActionController::Base is deprecated. " \
+ "Please set it on config.action_controller.session_options"
+ config.session_store = opts
+ end
+
+ def session_options
+ config.session_options
end
- # Returns the session store class currently used.
def session_store
- if defined? @@session_store
- @@session_store
+ case store = config.session_store
+ when :active_record_store
+ ActiveRecord::SessionStore
+ when Symbol
+ ActionDispatch::Session.const_get(store.to_s.camelize)
else
- ActionDispatch::Session::CookieStore
+ store
end
end
diff --git a/actionpack/test/controller/http_digest_authentication_test.rb b/actionpack/test/controller/http_digest_authentication_test.rb
index 7e9a2625f1..22d2e23de1 100644
--- a/actionpack/test/controller/http_digest_authentication_test.rb
+++ b/actionpack/test/controller/http_digest_authentication_test.rb
@@ -40,7 +40,8 @@ class HttpDigestAuthenticationTest < ActionController::TestCase
setup do
# Used as secret in generating nonce to prevent tampering of timestamp
- @old_secret, ActionController::Base.session_options[:secret] = ActionController::Base.session_options[:secret], "session_options_secret"
+ @secret = "session_options_secret"
+ @old_secret, ActionController::Base.session_options[:secret] = ActionController::Base.session_options[:secret], @secret
end
teardown do
@@ -202,7 +203,7 @@ class HttpDigestAuthenticationTest < ActionController::TestCase
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(@request, "SuperSecret"){nil}
+ assert !ActionController::HttpAuthentication::Digest.validate_digest_response(@secret, @request, "SuperSecret"){nil}
end
private