has_global_session 0.8.0 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/{README → README.rdoc} +88 -51
- data/has_global_session.gemspec +3 -3
- data/lib/generators/global_session_authority/global_session_authority_generator.rb +32 -0
- data/lib/generators/global_session_config/global_session_config_generator.rb +1 -1
- data/lib/generators/global_session_config/templates/global_session.yml.erb +18 -6
- data/lib/has_global_session/configuration.rb +20 -12
- data/lib/has_global_session/global_session.rb +29 -12
- data/lib/has_global_session/integrated_session.rb +3 -0
- data/rails/action_controller_instance_methods.rb +38 -1
- data/rails/init.rb +15 -12
- metadata +31 -10
data/{README → README.rdoc}
RENAMED
@@ -5,104 +5,121 @@ session state in a cryptographically secure way, facilitating single sign-on
|
|
5
5
|
and enabling easier development of large-scale distributed applications that
|
6
6
|
make use of architectural strategies such as sharding or separation of concerns.
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
In other words: it lets semi-related Web apps share selected bits of session
|
9
|
+
state.
|
10
|
+
|
11
|
+
This plugin does not provide a complete solution for identity management. In
|
12
|
+
particular, it does not provide any of the following:
|
10
13
|
|
11
14
|
* <b>federation</b> -- aka cross-domain single sign-on -- use OpenID for that.
|
12
15
|
|
13
|
-
* <b>authentication</b> -- the application
|
16
|
+
* <b>authentication</b> -- the application must authenticate the user.
|
17
|
+
|
18
|
+
* <b>authorization</b> -- the application is responsible for using the contents
|
19
|
+
of the global session to make authorization decisions.
|
14
20
|
|
15
21
|
* <b>secrecy</b> -- global session attributes can be signed but never encrypted;
|
16
|
-
protect against third-party snooping using SSL
|
17
|
-
users to see their session state, put it in a database
|
22
|
+
protect against third-party snooping using SSL. Group secrecy is expensive;
|
23
|
+
if you don't want your users to see their session state, put it in a database,
|
24
|
+
or in an encrypted local session cookie.
|
18
25
|
|
19
26
|
* <b>replication</b> -- the authentication authorities must have some way to
|
20
|
-
share information about the database of users
|
27
|
+
share information about the database of users in order to authenticate
|
28
|
+
them and place identifying information into the global session.
|
21
29
|
|
22
30
|
* <b>single sign-out</b> -- the authorities must have some way to broadcast a
|
23
31
|
notification when sessions are invalidated; they can override the default
|
24
32
|
Directory implementation to do realtime revocation checking.
|
25
33
|
|
26
|
-
|
34
|
+
= Example
|
35
|
+
|
36
|
+
1) Create a basic config file and edit it to suit your needs:
|
37
|
+
$ script/generate global_session_config mycoolapp.com
|
38
|
+
|
39
|
+
2) Create an authentication authority:
|
40
|
+
$ script/generate global_session_authority mycoolapp
|
41
|
+
|
42
|
+
3) Declare that some or all of your controllers will use the global session:
|
43
|
+
class ApplicationController < ActionController::Base
|
44
|
+
has_global_session
|
45
|
+
end
|
46
|
+
|
47
|
+
4) Make use of the global session hash in your controllers:
|
48
|
+
global_session['user'] = @user.id
|
49
|
+
...
|
50
|
+
@current_user = User.find(global_session['user'])
|
51
|
+
|
52
|
+
5) For easier programming, enable seamless integration with the local session:
|
53
|
+
(in global_session.yml)
|
54
|
+
common:
|
55
|
+
integrated: true
|
56
|
+
|
57
|
+
(in your controllers)
|
58
|
+
session['user'] = @user.id #goes to the global session
|
59
|
+
session['local_thingie'] = @thingie.id #goes to the local session
|
60
|
+
|
61
|
+
= Global Session Contents
|
27
62
|
|
28
63
|
Global session state is stored as a cookie in the user's browser. The cookie
|
29
64
|
is a Zlib-compressed JSON dictionary containing the following stuff:
|
30
|
-
* session metadata (UUID, created-at, expires-at,
|
65
|
+
* session metadata (UUID, created-at, expires-at, signing-authority)
|
31
66
|
* signed session attributes (e.g. the authenticated user ID)
|
32
67
|
* insecure session attributes (e.g. the last-visited URL)
|
33
68
|
* a cryptographic signature of the metadata and signed attributes
|
34
69
|
|
35
70
|
The global session is unserialized and its signature is verified whenever
|
36
|
-
a controller asks for
|
37
|
-
whenever
|
71
|
+
a controller asks for one of its attributes. The cookie's value is updated
|
72
|
+
whenever attributes change. As an optimization, the signature is only
|
38
73
|
recomputed when the metadata or signed attributes have changed; insecure
|
39
74
|
attributes can change "for free."
|
40
75
|
|
41
76
|
Because the security properties of attributes can vary, HasGlobalSession
|
42
77
|
requires all _possible_ attributes to be declared up-front in the config
|
43
78
|
file. The 'attributes' section of the config file defines the _schema_
|
44
|
-
for the global session: which attributes can be used,
|
45
|
-
|
79
|
+
for the global session: which attributes can be used, which can be trusted
|
80
|
+
to make authorization decisions (because they are signed), and are insecure
|
81
|
+
and therefore act only as "hints" about the session.
|
46
82
|
|
47
83
|
Since the session is serialized as JSON, only a limited range of object
|
48
84
|
types can be stored in it: strings, numbers, lists, hashes and other Ruby
|
49
85
|
primitives. Ruby booleans (true/false) do not translate well into JSON
|
50
86
|
and should be avoided.
|
51
87
|
|
52
|
-
= Example
|
53
|
-
|
54
|
-
1) Create a basic config file and edit it to suit your needs:
|
55
|
-
$ script/generate global_session_config mycoolapp.com
|
56
|
-
|
57
|
-
2) Create an authentication authority:
|
58
|
-
$ script/generate global_session_authority mycoolapp
|
59
|
-
|
60
|
-
3) Declare that some or all of your application's controllers will have access
|
61
|
-
to the global session:
|
62
|
-
class ApplicationController < ActionController::Base
|
63
|
-
has_global_session
|
64
|
-
end
|
65
|
-
|
66
|
-
4) Make use of the global session hash in your controllers:
|
67
|
-
global_session['user'] = @user.id
|
68
|
-
...
|
69
|
-
@current_user = User.find(global_session['user'])
|
70
|
-
|
71
88
|
= Detailed Information
|
72
89
|
|
73
90
|
== Global Session Domain
|
74
91
|
|
75
92
|
We refer to collection of _all_ Web application instances capable of using the
|
76
93
|
global session as the "domain." The global session domain may consist of any
|
77
|
-
number of distinct
|
78
|
-
The
|
94
|
+
number of distinct nodes, possibly hidden behind load balancers or proxies.
|
95
|
+
The nodes within the domain may all be running the same Rails application,
|
79
96
|
or they may be running different codebases that represent different parts of
|
80
97
|
a distributed application. (They may also be using app frameworks other than
|
81
98
|
Rails.)
|
82
99
|
|
83
|
-
The only constraint imposed by HasGlobalSession is that all
|
100
|
+
The only constraint imposed by HasGlobalSession is that all nodes within the
|
84
101
|
domain must have end-user-facing URLs within the same second-level DNS domain.
|
85
102
|
This is due to limitations imposed by the HTTP cookie mechanism: for privacy
|
86
|
-
reasons, cookies will only be sent to
|
87
|
-
|
103
|
+
reasons, cookies will only be sent to nodes within the same domain as the
|
104
|
+
node that first created them.
|
88
105
|
|
89
106
|
For example, in my HasGlobalSession configuration file I might specify that my
|
90
|
-
cookie's domain is "example.com". My app
|
107
|
+
cookie's domain is "example.com". My app nodes at app1.example.com and
|
91
108
|
app2.example.com would be part of the global session domain, but my business
|
92
|
-
partner's application at
|
109
|
+
partner's application at app3.partner.com could not participate.
|
93
110
|
|
94
111
|
== Authorities and Relying Parties
|
95
112
|
|
96
|
-
A
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
113
|
+
A node that can create or update the global session is said to be an "authority"
|
114
|
+
(because it's trusted by other parties to make assertions about global session
|
115
|
+
state). An application that can read the global session is said to be a "relying
|
116
|
+
party." In practice, every application is a relying party, but not all of them
|
117
|
+
need to be authorities.
|
101
118
|
|
102
119
|
There is an RSA key pair associated with each authority. The authority's
|
103
120
|
public key is distribued to all relying parties, but the private key must
|
104
121
|
remain a secret to that authority (which may consist of many individual
|
105
|
-
|
122
|
+
nodes).
|
106
123
|
|
107
124
|
This system allows for significant flexibility when configuring a distributed
|
108
125
|
app's global session. There must be at least one authority, but for many apps
|
@@ -117,7 +134,7 @@ Here are some reasons you might consider dividing your systems into different
|
|
117
134
|
authorities:
|
118
135
|
* beta/staging system vs. production system
|
119
136
|
* system hosted by a third party vs. system hosted internally
|
120
|
-
* e-commerce
|
137
|
+
* e-commerce node vs. storefront node
|
121
138
|
|
122
139
|
== The Directory
|
123
140
|
|
@@ -131,21 +148,41 @@ signing session attributes.
|
|
131
148
|
|
132
149
|
The Directory implementation included with HasGlobalSession uses the filesystem
|
133
150
|
as the backing store for its key pairs. Its #initialize method accepts a
|
134
|
-
filesystem path that will be searched for
|
135
|
-
|
151
|
+
filesystem path that will be searched for files containing PEM-encoded public
|
152
|
+
and private keys (the same format used by OpenSSH). This simple Directory
|
153
|
+
implementation relies on the following conventions:
|
154
|
+
* Public keys have a *.pub extension.
|
155
|
+
* Private keys have a *.key extension.
|
156
|
+
* If a node is an authority, then one (and *only* one) *.key file should exist.
|
157
|
+
* The local node's authority name is inferred from the name of the private key
|
158
|
+
file.
|
136
159
|
|
137
160
|
When used with a Rails app, HasGlobalSession expects to find its keystore in
|
138
161
|
config/authorities. You can use the global_session generator to create new key
|
139
|
-
pairs. Remember never to check a *.key file into a public repository!! (
|
140
|
-
|
162
|
+
pairs. Remember never to check a *.key file into a public repository!! (*.pub
|
163
|
+
files can be checked into source control and distributed freely.)
|
141
164
|
|
142
165
|
If you wish all of the systems to stop trusting an authority, simply delete
|
143
|
-
its public key from config/authorities.
|
166
|
+
its public key from config/authorities and re-deploy your app.
|
167
|
+
|
168
|
+
=== Implementing Your Own Directory Provider
|
169
|
+
|
170
|
+
To replace or enhance the built-in Directory, simply create a new class that
|
171
|
+
extends Directory and put the class somewhere in your app (the lib directory
|
172
|
+
is a good choice). In the HasGlobalSession configuration file, specify the
|
173
|
+
class name of the directory under the 'common' section, like so:
|
174
|
+
common:
|
175
|
+
integrated: true
|
176
|
+
directory: MyCoolDirectory
|
144
177
|
|
145
178
|
= To-Do
|
146
179
|
|
147
180
|
* Configurable session expiry
|
181
|
+
|
148
182
|
* Option to auto-renew session
|
149
|
-
|
183
|
+
|
184
|
+
* Option for non-sticky global session
|
185
|
+
(e.g. cookie expires at close of browser session, not at global session
|
186
|
+
expiration!)
|
150
187
|
|
151
188
|
Copyright (c) 2010 Tony Spataro <code@tracker.xeger.net>, released under the MIT license
|
data/has_global_session.gemspec
CHANGED
@@ -7,7 +7,7 @@ spec = Gem::Specification.new do |s|
|
|
7
7
|
s.required_ruby_version = Gem::Requirement.new(">= 1.8.7")
|
8
8
|
|
9
9
|
s.name = 'has_global_session'
|
10
|
-
s.version = '0.8.
|
10
|
+
s.version = '0.8.1'
|
11
11
|
s.date = '2010-06-01'
|
12
12
|
|
13
13
|
s.authors = ['Tony Spataro']
|
@@ -17,10 +17,10 @@ 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 Rails plugin allows several Rails web apps that share the same back-end user database to share session state in a cryptographically secure way, 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.7"])
|
21
21
|
|
22
22
|
basedir = File.dirname(__FILE__)
|
23
|
-
candidates = ['has_global_session.gemspec', 'init.rb', 'MIT-LICENSE', 'README'] +
|
23
|
+
candidates = ['has_global_session.gemspec', 'init.rb', 'MIT-LICENSE', 'README.rdoc'] +
|
24
24
|
Dir['lib/**/*'] +
|
25
25
|
Dir['rails/**/*']
|
26
26
|
s.files = candidates.sort
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class GlobalSessionAuthorityGenerator < Rails::Generator::Base
|
2
|
+
def initialize(runtime_args, runtime_options = {})
|
3
|
+
super
|
4
|
+
|
5
|
+
@app_name = File.basename(RAILS_ROOT)
|
6
|
+
@auth_name = args.shift
|
7
|
+
raise ArgumentError, "Must specify name for global session authority, e.g. 'mycoolapp'" unless @auth_name
|
8
|
+
end
|
9
|
+
|
10
|
+
def manifest
|
11
|
+
record do |m|
|
12
|
+
new_key = OpenSSL::PKey::RSA.generate( 1024 )
|
13
|
+
new_public = new_key.public_key.to_pem
|
14
|
+
new_private = new_key.to_pem
|
15
|
+
|
16
|
+
dest_dir = File.join(RAILS_ROOT, 'config', 'authorities')
|
17
|
+
FileUtils.mkdir_p(dest_dir)
|
18
|
+
|
19
|
+
File.open(File.join(dest_dir, @auth_name + ".pub"), 'w') do |f|
|
20
|
+
f.puts new_public
|
21
|
+
end
|
22
|
+
|
23
|
+
File.open(File.join(dest_dir, @auth_name + ".key"), 'w') do |f|
|
24
|
+
f.puts new_private
|
25
|
+
end
|
26
|
+
|
27
|
+
puts "***"
|
28
|
+
puts "*** Don't forget to delete config/authorities/#{@auth_name}.key"
|
29
|
+
puts "***"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -10,7 +10,7 @@ class GlobalSessionConfigGenerator < Rails::Generator::Base
|
|
10
10
|
def manifest
|
11
11
|
record do |m|
|
12
12
|
|
13
|
-
m.template '
|
13
|
+
m.template 'global_session.yml.erb',
|
14
14
|
'config/global_session.yml',
|
15
15
|
:assigns=>{:app_name=>@app_name,
|
16
16
|
:app_domain=>@app_domain}
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# Common settings of the global session (that apply to all Rails environments)
|
2
|
-
# are listed here. These may be overidden in the environment-specific section
|
3
|
-
# but it seldom makes sense to do so.
|
2
|
+
# are listed here. These may be overidden in the environment-specific section.
|
4
3
|
common:
|
5
4
|
attributes:
|
6
5
|
# Signed attributes of the global session
|
@@ -14,17 +13,30 @@ common:
|
|
14
13
|
# global attributes always taking precedence over local attributes.
|
15
14
|
integrated: true
|
16
15
|
|
17
|
-
|
16
|
+
# Test/spec runs
|
17
|
+
test:
|
18
|
+
timeout: 900
|
18
19
|
cookie:
|
19
|
-
name: __<%= app_name %>
|
20
|
+
name: __<%= app_name %>_test
|
20
21
|
domain: localhost
|
22
|
+
trust:
|
23
|
+
- test
|
21
24
|
|
22
|
-
|
25
|
+
# Development mode
|
26
|
+
development:
|
27
|
+
timeout: 3600
|
23
28
|
cookie:
|
24
|
-
name: __<%= app_name %>
|
29
|
+
name: __<%= app_name %>_development
|
25
30
|
domain: localhost
|
31
|
+
trust:
|
32
|
+
- development
|
33
|
+
- production
|
26
34
|
|
35
|
+
# Production mode
|
27
36
|
production:
|
37
|
+
timeout: 3600
|
28
38
|
cookie:
|
29
39
|
name: __<%= app_name %>_global
|
30
40
|
domain: <%= app_domain %>
|
41
|
+
trust:
|
42
|
+
- production
|
@@ -4,23 +4,13 @@ module HasGlobalSession
|
|
4
4
|
mattr_accessor :environment
|
5
5
|
|
6
6
|
def self.[](key)
|
7
|
-
|
8
|
-
raise MissingConfiguration, "config_file is nil; cannot read configuration" unless config_file
|
9
|
-
raise MissingConfiguration, "environment is nil; must be specified" unless environment
|
10
|
-
@config = YAML.load(File.read(config_file))
|
11
|
-
validate
|
12
|
-
end
|
13
|
-
if @config.has_key?(environment) && @config[environment].has_key?(key)
|
14
|
-
return @config[environment][key]
|
15
|
-
else
|
16
|
-
@config['common'][key]
|
17
|
-
end
|
7
|
+
get(key, true)
|
18
8
|
end
|
19
9
|
|
20
10
|
def self.validate
|
21
11
|
['attributes/signed', 'integrated', 'cookie/name', 'cookie/domain'].each do |path|
|
22
12
|
elements = path.split '/'
|
23
|
-
object =
|
13
|
+
object = get(elements.shift, false)
|
24
14
|
elements.each do |element|
|
25
15
|
object = object[element]
|
26
16
|
if object.nil?
|
@@ -30,5 +20,23 @@ module HasGlobalSession
|
|
30
20
|
end
|
31
21
|
end
|
32
22
|
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def self.get(key, validated)
|
26
|
+
unless @config
|
27
|
+
raise MissingConfiguration, "config_file is nil; cannot read configuration" unless config_file
|
28
|
+
raise MissingConfiguration, "environment is nil; must be specified" unless environment
|
29
|
+
@config = YAML.load(File.read(config_file))
|
30
|
+
raise TypeError, "#{config_file} must contain a Hash!" unless Hash === @config
|
31
|
+
validate if validated
|
32
|
+
end
|
33
|
+
if @config.has_key?(environment) &&
|
34
|
+
@config[environment].respond_to?(:has_key?) &&
|
35
|
+
@config[environment].has_key?(key)
|
36
|
+
return @config[environment][key]
|
37
|
+
else
|
38
|
+
@config['common'][key]
|
39
|
+
end
|
40
|
+
end
|
33
41
|
end
|
34
42
|
end
|
@@ -36,6 +36,12 @@ module HasGlobalSession
|
|
36
36
|
raise SecurityError, "Signature mismatch on global session cookie; tampering suspected"
|
37
37
|
end
|
38
38
|
|
39
|
+
unless Configuration['trust'].blank? ||
|
40
|
+
@authority = @directory.my_authority_name ||
|
41
|
+
Configuration['trust'].include?(@authority)
|
42
|
+
raise SecurityError, "Global sessions created by #{@authority} are not trusted"
|
43
|
+
end
|
44
|
+
|
39
45
|
if expired? || @directory.invalidated_session?(@id)
|
40
46
|
raise ExpiredSession, "Global session cookie has expired"
|
41
47
|
end
|
@@ -43,25 +49,25 @@ module HasGlobalSession
|
|
43
49
|
else
|
44
50
|
@signed = {}
|
45
51
|
@insecure = {}
|
46
|
-
@id =
|
52
|
+
@id = UUID.timestamp_create.to_s
|
47
53
|
@created_at = Time.now.utc
|
48
|
-
@expires_at = 2.hours.from_now.utc #TODO configurable
|
49
54
|
@authority = @directory.my_authority_name
|
50
|
-
|
55
|
+
renew!
|
51
56
|
end
|
52
57
|
end
|
53
58
|
|
54
|
-
def supports_key?(key)
|
55
|
-
@schema_signed.include?(key) || @schema_insecure.include?(key)
|
56
|
-
end
|
57
|
-
|
58
59
|
def expired?
|
59
60
|
(@expires_at <= Time.now)
|
60
61
|
end
|
61
62
|
|
62
63
|
def expire!
|
63
64
|
@expires_at = Time.at(0)
|
64
|
-
@
|
65
|
+
@dirty = true
|
66
|
+
end
|
67
|
+
|
68
|
+
def renew!
|
69
|
+
@expires_at = Configuration['timeout'].to_i.minutes.from_now.utc || 1.hours.from_now.utc
|
70
|
+
@dirty = true
|
65
71
|
end
|
66
72
|
|
67
73
|
def to_s
|
@@ -69,7 +75,7 @@ module HasGlobalSession
|
|
69
75
|
'tc'=>@created_at.to_i, 'te'=>@expires_at.to_i,
|
70
76
|
'ds'=>@signed, 'dx'=>@insecure}
|
71
77
|
|
72
|
-
if @signature && !@
|
78
|
+
if @signature && !@dirty
|
73
79
|
#use cached signature unless we've changed secure state
|
74
80
|
authority = @authority
|
75
81
|
signature = @signature
|
@@ -82,23 +88,34 @@ module HasGlobalSession
|
|
82
88
|
|
83
89
|
hash['s'] = signature
|
84
90
|
hash['a'] = authority
|
85
|
-
json = ActiveSupport::JSON.encode(hash)
|
91
|
+
json = hash.to_json #ActiveSupport::JSON.encode(hash) -- why does this expect Data sometimes?!
|
86
92
|
zbin = Zlib::Deflate.deflate(json, Zlib::BEST_COMPRESSION)
|
87
93
|
return Base64.encode64(zbin)
|
88
94
|
end
|
89
95
|
|
96
|
+
def supports_key?(key)
|
97
|
+
@schema_signed.include?(key) || @schema_insecure.include?(key)
|
98
|
+
end
|
99
|
+
|
90
100
|
def [](key)
|
91
101
|
@signed[key] || @insecure[key]
|
92
102
|
end
|
93
103
|
|
94
104
|
def []=(key, value)
|
105
|
+
case value
|
106
|
+
when String, Numeric, Array
|
107
|
+
#no-op
|
108
|
+
else
|
109
|
+
raise TypeError, "Cannot store values of type #{value.class.name} reliably"
|
110
|
+
end
|
111
|
+
|
95
112
|
if @schema_signed.include?(key)
|
96
113
|
unless @directory.my_private_key && @directory.my_authority_name
|
97
114
|
raise StandardError, 'Cannot change secure session attributes; we are not an authority'
|
98
115
|
end
|
99
116
|
|
100
117
|
@signed[key] = value
|
101
|
-
@
|
118
|
+
@dirty = true
|
102
119
|
elsif @schema_insecure.include?(key)
|
103
120
|
@insecure[key] = value
|
104
121
|
else
|
@@ -109,7 +126,7 @@ module HasGlobalSession
|
|
109
126
|
def has_key?(key)
|
110
127
|
@signed.has_key(key) || @insecure.has_key?(key)
|
111
128
|
end
|
112
|
-
|
129
|
+
|
113
130
|
def keys
|
114
131
|
@signed.keys + @insecure.keys
|
115
132
|
end
|
@@ -6,6 +6,7 @@ module HasGlobalSession
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def [](key)
|
9
|
+
key = key.to_s
|
9
10
|
if @global_session.supports_key?(key)
|
10
11
|
@global_session[key]
|
11
12
|
else
|
@@ -14,6 +15,7 @@ module HasGlobalSession
|
|
14
15
|
end
|
15
16
|
|
16
17
|
def []=(key, value)
|
18
|
+
key = key.to_s
|
17
19
|
if @global_session.supports_key?(key)
|
18
20
|
@global_session[key] = value
|
19
21
|
else
|
@@ -22,6 +24,7 @@ module HasGlobalSession
|
|
22
24
|
end
|
23
25
|
|
24
26
|
def has_key?(key)
|
27
|
+
key = key.to_s
|
25
28
|
@global_session.has_key(key) || @local_session.has_key?(key)
|
26
29
|
end
|
27
30
|
|
@@ -4,8 +4,14 @@ module HasGlobalSession
|
|
4
4
|
return @global_session if @global_session
|
5
5
|
|
6
6
|
begin
|
7
|
+
if (klass = Configuration['directory'])
|
8
|
+
klass = klass.constantize
|
9
|
+
else
|
10
|
+
klass = Directory
|
11
|
+
end
|
12
|
+
|
13
|
+
directory = klass.new(File.join(RAILS_ROOT, 'config', 'authorities'))
|
7
14
|
cookie = cookies[Configuration['cookie']['name']]
|
8
|
-
directory = Directory.new(File.join(RAILS_ROOT, 'config', 'authorities'))
|
9
15
|
|
10
16
|
begin
|
11
17
|
#unserialize the global session from the cookie, or
|
@@ -44,5 +50,36 @@ module HasGlobalSession
|
|
44
50
|
cookies[Configuration['cookie']['name']] = options
|
45
51
|
end
|
46
52
|
end
|
53
|
+
|
54
|
+
def log_processing
|
55
|
+
if logger && logger.info?
|
56
|
+
log_processing_for_request_id
|
57
|
+
log_processing_for_parameters
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def log_processing_for_request_id()
|
62
|
+
if global_session && global_session.id
|
63
|
+
session_id = global_session.id + " (#{session[:session_id]})"
|
64
|
+
elsif session[:session_id]
|
65
|
+
session_id = session[:session_id]
|
66
|
+
elsif request.session_options[:id]
|
67
|
+
session_id = request.session_options[:id]
|
68
|
+
end
|
69
|
+
|
70
|
+
request_id = "\n\nProcessing #{self.class.name}\##{action_name} "
|
71
|
+
request_id << "to #{params[:format]} " if params[:format]
|
72
|
+
request_id << "(for #{request_origin.split[0]}) [#{request.method.to_s.upcase}]"
|
73
|
+
request_id << "\n Session ID: #{session_id}" if session_id
|
74
|
+
|
75
|
+
logger.info(request_id)
|
76
|
+
end
|
77
|
+
|
78
|
+
def log_processing_for_parameters
|
79
|
+
parameters = respond_to?(:filter_parameters) ? filter_parameters(params) : params.dup
|
80
|
+
parameters = parameters.except!(:controller, :action, :format, :_method)
|
81
|
+
|
82
|
+
logger.info " Parameters: #{parameters.inspect}" unless parameters.empty?
|
83
|
+
end
|
47
84
|
end
|
48
85
|
end
|
data/rails/init.rb
CHANGED
@@ -1,18 +1,21 @@
|
|
1
1
|
basedir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
2
2
|
require File.join(basedir, 'lib', 'has_global_session')
|
3
3
|
|
4
|
-
|
5
|
-
# and operating environment.
|
6
|
-
HasGlobalSession::Configuration.config_file =
|
7
|
-
File.join(RAILS_ROOT, 'config', 'global_session.yml')
|
8
|
-
HasGlobalSession::Configuration.environment = RAILS_ENV
|
4
|
+
config_file = File.join(RAILS_ROOT, 'config', 'global_session.yml')
|
9
5
|
|
10
|
-
|
6
|
+
if File.exist?(config_file)
|
7
|
+
# Tie the Configuration module to Rails' filesystem structure
|
8
|
+
# and operating environment.
|
9
|
+
HasGlobalSession::Configuration.config_file = config_file
|
10
|
+
HasGlobalSession::Configuration.environment = RAILS_ENV
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
require File.join(basedir, 'rails', 'action_controller_instance_methods')
|
13
|
+
|
14
|
+
# Enable ActionController integration.
|
15
|
+
class ActionController::Base
|
16
|
+
def self.has_global_session
|
17
|
+
include HasGlobalSession::ActionControllerInstanceMethods
|
18
|
+
after_filter :global_session_update_cookie
|
19
|
+
end
|
17
20
|
end
|
18
|
-
end
|
21
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: has_global_session
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 61
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 8
|
9
|
+
- 1
|
10
|
+
version: 0.8.1
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Tony Spataro
|
@@ -14,14 +20,20 @@ default_executable:
|
|
14
20
|
dependencies:
|
15
21
|
- !ruby/object:Gem::Dependency
|
16
22
|
name: uuidtools
|
17
|
-
|
18
|
-
|
19
|
-
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
20
26
|
requirements:
|
21
27
|
- - ">="
|
22
28
|
- !ruby/object:Gem::Version
|
23
|
-
|
24
|
-
|
29
|
+
hash: 25
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 0
|
33
|
+
- 7
|
34
|
+
version: 1.0.7
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
25
37
|
description: This Rails plugin allows several Rails web apps that share the same back-end user database to share session state in a cryptographically secure way, 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.
|
26
38
|
email: code@tracker.xeger.net
|
27
39
|
executables: []
|
@@ -32,9 +44,10 @@ extra_rdoc_files: []
|
|
32
44
|
|
33
45
|
files:
|
34
46
|
- MIT-LICENSE
|
35
|
-
- README
|
47
|
+
- README.rdoc
|
36
48
|
- has_global_session.gemspec
|
37
49
|
- init.rb
|
50
|
+
- lib/generators/global_session_authority/global_session_authority_generator.rb
|
38
51
|
- lib/generators/global_session_config/USAGE
|
39
52
|
- lib/generators/global_session_config/global_session_config_generator.rb
|
40
53
|
- lib/generators/global_session_config/templates/global_session.yml.erb
|
@@ -55,21 +68,29 @@ rdoc_options: []
|
|
55
68
|
require_paths:
|
56
69
|
- lib
|
57
70
|
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
58
72
|
requirements:
|
59
73
|
- - ">="
|
60
74
|
- !ruby/object:Gem::Version
|
75
|
+
hash: 57
|
76
|
+
segments:
|
77
|
+
- 1
|
78
|
+
- 8
|
79
|
+
- 7
|
61
80
|
version: 1.8.7
|
62
|
-
version:
|
63
81
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
64
83
|
requirements:
|
65
84
|
- - ">="
|
66
85
|
- !ruby/object:Gem::Version
|
86
|
+
hash: 3
|
87
|
+
segments:
|
88
|
+
- 0
|
67
89
|
version: "0"
|
68
|
-
version:
|
69
90
|
requirements: []
|
70
91
|
|
71
92
|
rubyforge_project:
|
72
|
-
rubygems_version: 1.3.
|
93
|
+
rubygems_version: 1.3.7
|
73
94
|
signing_key:
|
74
95
|
specification_version: 3
|
75
96
|
summary: Secure single-domain session sharing plugin for Rails.
|