From c3bd619828f4ecc2cc056f6895b6f93851a97db2 Mon Sep 17 00:00:00 2001 From: Lourens Naude Date: Wed, 17 Dec 2008 18:30:57 +0000 Subject: [PATCH] Persistent session identifier support for CookieSessionStore and API compat. with the server side stores. --- .../action_controller/session/abstract_store.rb | 10 +++++ .../lib/action_controller/session/cookie_store.rb | 39 +++++++++++++------- .../test/controller/session/cookie_store_test.rb | 26 ++++++++++++- 3 files changed, 60 insertions(+), 15 deletions(-) diff --git a/actionpack/lib/action_controller/session/abstract_store.rb b/actionpack/lib/action_controller/session/abstract_store.rb index c6dd865..21979fe 100644 --- a/actionpack/lib/action_controller/session/abstract_store.rb +++ b/actionpack/lib/action_controller/session/abstract_store.rb @@ -20,6 +20,11 @@ module ActionController load! unless @loaded @id end + + def session_id + ActiveSupport::Deprecation.warn( "ActionController::Session::AbstractStore::SessionHash#session_id has been deprecated.Please use #id instead.", caller) + id() + end def [](key) load! unless @loaded @@ -37,6 +42,11 @@ module ActionController h end + def data + ActiveSupport::Deprecation.warn( "ActionController::Session::AbstractStore::SessionHash#data has been deprecated.Please use #to_hash instead.", caller) + to_hash + end + private def load! @id, session = @by.send(:load_session, @env) diff --git a/actionpack/lib/action_controller/session/cookie_store.rb b/actionpack/lib/action_controller/session/cookie_store.rb index f4089bf..9497ffb 100644 --- a/actionpack/lib/action_controller/session/cookie_store.rb +++ b/actionpack/lib/action_controller/session/cookie_store.rb @@ -74,17 +74,8 @@ module ActionController freeze end - class SessionHash < AbstractStore::SessionHash - private - def load! - session = @by.send(:load_session, @env) - replace(session) - @loaded = true - end - end - def call(env) - session_data = SessionHash.new(self, env) + session_data = ActionController::Session::AbstractStore::SessionHash.new(self, env) original_value = session_data.dup env[ENV_SESSION_KEY] = session_data @@ -142,17 +133,18 @@ module ActionController def load_session(env) request = Rack::Request.new(env) session_data = request.cookies[@key] - unmarshal(session_data) || {} + data = unmarshal(session_data) || persistent_session_id!( {} ) + [data[:session_id], data] end # Marshal a session hash into safe cookie data. Include an integrity hash. def marshal(session) - @verifier.generate(session) + @verifier.generate( persistent_session_id!( session ) ) end # Unmarshal cookie data to a hash and verify its integrity. def unmarshal(cookie) - @verifier.verify(cookie) if cookie + persistent_session_id!( @verifier.verify(cookie) ) if cookie rescue ActiveSupport::MessageVerifier::InvalidSignature nil end @@ -195,6 +187,27 @@ module ActionController key = secret.respond_to?(:call) ? secret.call : secret ActiveSupport::MessageVerifier.new(key, digest) end + + def generate_sid + ActiveSupport::SecureRandom.hex(16) + end + + def persistent_session_id!( data ) + ( data ||= {} ).merge!( inject_persistent_session_id( data ) ) + end + + def inject_persistent_session_id( data ) + requires_session_id?( data ) ? { :session_id => generate_sid() } : {} + end + + def requires_session_id?( data ) + if data + data.respond_to?(:key?) && !data.key?( :session_id ) + else + true + end + end + end end end diff --git a/actionpack/test/controller/session/cookie_store_test.rb b/actionpack/test/controller/session/cookie_store_test.rb index 8098059..8c150a8 100644 --- a/actionpack/test/controller/session/cookie_store_test.rb +++ b/actionpack/test/controller/session/cookie_store_test.rb @@ -9,6 +9,8 @@ class CookieStoreTest < ActionController::IntegrationTest CookieStoreApp = ActionController::Session::CookieStore.new(DispatcherApp, :key => SessionKey, :secret => SessionSecret) + Verifier = ActiveSupport::MessageVerifier.new(SessionSecret, 'SHA1') + SignedBar = "BAh7BjoIZm9vIghiYXI%3D--" + "fef868465920f415f2c0652d6910d3af288a0367" @@ -17,9 +19,13 @@ class CookieStoreTest < ActionController::IntegrationTest head :ok end + def persistent_session_id + render :text => session.id + end + def set_session_value session[:foo] = "bar" - head :ok + render :text => Marshal.dump(session.to_hash) end def get_session_value @@ -83,7 +89,8 @@ class CookieStoreTest < ActionController::IntegrationTest with_test_route_set do get '/set_session_value' assert_response :success - assert_equal ["_myapp_session=#{SignedBar}; path=/"], + session_payload = Verifier.generate( Marshal.load(response.body) ) + assert_equal ["_myapp_session=#{session_payload}; path=/"], headers['Set-Cookie'] end end @@ -132,6 +139,21 @@ class CookieStoreTest < ActionController::IntegrationTest end end + def test_persistent_session_id + with_test_route_set do + cookies[SessionKey] = SignedBar + get '/persistent_session_id' + assert_response :success + assert_equal response.body.size, 32 + session_id = response.body + get '/persistent_session_id' + assert_equal session_id, response.body + reset! + get '/persistent_session_id' + assert_not_equal session_id, response.body + end + end + private def with_test_route_set with_routing do |set| -- 1.5.4.5