has_global_session 0.8.1 → 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|