public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
Persistent session identifier support for CookieSessionStore and API compat. 
with the server side stores [#1591 state:resolved]

Signed-off-by: Joshua Peek <josh@joshpeek.com>
methodmissing (author)
Thu Dec 18 09:33:53 -0800 2008
josh (committer)
Thu Dec 18 09:33:53 -0800 2008
commit  3ff6b00ee30d0961f57e3c4b64ec8ff0155aaf2d
tree    e8adf40ecf077c4216ee36bcf9cc20f5ef071952
parent  33f76bb25a973a4707437064e2f963c521413fcb
...
21
22
23
 
 
 
 
 
 
 
24
25
26
...
37
38
39
 
 
 
 
 
 
 
40
41
42
...
21
22
23
24
25
26
27
28
29
30
31
32
33
...
44
45
46
47
48
49
50
51
52
53
54
55
56
0
@@ -21,6 +21,13 @@ module ActionController
0
           @id
0
         end
0
 
0
+        def session_id
0
+          ActiveSupport::Deprecation.warn(
0
+            "ActionController::Session::AbstractStore::SessionHash#session_id" +
0
+            "has been deprecated.Please use #id instead.", caller)
0
+          id
0
+        end
0
+
0
         def [](key)
0
           load! unless @loaded
0
           super
0
@@ -37,6 +44,13 @@ module ActionController
0
           h
0
         end
0
 
0
+        def data
0
+         ActiveSupport::Deprecation.warn(
0
+           "ActionController::Session::AbstractStore::SessionHash#data" +
0
+           "has been deprecated.Please use #to_hash instead.", caller)
0
+          to_hash
0
+        end
0
+
0
         private
0
           def load!
0
             @id, session = @by.send(:load_session, @env)
...
74
75
76
77
78
79
80
81
82
83
84
85
86
87
 
88
89
90
...
142
143
144
145
 
 
146
147
148
149
150
 
151
152
153
154
155
 
156
157
158
...
195
196
197
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
199
200
...
74
75
76
 
 
 
 
 
 
 
 
 
77
 
78
79
80
81
...
133
134
135
 
136
137
138
139
140
141
 
142
143
144
145
146
 
147
148
149
150
...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
0
@@ -74,17 +74,8 @@ module ActionController
0
         freeze
0
       end
0
 
0
-      class SessionHash < AbstractStore::SessionHash
0
-        private
0
-          def load!
0
-            session = @by.send(:load_session, @env)
0
-            replace(session)
0
-            @loaded = true
0
-          end
0
-      end
0
-
0
       def call(env)
0
-        session_data = SessionHash.new(self, env)
0
+        session_data = AbstractStore::SessionHash.new(self, env)
0
         original_value = session_data.dup
0
 
0
         env[ENV_SESSION_KEY] = session_data
0
@@ -142,17 +133,18 @@ module ActionController
0
         def load_session(env)
0
           request = Rack::Request.new(env)
0
           session_data = request.cookies[@key]
0
-          unmarshal(session_data) || {}
0
+          data = unmarshal(session_data) || persistent_session_id!({})
0
+          [data[:session_id], data]
0
         end
0
 
0
         # Marshal a session hash into safe cookie data. Include an integrity hash.
0
         def marshal(session)
0
-          @verifier.generate(session)
0
+          @verifier.generate( persistent_session_id!(session))
0
         end
0
 
0
         # Unmarshal cookie data to a hash and verify its integrity.
0
         def unmarshal(cookie)
0
-          @verifier.verify(cookie) if cookie
0
+          persistent_session_id!(@verifier.verify(cookie)) if cookie
0
         rescue ActiveSupport::MessageVerifier::InvalidSignature
0
           nil
0
         end
0
@@ -195,6 +187,26 @@ module ActionController
0
           key = secret.respond_to?(:call) ? secret.call : secret
0
           ActiveSupport::MessageVerifier.new(key, digest)
0
         end
0
+
0
+        def generate_sid
0
+          ActiveSupport::SecureRandom.hex(16)
0
+        end
0
+
0
+        def persistent_session_id!(data)
0
+          (data ||= {}).merge!(inject_persistent_session_id(data))
0
+        end
0
+
0
+        def inject_persistent_session_id(data)
0
+          requires_session_id?(data) ? { :session_id => generate_sid } : {}
0
+        end
0
+
0
+        def requires_session_id?(data)
0
+          if data
0
+            data.respond_to?(:key?) && !data.key?(:session_id)
0
+          else
0
+            true
0
+          end
0
+        end
0
     end
0
   end
0
 end
...
9
10
11
 
 
12
13
14
...
17
18
19
 
 
 
 
20
21
22
 
23
24
25
...
83
84
85
86
 
 
87
88
89
...
132
133
134
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
136
137
...
9
10
11
12
13
14
15
16
...
19
20
21
22
23
24
25
26
27
 
28
29
30
31
...
89
90
91
 
92
93
94
95
96
...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
0
@@ -9,6 +9,8 @@ class CookieStoreTest < ActionController::IntegrationTest
0
   CookieStoreApp = ActionController::Session::CookieStore.new(DispatcherApp,
0
                      :key => SessionKey, :secret => SessionSecret)
0
 
0
+  Verifier = ActiveSupport::MessageVerifier.new(SessionSecret, 'SHA1')
0
+
0
   SignedBar = "BAh7BjoIZm9vIghiYXI%3D--" +
0
     "fef868465920f415f2c0652d6910d3af288a0367"
0
 
0
@@ -17,9 +19,13 @@ class CookieStoreTest < ActionController::IntegrationTest
0
       head :ok
0
     end
0
 
0
+    def persistent_session_id
0
+      render :text => session[:session_id]
0
+    end
0
+
0
     def set_session_value
0
       session[:foo] = "bar"
0
-      head :ok
0
+      render :text => Marshal.dump(session.to_hash)
0
     end
0
 
0
     def get_session_value
0
@@ -83,7 +89,8 @@ class CookieStoreTest < ActionController::IntegrationTest
0
     with_test_route_set do
0
       get '/set_session_value'
0
       assert_response :success
0
-      assert_equal ["_myapp_session=#{SignedBar}; path=/"],
0
+      session_payload = Verifier.generate( Marshal.load(response.body) )
0
+      assert_equal ["_myapp_session=#{session_payload}; path=/"],
0
         headers['Set-Cookie']
0
    end
0
   end
0
@@ -132,6 +139,21 @@ class CookieStoreTest < ActionController::IntegrationTest
0
     end
0
   end
0
 
0
+  def test_persistent_session_id
0
+    with_test_route_set do
0
+      cookies[SessionKey] = SignedBar
0
+      get '/persistent_session_id'
0
+      assert_response :success
0
+      assert_equal response.body.size, 32
0
+      session_id = response.body
0
+      get '/persistent_session_id'
0
+      assert_equal session_id, response.body
0
+      reset!
0
+      get '/persistent_session_id'
0
+      assert_not_equal session_id, response.body
0
+    end
0
+  end
0
+
0
   private
0
     def with_test_route_set
0
       with_routing do |set|

Comments