global_session 1.0.10 → 1.0.13
Sign up to get free protection for your applications and to get access to all the features.
- data/global_session.gemspec +3 -3
- data/lib/global_session/configuration.rb +5 -0
- data/lib/global_session/directory.rb +39 -1
- data/lib/global_session/rack.rb +13 -8
- data/lib/global_session/rails/action_controller_class_methods.rb +25 -23
- data/lib/global_session/rails/action_controller_instance_methods.rb +2 -0
- data/lib/global_session/rails.rb +32 -6
- data/lib/global_session/session.rb +5 -0
- metadata +8 -8
data/global_session.gemspec
CHANGED
@@ -7,8 +7,8 @@ spec = Gem::Specification.new do |s|
|
|
7
7
|
s.required_ruby_version = Gem::Requirement.new(">= 1.8.7")
|
8
8
|
|
9
9
|
s.name = 'global_session'
|
10
|
-
s.version = '1.0.
|
11
|
-
s.date = '2012-
|
10
|
+
s.version = '1.0.13'
|
11
|
+
s.date = '2012-09-26'
|
12
12
|
|
13
13
|
s.authors = ['Tony Spataro']
|
14
14
|
s.email = 'support@rightscale.com'
|
@@ -17,7 +17,7 @@ spec = Gem::Specification.new do |s|
|
|
17
17
|
s.summary = %q{Secure single-domain session sharing plugin for Rails.}
|
18
18
|
s.description = %q{This plugin for Rails allows several web apps in an authentication domain to share session state, facilitating single sign-on in a distributed web app. It only provides session sharing and does not concern itself with authentication or replication of the user database.}
|
19
19
|
|
20
|
-
s.add_runtime_dependency('uuidtools', ["
|
20
|
+
s.add_runtime_dependency('uuidtools', [">= 1.0"])
|
21
21
|
s.add_runtime_dependency('json', ["~> 1.4"])
|
22
22
|
s.add_runtime_dependency('rack-contrib', ["~> 1.0"])
|
23
23
|
|
@@ -73,6 +73,11 @@ module GlobalSession
|
|
73
73
|
# you are integrating; see GlobalSession::Rails for more information.
|
74
74
|
#
|
75
75
|
class Configuration
|
76
|
+
# @return a representation of the object suitable for printing to the console
|
77
|
+
def inspect
|
78
|
+
"<#{self.class.name} @environment=#{@environment.inspect}>"
|
79
|
+
end
|
80
|
+
|
76
81
|
# Create a new Configuration object
|
77
82
|
#
|
78
83
|
# === Parameters
|
@@ -54,12 +54,17 @@ module GlobalSession
|
|
54
54
|
class Directory
|
55
55
|
attr_reader :configuration, :authorities, :private_key
|
56
56
|
|
57
|
+
# @return a representation of the object suitable for printing to the console
|
58
|
+
def inspect
|
59
|
+
"<#{self.class.name} @configuration=#{@configuration.inspect}>"
|
60
|
+
end
|
61
|
+
|
57
62
|
# Create a new Directory.
|
58
63
|
#
|
59
64
|
# === Parameters
|
60
65
|
# keystore_directory(String):: Absolute path to authority keystore
|
61
66
|
#
|
62
|
-
# ===Raise
|
67
|
+
# === Raise
|
63
68
|
# ConfigurationError:: if too many or too few keys are found, or if *.key/*.pub files are malformatted
|
64
69
|
def initialize(configuration, keystore_directory)
|
65
70
|
@configuration = configuration
|
@@ -84,6 +89,26 @@ module GlobalSession
|
|
84
89
|
@invalid_sessions = Set.new
|
85
90
|
end
|
86
91
|
|
92
|
+
# Create a new Session, initialized against this directory and ready to
|
93
|
+
# be used by the app.
|
94
|
+
#
|
95
|
+
# === Parameters
|
96
|
+
# directory(Directory):: directory implementation that the session should use for various operations
|
97
|
+
# cookie(String):: Optional, serialized global session cookie. If none is supplied, a new session is created.
|
98
|
+
# valid_signature_digest(String):: Optional, already-trusted signature. If supplied, the expensive RSA-verify operation will be skipped if the cookie's signature matches the value supplied.
|
99
|
+
#
|
100
|
+
# === Return
|
101
|
+
# session(Session):: the newly-initialized session
|
102
|
+
#
|
103
|
+
# ===Raise
|
104
|
+
# InvalidSession:: if the session contained in the cookie has been invalidated
|
105
|
+
# ExpiredSession:: if the session contained in the cookie has expired
|
106
|
+
# MalformedCookie:: if the cookie was corrupt or malformed
|
107
|
+
# SecurityError:: if signature is invalid or cookie is not signed by a trusted authority
|
108
|
+
def create_session(*params)
|
109
|
+
Session.new(self, *params)
|
110
|
+
end
|
111
|
+
|
87
112
|
def local_authority_name
|
88
113
|
@configuration['authority']
|
89
114
|
end
|
@@ -128,5 +153,18 @@ module GlobalSession
|
|
128
153
|
def report_invalid_session(uuid, expired_at)
|
129
154
|
@invalid_sessions << uuid
|
130
155
|
end
|
156
|
+
|
157
|
+
# Callback used by GlobalSession::Rack::Middleware when the application invalidated
|
158
|
+
# current global_session object. This callback could help application to get data related
|
159
|
+
# to the previous global session (old_global_session_id), and put it to new global session
|
160
|
+
# (new_global_sesion_id)
|
161
|
+
|
162
|
+
# invalidated_uuid(String):: Invalidated Global session UUID
|
163
|
+
# new_uuid(String):: Newly created Global session UUID
|
164
|
+
# === Return
|
165
|
+
# true: Always returns true
|
166
|
+
def session_invalidated(invalidated_uuid, new_uuid)
|
167
|
+
true
|
168
|
+
end
|
131
169
|
end
|
132
170
|
end
|
data/lib/global_session/rack.rb
CHANGED
@@ -88,7 +88,7 @@ module GlobalSession
|
|
88
88
|
begin
|
89
89
|
read_cookie(env)
|
90
90
|
rescue Exception => e
|
91
|
-
env['global_session'] =
|
91
|
+
env['global_session'] = @directory.create_session
|
92
92
|
handle_error('reading session cookie', env, e)
|
93
93
|
end
|
94
94
|
|
@@ -114,12 +114,11 @@ module GlobalSession
|
|
114
114
|
# env(Hash): Rack environment.
|
115
115
|
def read_cookie(env)
|
116
116
|
if env['rack.cookies'].has_key?(@cookie_name)
|
117
|
-
env['global_session'] =
|
118
|
-
env['rack.cookies'][@cookie_name])
|
117
|
+
env['global_session'] = @directory.create_session(env['rack.cookies'][@cookie_name])
|
119
118
|
elsif @cookie_retrieval && cookie = @cookie_retrieval.call(env)
|
120
|
-
env['global_session'] =
|
119
|
+
env['global_session'] = @directory.create_session(cookie)
|
121
120
|
else
|
122
|
-
env['global_session'] =
|
121
|
+
env['global_session'] = @directory.create_session
|
123
122
|
end
|
124
123
|
|
125
124
|
true
|
@@ -149,9 +148,15 @@ module GlobalSession
|
|
149
148
|
|
150
149
|
begin
|
151
150
|
domain = @configuration['cookie']['domain'] || env['SERVER_NAME']
|
152
|
-
if env['global_session']
|
153
|
-
|
154
|
-
|
151
|
+
if env['global_session']
|
152
|
+
global_session = env['global_session']
|
153
|
+
unless global_session.valid?
|
154
|
+
invalidated_uuid = global_session.id
|
155
|
+
global_session = @directory.create_session
|
156
|
+
@directory.session_invalidated(invalidated_uuid, global_session.id)
|
157
|
+
end
|
158
|
+
value = global_session.to_s
|
159
|
+
expires = @configuration['ephemeral'] ? nil : global_session.expired_at
|
155
160
|
unless env['rack.cookies'].has_key?(@cookie_name) && env['rack.cookies'][@cookie_name] == value
|
156
161
|
env['rack.cookies'][@cookie_name] =
|
157
162
|
{:value => value, :domain => domain, :expires => expires, :httponly=>true}
|
@@ -25,24 +25,23 @@ module GlobalSession
|
|
25
25
|
# app-wide data such as the configuration object, and implements the DSL used to
|
26
26
|
# configure controllers' use of the global session.
|
27
27
|
module ActionControllerClassMethods
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
return @global_session_config
|
35
|
-
end
|
36
|
-
|
37
|
-
def global_session_config=(config)
|
38
|
-
@global_session_config = config
|
39
|
-
end
|
28
|
+
VALID_OPTIONS = [:raise, :renew, :only, :except]
|
29
|
+
DEFAULT_OPTIONS = {
|
30
|
+
:raise=>true,
|
31
|
+
:renew=>true
|
32
|
+
}
|
40
33
|
|
41
34
|
def has_global_session(options={})
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
35
|
+
#validate our options
|
36
|
+
options.assert_valid_keys(VALID_OPTIONS)
|
37
|
+
if options.key?(:only) && options.key?(:except)
|
38
|
+
raise ArgumentError, "Must specify :only OR :except, you specified both"
|
39
|
+
end
|
40
|
+
|
41
|
+
#start with default options; merge any options inherited from our base class;
|
42
|
+
#merge any options provided by the caller.
|
43
|
+
obase = self.superclass.global_session_options
|
44
|
+
options = DEFAULT_OPTIONS.merge(obase).merge(options)
|
46
45
|
|
47
46
|
#ensure derived-class options don't conflict with mutually exclusive base-class options
|
48
47
|
options.delete(:only) if obase.has_key?(:only) && options.has_key?(:except)
|
@@ -51,20 +50,23 @@ module GlobalSession
|
|
51
50
|
#mark the global session as enabled (a hidden option) and store our
|
52
51
|
#calculated, merged options
|
53
52
|
options[:enabled] = true
|
54
|
-
self.global_session_options = options
|
55
53
|
|
56
|
-
|
54
|
+
self.global_session_options = options
|
57
55
|
end
|
58
56
|
|
59
57
|
def no_global_session
|
60
|
-
|
61
|
-
|
58
|
+
#mark the global session as not-enabled (a hidden option)
|
59
|
+
self.global_session_options={:enabled=>false}
|
62
60
|
end
|
63
61
|
|
64
62
|
def global_session_options
|
65
|
-
|
66
|
-
|
67
|
-
|
63
|
+
if @global_session_options
|
64
|
+
@global_session_options
|
65
|
+
elsif self.superclass.respond_to?(:global_session_options)
|
66
|
+
self.superclass.global_session_options
|
67
|
+
else
|
68
|
+
{}
|
69
|
+
end
|
68
70
|
end
|
69
71
|
|
70
72
|
def global_session_options=(options)
|
@@ -43,6 +43,8 @@ module GlobalSession
|
|
43
43
|
unless base.instance_methods.include?("log_processing_without_global_session")
|
44
44
|
base.alias_method_chain :log_processing, :global_session
|
45
45
|
end
|
46
|
+
|
47
|
+
base.before_filter :global_session_initialize
|
46
48
|
end
|
47
49
|
|
48
50
|
# Shortcut accessor for global session configuration object.
|
data/lib/global_session/rails.rb
CHANGED
@@ -41,14 +41,40 @@ end
|
|
41
41
|
|
42
42
|
module GlobalSession
|
43
43
|
module Rails
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
44
|
+
class <<self
|
45
|
+
# Single Configuration object used by entire Rails app
|
46
|
+
attr_accessor :configuration
|
47
|
+
|
48
|
+
# Single Directory object used by entire Rails app
|
49
|
+
attr_accessor :directory
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.activate(rails_config, &block)
|
53
|
+
config_file = File.join(::Rails.root, 'config', 'global_session.yml')
|
54
|
+
self.configuration = GlobalSession::Configuration.new(config_file, ::Rails.env)
|
55
|
+
|
56
|
+
dir_name = self.configuration['directory'] || 'GlobalSession::Directory'
|
57
|
+
begin
|
58
|
+
dir_klass = dir_name.constantize
|
59
|
+
rescue NameError => e
|
60
|
+
raise GlobalSession::ConfigurationError,
|
61
|
+
"Unknown/malformed directory class '#{dir_name}' in config file: #{e.message}"
|
62
|
+
end
|
63
|
+
|
64
|
+
unless dir_klass.ancestors.include?(GlobalSession::Directory)
|
65
|
+
raise GlobalSession::ConfigurationError,
|
66
|
+
"Specified directory class '#{dir_name}' does not inherit from GlobalSession::Directory"
|
67
|
+
end
|
68
|
+
|
69
|
+
authorities_dir = File.join(::Rails.root, 'config', 'authorities')
|
70
|
+
self.directory = dir_klass.new(self.configuration, authorities_dir)
|
48
71
|
|
49
72
|
# Add our middleware to the stack.
|
50
|
-
|
51
|
-
|
73
|
+
rails_config.middleware.insert_before(ActionController::Base.session_store, ::Rack::Cookies)
|
74
|
+
rails_config.middleware.insert_before(ActionController::Base.session_store, ::Rack::GlobalSession,
|
75
|
+
self.configuration,
|
76
|
+
self.directory,
|
77
|
+
&block)
|
52
78
|
|
53
79
|
return true
|
54
80
|
end
|
@@ -48,6 +48,11 @@ module GlobalSession
|
|
48
48
|
return Encoding::JSON.load(json)
|
49
49
|
end
|
50
50
|
|
51
|
+
# @return a representation of the object suitable for printing to the console
|
52
|
+
def inspect
|
53
|
+
"<#{self.class.name} @id=#{@id.inspect}>"
|
54
|
+
end
|
55
|
+
|
51
56
|
# Create a new global session object.
|
52
57
|
#
|
53
58
|
# === Parameters
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: global_session
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 13
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 1.0.
|
9
|
+
- 13
|
10
|
+
version: 1.0.13
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Tony Spataro
|
@@ -15,20 +15,20 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-
|
18
|
+
date: 2012-09-26 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
22
|
version_requirements: &id001 !ruby/object:Gem::Requirement
|
23
23
|
none: false
|
24
24
|
requirements:
|
25
|
-
- -
|
25
|
+
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
hash:
|
27
|
+
hash: 15
|
28
28
|
segments:
|
29
|
-
- 2
|
30
29
|
- 1
|
31
|
-
|
30
|
+
- 0
|
31
|
+
version: "1.0"
|
32
32
|
requirement: *id001
|
33
33
|
name: uuidtools
|
34
34
|
prerelease: false
|