Class: Rack::Middleware::SessionInjector
- Inherits:
-
Object
- Object
- Rack::Middleware::SessionInjector
- Defined in:
- lib/session_injector.rb
Defined Under Namespace
Classes: InvalidHandshake
Constant Summary collapse
- RACK_COOKIE_STRING =
'rack.request.cookie_string'.freeze
- RACK_COOKIE_HASH =
'rack.request.cookie_hash'.freeze
- HTTP_COOKIE =
'HTTP_COOKIE'.freeze
- DEFAULT_OPTIONS =
{ # use the AbstractStore default key as our session id key # if you have configured a custom session store key, you must # specify that as the value for this middleware :key => ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS[:key], :token_lifetime => 5000, # five seconds should be enough :die_on_handshake_failure => true }
- SESSION_INJECTOR_KEY =
the env key we will use to stash ourselves for downstream access
'_session_injector'
- SESSION_PROPAGATE_KEY =
the env key upstream uses to stash a flag to tell us to propagate a session this is a convenience for manually adding a request parameter to a redirect response location
'_session_propagate'
- HANDSHAKE_PARAM =
the internal parameter we will use to convey the session handshake token
'_hs_'
Class Method Summary collapse
-
.extract_session_id(request, session_id_key) ⇒ Object
find the current session id.
-
.generate_handshake_parameter(request, target_domain, lifetime = nil) ⇒ Object
generates the handshake parameter key=value string.
-
.generate_handshake_token(request, target_domain, lifetime = nil) ⇒ Object
generates the handshake token we can send to the target domain.
-
.propagate_session(request, target_domain, lifetime = nil) ⇒ Object
helper that sets a flag to rewrite the location header with session propagation handshake.
Instance Method Summary collapse
- #call(env) ⇒ Object
-
#initialize(app, options = {}) ⇒ SessionInjector
constructor
A new instance of SessionInjector.
-
#propagate_session(env, status, headers, response) ⇒ Object
rewrites location header if requested.
-
#session_id_key ⇒ Object
return the env key containing the session id.
-
#token_key ⇒ Object
return the key we use for encryption and hashing.
Constructor Details
#initialize(app, options = {}) ⇒ SessionInjector
Returns a new instance of SessionInjector.
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/session_injector.rb', line 32 def initialize(app, = {}) @app = app = DEFAULT_OPTIONS.merge() @session_id_key = [:key] # statically generated token key in case we # need to fall back (no cookie token key has been set) # handshakes are by definition transient, so the only # important requirement is that the middleware that generates # the token can decrypt the token. when not under a clustered/balanced # architecture, that most likely means the same process/middelware # so the key value is not important # in fact, non-durability of the token is a security feature generated_token_key = ActiveSupport::SecureRandom.hex(16) @token_key = [:token_key] || generated_token_key @enforced_lifetime = [:token_lifetime] @die_on_handshake_failure = [:die_on_handshake_failure] end |
Class Method Details
.extract_session_id(request, session_id_key) ⇒ Object
find the current session id
104 105 106 107 |
# File 'lib/session_injector.rb', line 104 def self.extract_session_id(request, session_id_key) #request.session_options[:id] request.[session_id_key] end |
.generate_handshake_parameter(request, target_domain, lifetime = nil) ⇒ Object
generates the handshake parameter key=value string
94 95 96 |
# File 'lib/session_injector.rb', line 94 def self.generate_handshake_parameter(request, target_domain, lifetime = nil) "#{HANDSHAKE_PARAM}=#{generate_handshake_token(request, target_domain, lifetime)}" end |
.generate_handshake_token(request, target_domain, lifetime = nil) ⇒ Object
generates the handshake token we can send to the target domain
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/session_injector.rb', line 74 def self.generate_handshake_token(request, target_domain, lifetime = nil) # retrieve the configured middleware instance session_injector = request.env[SESSION_INJECTOR_KEY] # note: scheme is not included in handshake # a session initiated on https may be established on http handshake = { :request_ip => request.ip, :request_path => request.fullpath, # more for accounting/stats than anything else :src_domain => request.host, :tgt_domain => target_domain, :token_create_time => Time.now.to_i, # the most important thing :session_id => extract_session_id(request, session_injector.session_id_key) } handshake[:requested_lifetime] = lifetime if lifetime # we could reuse ActionDispatch::Cookies.TOKEN_KEY if it is present but let's not! ActiveSupport::MessageEncryptor.new(session_injector.token_key).encrypt_and_sign(handshake); end |
.propagate_session(request, target_domain, lifetime = nil) ⇒ Object
helper that sets a flag to rewrite the location header with session propagation handshake
99 100 101 |
# File 'lib/session_injector.rb', line 99 def self.propagate_session(request, target_domain, lifetime = nil) request.env[SESSION_PROPAGATE_KEY] = [ target_domain, lifetime ] end |
Instance Method Details
#call(env) ⇒ Object
50 51 52 53 54 55 56 |
# File 'lib/session_injector.rb', line 50 def call(env) env[SESSION_INJECTOR_KEY] = self; # store ourselves for downstream access reconstitute_session(env) response = @app.call(env) response = propagate_session(env, *response) response end |
#propagate_session(env, status, headers, response) ⇒ Object
rewrites location header if requested
59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/session_injector.rb', line 59 def propagate_session(env, status, headers, response) propagate_flag = env.delete(SESSION_PROPAGATE_KEY) location = headers["Location"] if propagate_flag and location # we've been told to rewrite the location header and it is present uri = URI::parse(location) prefix = uri.query ? "&" : "" # append handshake param to query uri.query = [uri.query, prefix, SessionInjector.generate_handshake_parameter(Rack::Request.new(env), propagate_flag[0], propagate_flag[1])].join headers["Location"] = uri.to_s end [ status, headers, response] end |
#session_id_key ⇒ Object
return the env key containing the session id
110 111 112 |
# File 'lib/session_injector.rb', line 110 def session_id_key @session_id_key end |
#token_key ⇒ Object
return the key we use for encryption and hashing
115 116 117 |
# File 'lib/session_injector.rb', line 115 def token_key @token_key end |