Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
methodmissing authored and josh committed Dec 18, 2008
1 parent 33f76bb commit 3ff6b00
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 15 deletions.
14 changes: 14 additions & 0 deletions actionpack/lib/action_controller/session/abstract_store.rb
Expand Up @@ -21,6 +21,13 @@ def id
@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
super
Expand All @@ -37,6 +44,13 @@ def to_hash
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)
Expand Down
38 changes: 25 additions & 13 deletions actionpack/lib/action_controller/session/cookie_store.rb
Expand Up @@ -74,17 +74,8 @@ def initialize(app, options = {})
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 = AbstractStore::SessionHash.new(self, env)
original_value = session_data.dup

env[ENV_SESSION_KEY] = session_data
Expand Down Expand Up @@ -142,17 +133,18 @@ def build_cookie(key, value)
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
Expand Down Expand Up @@ -195,6 +187,26 @@ def verifier_for(secret, digest)
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
26 changes: 24 additions & 2 deletions actionpack/test/controller/session/cookie_store_test.rb
Expand Up @@ -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"

Expand All @@ -17,9 +19,13 @@ def no_session_access
head :ok
end

def persistent_session_id
render :text => session[:session_id]
end

def set_session_value
session[:foo] = "bar"
head :ok
render :text => Marshal.dump(session.to_hash)
end

def get_session_value
Expand Down Expand Up @@ -83,7 +89,8 @@ def test_setting_session_value
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
Expand Down Expand Up @@ -132,6 +139,21 @@ def test_doesnt_write_session_cookie_if_session_is_unchanged
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|
Expand Down

0 comments on commit 3ff6b00

Please sign in to comment.