public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
Added support for http_only cookies in cookie_store Added unit tests for secure 
and http_only cookies in cookie_store

Signed-off-by: Michael Koziarski <michael@koziarski.com>
[#1046 state:committed]
pelle (author)
Tue Sep 16 09:22:11 -0700 2008
NZKoz (committer)
Wed Sep 17 04:20:16 -0700 2008
commit  7ecb9689b03335ec28958c506b083390f4212d45
tree    e359e86f989b0c9a27f9bafba68c5ba6cd9f01bc
parent  c47525a58397851895b25f7c1bba06b30b0f6b5d
...
1
2
 
 
3
4
5
...
1
2
3
4
5
6
7
0
@@ -1,5 +1,7 @@
0
 *Edge*
0
 
0
+* Set HttpOnly for the cookie session store's cookie.  #1046 
0
+
0
 * Added FormTagHelper#image_submit_tag confirm option #784 [Alastair Brunton]
0
 
0
 * Fixed FormTagHelper#submit_tag with :disable_with option wouldn't submit the button's value when was clicked #633 [Jose Fernandez]
...
42
43
44
45
 
 
46
47
48
...
42
43
44
 
45
46
47
48
49
0
@@ -42,7 +42,8 @@ module ActionController #:nodoc:
0
       :prefix           => "ruby_sess.",    # prefix session file names
0
       :session_path     => "/",             # available to all paths in app
0
       :session_key      => "_session_id",
0
-      :cookie_only      => true
0
+      :cookie_only      => true,
0
+      :session_http_only=> true
0
     }
0
 
0
     def initialize(cgi, session_options = {})
...
14
15
16
17
 
 
18
19
20
...
14
15
16
 
17
18
19
20
21
0
@@ -14,7 +14,8 @@ module ActionController #:nodoc:
0
       :prefix           => "ruby_sess.",    # prefix session file names
0
       :session_path     => "/",             # available to all paths in app
0
       :session_key      => "_session_id",
0
-      :cookie_only      => true
0
+      :cookie_only      => true,
0
+      :session_http_only=> true
0
     }
0
 
0
     def initialize(env, session_options = DEFAULT_SESSION_OPTIONS)
...
70
71
72
73
 
 
74
75
76
...
70
71
72
 
73
74
75
76
77
0
@@ -70,7 +70,8 @@ class CGI::Session::CookieStore
0
       'path'    => options['session_path'],
0
       'domain'  => options['session_domain'],
0
       'expires' => options['session_expires'],
0
-      'secure'  => options['session_secure']
0
+      'secure'  => options['session_secure'],
0
+      'http_only' => options['session_http_only']
0
     }
0
 
0
     # Set no_hidden and no_cookies since the session id is unused and we
...
60
61
62
 
 
 
 
63
64
65
...
60
61
62
63
64
65
66
67
68
69
0
@@ -60,6 +60,10 @@ module ActionController #:nodoc:
0
       #   # the session will only work over HTTPS, but only for the foo action
0
       #   session :only => :foo, :session_secure => true
0
       #
0
+      #   # the session by default uses HttpOnly sessions for security reasons.
0
+      #   # this can be switched off.
0
+      #   session :only => :foo, :session_http_only => false
0
+      #
0
       #   # the session will only be disabled for 'foo', and only if it is
0
       #   # requested as a web service
0
       #   session :off, :only => :foo,
...
36
37
38
39
 
 
 
40
41
42
...
149
150
151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
153
154
...
195
196
197
 
 
 
 
 
 
 
198
199
200
...
36
37
38
 
39
40
41
42
43
44
...
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
...
239
240
241
242
243
244
245
246
247
248
249
250
251
0
@@ -36,7 +36,9 @@ class CookieStoreTest < Test::Unit::TestCase
0
       'session_key' => '_myapp_session',
0
       'secret' => 'Keep it secret; keep it safe.',
0
       'no_cookies' => true,
0
-      'no_hidden' => true }
0
+      'no_hidden' => true,
0
+      'session_http_only' => true
0
+       }
0
   end
0
 
0
   def self.cookies
0
@@ -149,6 +151,48 @@ class CookieStoreTest < Test::Unit::TestCase
0
       assert_equal 1, session.cgi.output_cookies.size
0
       cookie = session.cgi.output_cookies.first
0
       assert_cookie cookie, cookie_value(:flashed)
0
+      assert_http_only_cookie cookie
0
+      assert_secure_cookie cookie, false
0
+    end
0
+  end
0
+
0
+  def test_writes_non_secure_cookie_by_default
0
+    set_cookie! cookie_value(:typical)
0
+    new_session do |session|
0
+      session['flash'] = {}
0
+      session.close
0
+      cookie = session.cgi.output_cookies.first
0
+      assert_secure_cookie cookie,false
0
+    end
0
+  end
0
+
0
+  def test_writes_secure_cookie
0
+    set_cookie! cookie_value(:typical)
0
+    new_session('session_secure'=>true) do |session|
0
+      session['flash'] = {}
0
+      session.close
0
+      cookie = session.cgi.output_cookies.first
0
+      assert_secure_cookie cookie
0
+    end
0
+  end
0
+
0
+  def test_http_only_cookie_by_default
0
+    set_cookie! cookie_value(:typical)
0
+    new_session do |session|
0
+      session['flash'] = {}
0
+      session.close
0
+      cookie = session.cgi.output_cookies.first
0
+      assert_http_only_cookie cookie
0
+    end
0
+  end
0
+
0
+  def test_overides_http_only_cookie
0
+    set_cookie! cookie_value(:typical)
0
+    new_session('session_http_only'=>false) do |session|
0
+      session['flash'] = {}
0
+      session.close
0
+      cookie = session.cgi.output_cookies.first
0
+      assert_http_only_cookie cookie, false
0
     end
0
   end
0
 
0
@@ -195,6 +239,13 @@ class CookieStoreTest < Test::Unit::TestCase
0
       assert_equal expires, cookie.expires ? cookie.expires.to_date : cookie.expires, message
0
     end
0
 
0
+    def assert_secure_cookie(cookie,value=true)
0
+      assert cookie.secure==value
0
+    end
0
+
0
+    def assert_http_only_cookie(cookie,value=true)
0
+      assert cookie.http_only==value
0
+    end
0
 
0
     def cookies(*which)
0
       self.class.cookies.values_at(*which)

Comments