From aa585457446ecfc32cc7b99bbc932286e4852ebf Mon Sep 17 00:00:00 2001 From: Donald Parish Date: Mon, 23 Feb 2009 11:47:13 -0600 Subject: [PATCH 4/4] Remove session from nonce and opaque. Use session secret instead. --- .../lib/action_controller/http_authentication.rb | 30 ++++++++++++------- 1 files changed, 19 insertions(+), 11 deletions(-) diff --git a/vendor/rails/actionpack/lib/action_controller/http_authentication.rb b/vendor/rails/actionpack/lib/action_controller/http_authentication.rb index 4243071..6bf0dc8 100644 --- a/vendor/rails/actionpack/lib/action_controller/http_authentication.rb +++ b/vendor/rails/actionpack/lib/action_controller/http_authentication.rb @@ -179,9 +179,9 @@ module ActionController # Raises error unless the request credentials response value matches the expected value. def validate_digest_response(request, realm, &password_procedure) credentials = decode_credentials_header(request) - valid_nonce = validate_nonce(request, credentials[:nonce]) + valid_nonce = validate_nonce(request,credentials[:nonce]) - if valid_nonce && realm == credentials[:realm] && opaque(request.session.id) == credentials[:opaque] + if valid_nonce && realm == credentials[:realm] && opaque == credentials[:opaque] password = password_procedure.call(credentials[:username]) expected = expected_response(request.env['REQUEST_METHOD'], credentials[:uri], credentials, password) expected == credentials[:response] @@ -213,8 +213,7 @@ module ActionController end def authentication_header(controller, realm) - session_id = controller.request.session.id - controller.headers["WWW-Authenticate"] = %(Digest realm="#{realm}", qop="auth", algorithm=MD5, nonce="#{nonce(session_id)}", opaque="#{opaque(session_id)}") + controller.headers["WWW-Authenticate"] = %(Digest realm="#{realm}", qop="auth", algorithm=MD5, nonce="#{nonce}", opaque="#{opaque}") end def authentication_request(controller, realm, message = nil) @@ -253,22 +252,31 @@ module ActionController # of this document. # # The nonce is opaque to the client. - def nonce(session_id, time = Time.now) + def nonce(time = Time.now) t = time.to_i - hashed = [t, session_id] + hashed = [t, session_secret] digest = ::Digest::MD5.hexdigest(hashed.join(":")) Base64.encode64("#{t}:#{digest}").gsub("\n", '') end - def validate_nonce(request, value) + # Might want a shorter timeout depending on whether the request + # is a PUT or POST, and if client is browser or web service. + # 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=10*60) t = Base64.decode64(value).split(":").first.to_i - nonce(request.session.id, t) == value && (t - Time.now.to_i).abs <= 10 * 60 + nonce(t) == value && (t - Time.now.to_i).abs <= seconds_to_timeout end # Opaque based on digest of session_id - def opaque(session_id) - Base64.encode64(::Digest::MD5::hexdigest(session_id)).gsub("\n", '') + def opaque() + ::Digest::MD5.hexdigest(session_secret) + end + + def session_secret + ::Digest::MD5.hexdigest(ActionController::Base.session_options[:secret]) end end end -end +end \ No newline at end of file -- 1.6.1.9.g97c34