public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
Bug: Earlier Check for Session in Forgery Protection

The session is used by the form_authenticity_token method before it is
tested to be valid.  This patch moves a few lines around so that the
session is validated first.

Without this patch, if you try to use forgery protection with sessions
turned off, you get this exception message:

  undefined method `session_id' for {}:Hash

The patch includes a test that can be used to see this behavior before
the request_forgery_protection.rb file is patched to fix it.
pjones (author)
Wed May 07 15:04:18 -0700 2008
dhh (committer)
Sun May 11 11:27:34 -0700 2008
commit  2a986200b9a6be0f68a0db504dc478da04842dee
tree    66421a3dd7322c44184a273834ed95795f0a5a0f
parent  7013d9e52a41a6261738b8d11bcada85bc6fe81b
...
105
106
107
108
 
 
 
109
110
111
112
113
114
115
116
...
105
106
107
 
108
109
110
111
112
113
 
 
114
115
116
0
@@ -105,12 +105,12 @@ module ActionController #:nodoc:
0
       # Sets the token value for the current session.  Pass a <tt>:secret</tt> option
0
       # in +protect_from_forgery+ to add a custom salt to the hash.
0
       def form_authenticity_token
0
-        @form_authenticity_token ||= if request_forgery_protection_options[:secret]
0
+        @form_authenticity_token ||= if !session.respond_to?(:session_id)
0
+          raise InvalidAuthenticityToken, "Request Forgery Protection requires a valid session.  Use #allow_forgery_protection to disable it, or use a valid session."
0
+        elsif request_forgery_protection_options[:secret]
0
           authenticity_token_from_session_id
0
         elsif session.respond_to?(:dbman) && session.dbman.respond_to?(:generate_digest)
0
           authenticity_token_from_cookie_session
0
-        elsif session.nil?
0
-          raise InvalidAuthenticityToken, "Request Forgery Protection requires a valid session.  Use #allow_forgery_protection to disable it, or use a valid session."
0
         else
0
           raise InvalidAuthenticityToken, "No :secret given to the #protect_from_forgery call.  Set that or use a session store capable of generating its own keys (Cookie Session Store)."
0
         end
...
50
51
52
 
 
 
 
 
 
 
 
53
54
55
...
224
225
226
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
50
51
52
53
54
55
56
57
58
59
60
61
62
63
...
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
0
@@ -50,6 +50,14 @@ class CsrfCookieMonsterController < ActionController::Base
0
   protect_from_forgery :only => :index
0
 end
0
 
0
+# sessions are turned off
0
+class SessionOffController < ActionController::Base
0
+  protect_from_forgery :secret => 'foobar'
0
+  session :off
0
+  def rescue_action(e) raise e end
0
+  include RequestForgeryProtectionActions
0
+end
0
+
0
 class FreeCookieController < CsrfCookieMonsterController
0
   self.allow_forgery_protection = false
0
   
0
@@ -224,3 +232,19 @@ class FreeCookieControllerTest < Test::Unit::TestCase
0
     end
0
   end
0
 end
0
+
0
+class SessionOffControllerTest < Test::Unit::TestCase
0
+  def setup
0
+    @controller = SessionOffController.new
0
+    @request    = ActionController::TestRequest.new
0
+    @response   = ActionController::TestResponse.new
0
+    @token      = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('SHA1'), 'abc', '123')
0
+  end
0
+
0
+  def test_should_raise_correct_exception
0
+    @request.session = {} # session(:off) doesn't appear to work with controller tests
0
+    assert_raises(ActionController::InvalidAuthenticityToken) do
0
+      post :index, :authenticity_token => @token
0
+    end
0
+  end
0
+end

Comments