Froze rails gems
[depot.git] / vendor / rails / actionpack / test / controller / session / cookie_store_test.rb
1 require 'abstract_unit'
2 require 'action_controller/cgi_process'
3 require 'action_controller/cgi_ext'
4
5 require 'stringio'
6
7
8 class CGI::Session::CookieStore
9 def ensure_secret_secure_with_test_hax(secret)
10 if secret == CookieStoreTest.default_session_options['secret']
11 return true
12 else
13 ensure_secret_secure_without_test_hax(secret)
14 end
15 end
16 alias_method_chain :ensure_secret_secure, :test_hax
17 end
18
19
20 # Expose for tests.
21 class CGI
22 attr_reader :output_cookies, :output_hidden
23
24 class Session
25 attr_reader :dbman
26
27 class CookieStore
28 attr_reader :data, :original, :cookie_options
29 end
30 end
31 end
32
33 class CookieStoreTest < Test::Unit::TestCase
34 def self.default_session_options
35 { 'database_manager' => CGI::Session::CookieStore,
36 'session_key' => '_myapp_session',
37 'secret' => 'Keep it secret; keep it safe.',
38 'no_cookies' => true,
39 'no_hidden' => true,
40 'session_http_only' => true
41 }
42 end
43
44 def self.cookies
45 { :empty => ['BAgw--0686dcaccc01040f4bd4f35fe160afe9bc04c330', {}],
46 :a_one => ['BAh7BiIGYWkG--5689059497d7f122a7119f171aef81dcfd807fec', { 'a' => 1 }],
47 :typical => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7BiILbm90aWNlIgxIZXkgbm93--9d20154623b9eeea05c62ab819be0e2483238759', { 'user_id' => 123, 'flash' => { 'notice' => 'Hey now' }}],
48 :flashed => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA==--bf9785a666d3c4ac09f7fe3353496b437546cfbf', { 'user_id' => 123, 'flash' => {} }],
49 :double_escaped => [CGI.escape('BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA%3D%3D--bf9785a666d3c4ac09f7fe3353496b437546cfbf'), { 'user_id' => 123, 'flash' => {} }] }
50
51 end
52
53 def setup
54 ENV.delete('HTTP_COOKIE')
55 end
56
57 def test_raises_argument_error_if_missing_session_key
58 [nil, ''].each do |blank|
59 assert_raise(ArgumentError, blank.inspect) { new_session 'session_key' => blank }
60 end
61 end
62
63 def test_raises_argument_error_if_missing_secret
64 [nil, ''].each do |blank|
65 assert_raise(ArgumentError, blank.inspect) { new_session 'secret' => blank }
66 end
67 end
68
69 def test_raises_argument_error_if_secret_is_probably_insecure
70 ["password", "secret", "12345678901234567890123456789"].each do |blank|
71 assert_raise(ArgumentError, blank.inspect) { new_session 'secret' => blank }
72 end
73 end
74
75 def test_reconfigures_session_to_omit_id_cookie_and_hidden_field
76 new_session do |session|
77 assert_equal true, @options['no_hidden']
78 assert_equal true, @options['no_cookies']
79 end
80 end
81
82 def test_restore_unmarshals_missing_cookie_as_empty_hash
83 new_session do |session|
84 assert_nil session.dbman.data
85 assert_nil session['test']
86 assert_equal Hash.new, session.dbman.data
87 end
88 end
89
90 def test_restore_unmarshals_good_cookies
91 cookies(:empty, :a_one, :typical).each do |value, expected|
92 set_cookie! value
93 new_session do |session|
94 assert_nil session['lazy loads the data hash']
95 assert_equal expected, session.dbman.data
96 end
97 end
98 end
99
100 def test_restore_deletes_tampered_cookies
101 set_cookie! 'a--b'
102 new_session do |session|
103 assert_raise(CGI::Session::CookieStore::TamperedWithCookie) { session['fail'] }
104 assert_cookie_deleted session
105 end
106 end
107
108 def test_restores_double_encoded_cookies
109 set_cookie! cookie_value(:double_escaped)
110 new_session do |session|
111 session.dbman.restore
112 assert_equal session["user_id"], 123
113 assert_equal session["flash"], {}
114 end
115 end
116
117 def test_close_doesnt_write_cookie_if_data_is_blank
118 new_session do |session|
119 assert_no_cookies session
120 session.close
121 assert_no_cookies session
122 end
123 end
124
125 def test_close_doesnt_write_cookie_if_data_is_unchanged
126 set_cookie! cookie_value(:typical)
127 new_session do |session|
128 assert_no_cookies session
129 session['user_id'] = session['user_id']
130 session.close
131 assert_no_cookies session
132 end
133 end
134
135 def test_close_raises_when_data_overflows
136 set_cookie! cookie_value(:empty)
137 new_session do |session|
138 session['overflow'] = 'bye!' * 1024
139 assert_raise(CGI::Session::CookieStore::CookieOverflow) { session.close }
140 assert_no_cookies session
141 end
142 end
143
144 def test_close_marshals_and_writes_cookie
145 set_cookie! cookie_value(:typical)
146 new_session do |session|
147 assert_no_cookies session
148 session['flash'] = {}
149 assert_no_cookies session
150 session.close
151 assert_equal 1, session.cgi.output_cookies.size
152 cookie = session.cgi.output_cookies.first
153 assert_cookie cookie, cookie_value(:flashed)
154 assert_http_only_cookie cookie
155 assert_secure_cookie cookie, false
156 end
157 end
158
159 def test_writes_non_secure_cookie_by_default
160 set_cookie! cookie_value(:typical)
161 new_session do |session|
162 session['flash'] = {}
163 session.close
164 cookie = session.cgi.output_cookies.first
165 assert_secure_cookie cookie,false
166 end
167 end
168
169 def test_writes_secure_cookie
170 set_cookie! cookie_value(:typical)
171 new_session('session_secure'=>true) do |session|
172 session['flash'] = {}
173 session.close
174 cookie = session.cgi.output_cookies.first
175 assert_secure_cookie cookie
176 end
177 end
178
179 def test_http_only_cookie_by_default
180 set_cookie! cookie_value(:typical)
181 new_session do |session|
182 session['flash'] = {}
183 session.close
184 cookie = session.cgi.output_cookies.first
185 assert_http_only_cookie cookie
186 end
187 end
188
189 def test_overides_http_only_cookie
190 set_cookie! cookie_value(:typical)
191 new_session('session_http_only'=>false) do |session|
192 session['flash'] = {}
193 session.close
194 cookie = session.cgi.output_cookies.first
195 assert_http_only_cookie cookie, false
196 end
197 end
198
199 def test_delete_writes_expired_empty_cookie_and_sets_data_to_nil
200 set_cookie! cookie_value(:typical)
201 new_session do |session|
202 assert_no_cookies session
203 session.delete
204 assert_cookie_deleted session
205
206 # @data is set to nil so #close doesn't send another cookie.
207 session.close
208 assert_cookie_deleted session
209 end
210 end
211
212 def test_new_session_doesnt_reuse_deleted_cookie_data
213 set_cookie! cookie_value(:typical)
214
215 new_session do |session|
216 assert_not_nil session['user_id']
217 session.delete
218
219 # Start a new session using the same CGI instance.
220 post_delete_session = CGI::Session.new(session.cgi, self.class.default_session_options)
221 assert_nil post_delete_session['user_id']
222 end
223 end
224
225 private
226 def assert_no_cookies(session)
227 assert_nil session.cgi.output_cookies, session.cgi.output_cookies.inspect
228 end
229
230 def assert_cookie_deleted(session, message = 'Expected session deletion cookie to be set')
231 assert_equal 1, session.cgi.output_cookies.size
232 cookie = session.cgi.output_cookies.first
233 assert_cookie cookie, nil, 1.year.ago.to_date, "#{message}: #{cookie.name} => #{cookie.value}"
234 end
235
236 def assert_cookie(cookie, value = nil, expires = nil, message = nil)
237 assert_equal '_myapp_session', cookie.name, message
238 assert_equal [value].compact, cookie.value, message
239 assert_equal expires, cookie.expires ? cookie.expires.to_date : cookie.expires, message
240 end
241
242 def assert_secure_cookie(cookie,value=true)
243 assert cookie.secure==value
244 end
245
246 def assert_http_only_cookie(cookie,value=true)
247 assert cookie.http_only==value
248 end
249
250 def cookies(*which)
251 self.class.cookies.values_at(*which)
252 end
253
254 def cookie_value(which)
255 self.class.cookies[which].first
256 end
257
258 def set_cookie!(value)
259 ENV['HTTP_COOKIE'] = "_myapp_session=#{value}"
260 end
261
262 def new_session(options = {})
263 with_cgi do |cgi|
264 assert_nil cgi.output_hidden, "Output hidden params should be empty: #{cgi.output_hidden.inspect}"
265 assert_nil cgi.output_cookies, "Output cookies should be empty: #{cgi.output_cookies.inspect}"
266
267 @options = self.class.default_session_options.merge(options)
268 session = CGI::Session.new(cgi, @options)
269 ObjectSpace.undefine_finalizer(session)
270
271 assert_nil cgi.output_hidden, "Output hidden params should be empty: #{cgi.output_hidden.inspect}"
272 assert_nil cgi.output_cookies, "Output cookies should be empty: #{cgi.output_cookies.inspect}"
273
274 yield session if block_given?
275 session
276 end
277 end
278
279 def with_cgi
280 ENV['REQUEST_METHOD'] = 'GET'
281 ENV['HTTP_HOST'] = 'example.com'
282 ENV['QUERY_STRING'] = ''
283
284 cgi = CGI.new('query', StringIO.new(''))
285 yield cgi if block_given?
286 cgi
287 end
288 end
289
290
291 class CookieStoreWithBlockAsSecretTest < CookieStoreTest
292 def self.default_session_options
293 CookieStoreTest.default_session_options.merge 'secret' => Proc.new { 'Keep it secret; keep it safe.' }
294 end
295 end
296
297
298 class CookieStoreWithMD5DigestTest < CookieStoreTest
299 def self.default_session_options
300 CookieStoreTest.default_session_options.merge 'digest' => 'MD5'
301 end
302
303 def self.cookies
304 { :empty => ['BAgw--0415cc0be9579b14afc22ee2d341aa21', {}],
305 :a_one => ['BAh7BiIGYWkG--5a0ed962089cc6600ff44168a5d59bc8', { 'a' => 1 }],
306 :typical => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7BiILbm90aWNlIgxIZXkgbm93--f426763f6ef435b3738b493600db8d64', { 'user_id' => 123, 'flash' => { 'notice' => 'Hey now' }}],
307 :flashed => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA==--0af9156650dab044a53a91a4ddec2c51', { 'user_id' => 123, 'flash' => {} }],
308 :double_escaped => [CGI.escape('BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA%3D%3D--0af9156650dab044a53a91a4ddec2c51'), { 'user_id' => 123, 'flash' => {} }] }
309 end
310 end