has_global_session 0.8.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/has_global_session.gemspec +4 -3
- data/init.rb +2 -2
- data/lib/has_global_session/directory.rb +6 -0
- data/lib/has_global_session/global_session.rb +18 -11
- data/rails/action_controller_instance_methods.rb +25 -30
- data/rails/init.rb +1 -1
- metadata +21 -9
- data/lib/generators/global_session_authority/global_session_authority_generator.rb +0 -32
- data/lib/generators/global_session_config/USAGE +0 -2
- data/lib/generators/global_session_config/global_session_config_generator.rb +0 -19
- data/lib/generators/global_session_config/templates/global_session.yml.erb +0 -42
data/has_global_session.gemspec
CHANGED
@@ -7,17 +7,18 @@ 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.
|
11
|
-
s.date = '2010-06-
|
10
|
+
s.version = '0.8.2'
|
11
|
+
s.date = '2010-06-09'
|
12
12
|
|
13
13
|
s.authors = ['Tony Spataro']
|
14
14
|
s.email = 'code@tracker.xeger.net'
|
15
15
|
s.homepage= 'http://github.com/xeger/has_global_session'
|
16
16
|
|
17
17
|
s.summary = %q{Secure single-domain session sharing plugin for Rails.}
|
18
|
-
s.description = %q{This Rails
|
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
20
|
s.add_runtime_dependency('uuidtools', [">= 1.0.7"])
|
21
|
+
s.add_runtime_dependency('json', [">= 1.1.7"])
|
21
22
|
|
22
23
|
basedir = File.dirname(__FILE__)
|
23
24
|
candidates = ['has_global_session.gemspec', 'init.rb', 'MIT-LICENSE', 'README.rdoc'] +
|
data/init.rb
CHANGED
@@ -23,6 +23,12 @@ module HasGlobalSession
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
def trusted_authority?(authority)
|
27
|
+
Configuration['trust'].blank? ||
|
28
|
+
authority == my_authority_name ||
|
29
|
+
Configuration['trust'].include?(authority)
|
30
|
+
end
|
31
|
+
|
26
32
|
def invalidated_session?(uuid)
|
27
33
|
false
|
28
34
|
end
|
@@ -18,7 +18,7 @@ module HasGlobalSession
|
|
18
18
|
#User presented us with a cookie; let's decrypt and verify it
|
19
19
|
zbin = Base64.decode64(cookie)
|
20
20
|
json = Zlib::Inflate.inflate(zbin)
|
21
|
-
hash =
|
21
|
+
hash = JSON.load(json)
|
22
22
|
@id = hash['id']
|
23
23
|
@created_at = Time.at(hash['tc'].to_i)
|
24
24
|
@expires_at = Time.at(hash['te'].to_i)
|
@@ -31,14 +31,13 @@ module HasGlobalSession
|
|
31
31
|
expected = digest(hash)
|
32
32
|
signer = @directory.authorities[@authority]
|
33
33
|
raise SecurityError, "Unknown signing authority #{@authority}" unless signer
|
34
|
+
|
34
35
|
got = signer.public_decrypt(Base64.decode64(@signature))
|
35
36
|
unless (got == expected)
|
36
37
|
raise SecurityError, "Signature mismatch on global session cookie; tampering suspected"
|
37
38
|
end
|
38
39
|
|
39
|
-
unless
|
40
|
-
@authority = @directory.my_authority_name ||
|
41
|
-
Configuration['trust'].include?(@authority)
|
40
|
+
unless @directory.trusted_authority?(@authority)
|
42
41
|
raise SecurityError, "Global sessions created by #{@authority} are not trusted"
|
43
42
|
end
|
44
43
|
|
@@ -49,7 +48,15 @@ module HasGlobalSession
|
|
49
48
|
else
|
50
49
|
@signed = {}
|
51
50
|
@insecure = {}
|
52
|
-
|
51
|
+
|
52
|
+
if defined?(::UUIDTools) # UUIDTools v2
|
53
|
+
@id = ::UUIDTools::UUID.timestamp_create.to_s
|
54
|
+
elsif defined?(::UUID) # UUIDTools v1
|
55
|
+
@id = ::UUID.timestamp_create.to_s
|
56
|
+
else
|
57
|
+
raise TypeError, "Neither UUIDTools nor UUID defined; unsupported UUIDTools version?"
|
58
|
+
end
|
59
|
+
|
53
60
|
@created_at = Time.now.utc
|
54
61
|
@authority = @directory.my_authority_name
|
55
62
|
renew!
|
@@ -88,7 +95,7 @@ module HasGlobalSession
|
|
88
95
|
|
89
96
|
hash['s'] = signature
|
90
97
|
hash['a'] = authority
|
91
|
-
json = hash.to_json
|
98
|
+
json = hash.to_json
|
92
99
|
zbin = Zlib::Deflate.deflate(json, Zlib::BEST_COMPRESSION)
|
93
100
|
return Base64.encode64(zbin)
|
94
101
|
end
|
@@ -143,21 +150,21 @@ module HasGlobalSession
|
|
143
150
|
private
|
144
151
|
|
145
152
|
def digest(input)
|
146
|
-
canonical =
|
153
|
+
canonical = canonicalize(input).to_json
|
147
154
|
return Digest::SHA1.new().update(canonical).hexdigest
|
148
155
|
end
|
149
156
|
|
150
157
|
def canonicalize(input)
|
151
158
|
case input
|
152
159
|
when Hash
|
153
|
-
output =
|
160
|
+
output = Array.new
|
154
161
|
ordered_keys = input.keys.sort
|
155
162
|
ordered_keys.each do |key|
|
156
|
-
output[canonicalize(key)
|
163
|
+
output << [ canonicalize(key), canonicalize(input[key]) ]
|
157
164
|
end
|
158
165
|
when Array
|
159
166
|
output = input.collect { |x| canonicalize(x) }
|
160
|
-
when Numeric, String
|
167
|
+
when Numeric, String
|
161
168
|
output = input
|
162
169
|
else
|
163
170
|
raise TypeError, "Objects of type #{input.class.name} cannot be serialized in the global session"
|
@@ -166,4 +173,4 @@ module HasGlobalSession
|
|
166
173
|
return output
|
167
174
|
end
|
168
175
|
end
|
169
|
-
end
|
176
|
+
end
|
@@ -3,28 +3,25 @@ module HasGlobalSession
|
|
3
3
|
def global_session
|
4
4
|
return @global_session if @global_session
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
6
|
+
if (klass = Configuration['directory'])
|
7
|
+
klass = klass.constantize
|
8
|
+
else
|
9
|
+
klass = Directory
|
10
|
+
end
|
12
11
|
|
13
|
-
|
14
|
-
|
12
|
+
directory = klass.new(File.join(RAILS_ROOT, 'config', 'authorities'))
|
13
|
+
cookie_name = Configuration['cookie']['name']
|
14
|
+
cookie = cookies[cookie_name]
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
rescue SessionExpired
|
21
|
-
#if the cookie is present but expired, silently
|
22
|
-
#initialize a new global session
|
23
|
-
@global_session = GlobalSession.new(directory)
|
24
|
-
end
|
16
|
+
begin
|
17
|
+
#unserialize the global session from the cookie, or
|
18
|
+
#initialize a new global session if cookie == nil
|
19
|
+
@global_session = GlobalSession.new(directory, cookie)
|
25
20
|
rescue Exception => e
|
26
|
-
|
27
|
-
|
21
|
+
#silently recover from any error by initializing a new global session;
|
22
|
+
#the new session will be unauthenticated.
|
23
|
+
#TODO log the error
|
24
|
+
@global_session = GlobalSession.new(directory)
|
28
25
|
end
|
29
26
|
end
|
30
27
|
|
@@ -36,18 +33,16 @@ module HasGlobalSession
|
|
36
33
|
end
|
37
34
|
|
38
35
|
def global_session_update_cookie
|
39
|
-
|
40
|
-
if @global_session.expired?
|
41
|
-
options = {:value => nil,
|
42
|
-
:domain => Configuration['cookie']['domain'],
|
43
|
-
:expires => Time.at(0)}
|
44
|
-
else
|
45
|
-
options = {:value => @global_session.to_s,
|
46
|
-
:domain => Configuration['cookie']['domain'],
|
47
|
-
:expires => @global_session.expires_at}
|
48
|
-
end
|
36
|
+
return unless @global_session
|
49
37
|
|
50
|
-
|
38
|
+
cookie_name = Configuration['cookie']['name']
|
39
|
+
if @global_session.expired?
|
40
|
+
cookies.delete cookie_name
|
41
|
+
else
|
42
|
+
options = {:value => @global_session.to_s,
|
43
|
+
:domain => Configuration['cookie']['domain'],
|
44
|
+
:expires => @global_session.expires_at}
|
45
|
+
cookies[cookie_name] = options
|
51
46
|
end
|
52
47
|
end
|
53
48
|
|
data/rails/init.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: has_global_session
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 59
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 8
|
9
|
-
-
|
10
|
-
version: 0.8.
|
9
|
+
- 2
|
10
|
+
version: 0.8.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Tony Spataro
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-06-
|
18
|
+
date: 2010-06-09 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -34,7 +34,23 @@ dependencies:
|
|
34
34
|
version: 1.0.7
|
35
35
|
type: :runtime
|
36
36
|
version_requirements: *id001
|
37
|
-
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: json
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 29
|
46
|
+
segments:
|
47
|
+
- 1
|
48
|
+
- 1
|
49
|
+
- 7
|
50
|
+
version: 1.1.7
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
description: 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.
|
38
54
|
email: code@tracker.xeger.net
|
39
55
|
executables: []
|
40
56
|
|
@@ -47,10 +63,6 @@ files:
|
|
47
63
|
- README.rdoc
|
48
64
|
- has_global_session.gemspec
|
49
65
|
- init.rb
|
50
|
-
- lib/generators/global_session_authority/global_session_authority_generator.rb
|
51
|
-
- lib/generators/global_session_config/USAGE
|
52
|
-
- lib/generators/global_session_config/global_session_config_generator.rb
|
53
|
-
- lib/generators/global_session_config/templates/global_session.yml.erb
|
54
66
|
- lib/has_global_session.rb
|
55
67
|
- lib/has_global_session/configuration.rb
|
56
68
|
- lib/has_global_session/directory.rb
|
@@ -1,32 +0,0 @@
|
|
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
|
@@ -1,19 +0,0 @@
|
|
1
|
-
class GlobalSessionConfigGenerator < Rails::Generator::Base
|
2
|
-
def initialize(runtime_args, runtime_options = {})
|
3
|
-
super
|
4
|
-
|
5
|
-
@app_name = File.basename(RAILS_ROOT)
|
6
|
-
@app_domain = args.shift
|
7
|
-
raise ArgumentError, "Must specify DNS domain for global session cookie, e.g. 'example.com'" unless @app_domain
|
8
|
-
end
|
9
|
-
|
10
|
-
def manifest
|
11
|
-
record do |m|
|
12
|
-
|
13
|
-
m.template 'global_session.yml.erb',
|
14
|
-
'config/global_session.yml',
|
15
|
-
:assigns=>{:app_name=>@app_name,
|
16
|
-
:app_domain=>@app_domain}
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,42 +0,0 @@
|
|
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
|
-
common:
|
4
|
-
attributes:
|
5
|
-
# Signed attributes of the global session
|
6
|
-
signed:
|
7
|
-
- user
|
8
|
-
# Untrusted attributes of the global session
|
9
|
-
insecure:
|
10
|
-
- account
|
11
|
-
# Enable local session integration in order to use the ActionController
|
12
|
-
# method #session to access both local AND global session state, with
|
13
|
-
# global attributes always taking precedence over local attributes.
|
14
|
-
integrated: true
|
15
|
-
|
16
|
-
# Test/spec runs
|
17
|
-
test:
|
18
|
-
timeout: 900
|
19
|
-
cookie:
|
20
|
-
name: __<%= app_name %>_test
|
21
|
-
domain: localhost
|
22
|
-
trust:
|
23
|
-
- test
|
24
|
-
|
25
|
-
# Development mode
|
26
|
-
development:
|
27
|
-
timeout: 3600
|
28
|
-
cookie:
|
29
|
-
name: __<%= app_name %>_development
|
30
|
-
domain: localhost
|
31
|
-
trust:
|
32
|
-
- development
|
33
|
-
- production
|
34
|
-
|
35
|
-
# Production mode
|
36
|
-
production:
|
37
|
-
timeout: 3600
|
38
|
-
cookie:
|
39
|
-
name: __<%= app_name %>_global
|
40
|
-
domain: <%= app_domain %>
|
41
|
-
trust:
|
42
|
-
- production
|