mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
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>
This commit is contained in:
parent
33f76bb25a
commit
3ff6b00ee3
3 changed files with 63 additions and 15 deletions
|
@ -21,6 +21,13 @@ module ActionController
|
||||||
@id
|
@id
|
||||||
end
|
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)
|
def [](key)
|
||||||
load! unless @loaded
|
load! unless @loaded
|
||||||
super
|
super
|
||||||
|
@ -37,6 +44,13 @@ module ActionController
|
||||||
h
|
h
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def data
|
||||||
|
ActiveSupport::Deprecation.warn(
|
||||||
|
"ActionController::Session::AbstractStore::SessionHash#data" +
|
||||||
|
"has been deprecated.Please use #to_hash instead.", caller)
|
||||||
|
to_hash
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def load!
|
def load!
|
||||||
@id, session = @by.send(:load_session, @env)
|
@id, session = @by.send(:load_session, @env)
|
||||||
|
|
|
@ -74,17 +74,8 @@ module ActionController
|
||||||
freeze
|
freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
class SessionHash < AbstractStore::SessionHash
|
|
||||||
private
|
|
||||||
def load!
|
|
||||||
session = @by.send(:load_session, @env)
|
|
||||||
replace(session)
|
|
||||||
@loaded = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(env)
|
def call(env)
|
||||||
session_data = SessionHash.new(self, env)
|
session_data = AbstractStore::SessionHash.new(self, env)
|
||||||
original_value = session_data.dup
|
original_value = session_data.dup
|
||||||
|
|
||||||
env[ENV_SESSION_KEY] = session_data
|
env[ENV_SESSION_KEY] = session_data
|
||||||
|
@ -142,17 +133,18 @@ module ActionController
|
||||||
def load_session(env)
|
def load_session(env)
|
||||||
request = Rack::Request.new(env)
|
request = Rack::Request.new(env)
|
||||||
session_data = request.cookies[@key]
|
session_data = request.cookies[@key]
|
||||||
unmarshal(session_data) || {}
|
data = unmarshal(session_data) || persistent_session_id!({})
|
||||||
|
[data[:session_id], data]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Marshal a session hash into safe cookie data. Include an integrity hash.
|
# Marshal a session hash into safe cookie data. Include an integrity hash.
|
||||||
def marshal(session)
|
def marshal(session)
|
||||||
@verifier.generate(session)
|
@verifier.generate( persistent_session_id!(session))
|
||||||
end
|
end
|
||||||
|
|
||||||
# Unmarshal cookie data to a hash and verify its integrity.
|
# Unmarshal cookie data to a hash and verify its integrity.
|
||||||
def unmarshal(cookie)
|
def unmarshal(cookie)
|
||||||
@verifier.verify(cookie) if cookie
|
persistent_session_id!(@verifier.verify(cookie)) if cookie
|
||||||
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
@ -195,6 +187,26 @@ module ActionController
|
||||||
key = secret.respond_to?(:call) ? secret.call : secret
|
key = secret.respond_to?(:call) ? secret.call : secret
|
||||||
ActiveSupport::MessageVerifier.new(key, digest)
|
ActiveSupport::MessageVerifier.new(key, digest)
|
||||||
end
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,6 +9,8 @@ class CookieStoreTest < ActionController::IntegrationTest
|
||||||
CookieStoreApp = ActionController::Session::CookieStore.new(DispatcherApp,
|
CookieStoreApp = ActionController::Session::CookieStore.new(DispatcherApp,
|
||||||
:key => SessionKey, :secret => SessionSecret)
|
:key => SessionKey, :secret => SessionSecret)
|
||||||
|
|
||||||
|
Verifier = ActiveSupport::MessageVerifier.new(SessionSecret, 'SHA1')
|
||||||
|
|
||||||
SignedBar = "BAh7BjoIZm9vIghiYXI%3D--" +
|
SignedBar = "BAh7BjoIZm9vIghiYXI%3D--" +
|
||||||
"fef868465920f415f2c0652d6910d3af288a0367"
|
"fef868465920f415f2c0652d6910d3af288a0367"
|
||||||
|
|
||||||
|
@ -17,9 +19,13 @@ class CookieStoreTest < ActionController::IntegrationTest
|
||||||
head :ok
|
head :ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def persistent_session_id
|
||||||
|
render :text => session[:session_id]
|
||||||
|
end
|
||||||
|
|
||||||
def set_session_value
|
def set_session_value
|
||||||
session[:foo] = "bar"
|
session[:foo] = "bar"
|
||||||
head :ok
|
render :text => Marshal.dump(session.to_hash)
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_session_value
|
def get_session_value
|
||||||
|
@ -83,7 +89,8 @@ class CookieStoreTest < ActionController::IntegrationTest
|
||||||
with_test_route_set do
|
with_test_route_set do
|
||||||
get '/set_session_value'
|
get '/set_session_value'
|
||||||
assert_response :success
|
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']
|
headers['Set-Cookie']
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -132,6 +139,21 @@ class CookieStoreTest < ActionController::IntegrationTest
|
||||||
end
|
end
|
||||||
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
|
private
|
||||||
def with_test_route_set
|
def with_test_route_set
|
||||||
with_routing do |set|
|
with_routing do |set|
|
||||||
|
|
Loading…
Reference in a new issue