has_global_session 1.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/has_global_session.gemspec +2 -6
- data/lib/has_global_session.rb +3 -0
- data/lib/has_global_session/configuration.rb +29 -46
- data/lib/has_global_session/directory.rb +5 -4
- data/lib/has_global_session/global_session.rb +4 -3
- data/lib/has_global_session/integrated_session.rb +14 -0
- data/lib/has_global_session/rails.rb +1 -0
- data/lib/has_global_session/rails/action_controller_class_methods.rb +25 -0
- data/lib/has_global_session/rails/action_controller_instance_methods.rb +16 -7
- data/rails/init.rb +3 -11
- metadata +4 -2
data/has_global_session.gemspec
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
1
|
+
# -*- mode: ruby; encoding: utf-8 -*-
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
4
|
|
@@ -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 = '1.0'
|
10
|
+
s.version = '1.1.0'
|
11
11
|
s.date = '2010-07-27'
|
12
12
|
|
13
13
|
s.authors = ['Tony Spataro']
|
@@ -32,7 +32,3 @@ spec = Gem::Specification.new do |s|
|
|
32
32
|
Dir['rails_generators/**/*']
|
33
33
|
s.files = candidates.sort
|
34
34
|
end
|
35
|
-
|
36
|
-
if $PROGRAM_NAME == __FILE__
|
37
|
-
Gem::Builder.new(spec).build
|
38
|
-
end
|
data/lib/has_global_session.rb
CHANGED
@@ -49,6 +49,9 @@ require 'uuidtools'
|
|
49
49
|
require 'json'
|
50
50
|
require 'active_support'
|
51
51
|
|
52
|
+
#Require Ruby library dependencies
|
53
|
+
require 'openssl'
|
54
|
+
|
52
55
|
#Require the core suite of HasGlobalSession classes and modules
|
53
56
|
basedir = File.dirname(__FILE__)
|
54
57
|
require File.join(basedir, 'has_global_session', 'configuration')
|
@@ -22,6 +22,13 @@ module HasGlobalSession
|
|
22
22
|
# * name
|
23
23
|
# * domain
|
24
24
|
#
|
25
|
+
# === Config Environments
|
26
|
+
# The operational environment of has_global_session defines which section
|
27
|
+
# of the configuration file it gets its settings from. When used with
|
28
|
+
# a web app, the environment should be set to the same environment as
|
29
|
+
# the web app. (If using Rails integration, this happens for you
|
30
|
+
# automatically.)
|
31
|
+
#
|
25
32
|
# === Environment-Specific Settings
|
26
33
|
# The top level of keys in the configuration hash are special; they provide different
|
27
34
|
# sections of settings that apply in different environments. For instance, a Rails
|
@@ -44,55 +51,38 @@ module HasGlobalSession
|
|
44
51
|
# The name and location of the config file depend on the Web framework with which
|
45
52
|
# you are integrating; see HasGlobalSession::Rails for more information.
|
46
53
|
#
|
47
|
-
|
48
|
-
#
|
49
|
-
#
|
50
|
-
# === Return
|
51
|
-
# env(String):: The current configuration environment
|
52
|
-
def self.environment; @environment; end
|
53
|
-
|
54
|
-
# Writer for the environment module-attribute.
|
55
|
-
#
|
56
|
-
# === Parameters
|
57
|
-
# value(String):: Configuration environment from which settings should be read
|
58
|
-
#
|
59
|
-
# === Return
|
60
|
-
# env(String):: The new configuration environment
|
61
|
-
def self.environment=(value); @environment = value; end
|
62
|
-
|
63
|
-
# Reader for the config_file module-attribute.
|
64
|
-
#
|
65
|
-
# === Return
|
66
|
-
# file(String):: Absolute path to configuration file
|
67
|
-
def self.config_file; @config_file; end
|
68
|
-
|
69
|
-
# Writer for the config_file module-attribute.
|
54
|
+
class Configuration
|
55
|
+
# Create a new Configuration objectt
|
70
56
|
#
|
71
57
|
# === Parameters
|
72
|
-
#
|
58
|
+
# config_File(String):: Absolute path to the configuration file
|
59
|
+
# environment(String):: Config file section from which
|
73
60
|
#
|
74
|
-
# ===
|
75
|
-
#
|
76
|
-
|
61
|
+
# === Raise
|
62
|
+
# MissingConfiguration:: if config file is missing or unreadable
|
63
|
+
# TypeError:: if config file does not contain a YAML-serialized Hash
|
64
|
+
def initialize(config_file, environment)
|
65
|
+
raise MissingConfiguration, "Missing or unreadable configuration file" unless File.readable?(config_file)
|
66
|
+
@config = YAML.load(File.read(config_file))
|
67
|
+
@environment = environment
|
68
|
+
raise TypeError, "#{config_file} must contain a Hash!" unless Hash === @config
|
69
|
+
validate
|
70
|
+
end
|
77
71
|
|
78
72
|
# Reader for configuration elements. The reader first checks
|
79
73
|
# the current environment's settings section for the named
|
80
74
|
# value; if not found, it checks the common settings section.
|
81
75
|
#
|
82
76
|
# === Parameters
|
83
|
-
#
|
77
|
+
# key(String):: Name of configuration element to retrieve
|
84
78
|
#
|
85
79
|
# === Return
|
86
|
-
#
|
87
|
-
|
88
|
-
# === Raise
|
89
|
-
# MissingConfiguration:: if config file location is unset, environment is unset, or config file is missing
|
90
|
-
# TypeError:: if config file does not contain a YAML-serialized Hash
|
91
|
-
def self.[](key)
|
80
|
+
# value(String):: the value of the configuration element
|
81
|
+
def [](key)
|
92
82
|
get(key, true)
|
93
83
|
end
|
94
84
|
|
95
|
-
def
|
85
|
+
def validate # :nodoc
|
96
86
|
['attributes/signed', 'integrated', 'cookie/name', 'timeout'].each do |path|
|
97
87
|
elements = path.split '/'
|
98
88
|
object = get(elements.shift, false)
|
@@ -108,17 +98,10 @@ module HasGlobalSession
|
|
108
98
|
|
109
99
|
private
|
110
100
|
|
111
|
-
def
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
@config = YAML.load(File.read(config_file))
|
116
|
-
raise TypeError, "#{config_file} must contain a Hash!" unless Hash === @config
|
117
|
-
validate if validated
|
118
|
-
end
|
119
|
-
if @config.has_key?(environment) &&
|
120
|
-
@config[environment].has_key?(key)
|
121
|
-
return @config[environment][key]
|
101
|
+
def get(key, validated) # :nodoc
|
102
|
+
if @config.has_key?(@environment) &&
|
103
|
+
@config[@environment].has_key?(key)
|
104
|
+
return @config[@environment][key]
|
122
105
|
else
|
123
106
|
@config['common'][key]
|
124
107
|
end
|
@@ -29,7 +29,7 @@ module HasGlobalSession
|
|
29
29
|
# at initialization time.
|
30
30
|
#
|
31
31
|
class Directory
|
32
|
-
attr_reader :authorities, :private_key, :local_authority_name
|
32
|
+
attr_reader :configuration, :authorities, :private_key, :local_authority_name
|
33
33
|
|
34
34
|
# Create a new Directory.
|
35
35
|
#
|
@@ -38,7 +38,8 @@ module HasGlobalSession
|
|
38
38
|
#
|
39
39
|
# ===Raise
|
40
40
|
# ConfigurationError:: if too many or too few keys are found, or if *.key/*.pub files are malformatted
|
41
|
-
def initialize(keystore_directory)
|
41
|
+
def initialize(configuration, keystore_directory)
|
42
|
+
@configuration = configuration
|
42
43
|
certs = Dir[File.join(keystore_directory, '*.pub')]
|
43
44
|
keys = Dir[File.join(keystore_directory, '*.key')]
|
44
45
|
raise ConfigurationError, "Excepted 0 or 1 key files, found #{keys.size}" unless [0, 1].include?(keys.size)
|
@@ -51,7 +52,7 @@ module HasGlobalSession
|
|
51
52
|
raise ConfigurationError, "Expected #{basename} to contain an RSA public key" unless @authorities[authority].public?
|
52
53
|
end
|
53
54
|
|
54
|
-
if (authority_name =
|
55
|
+
if (authority_name = @configuration['authority'])
|
55
56
|
key_file = keys.detect { |kf| kf =~ /#{authority_name}.key$/ }
|
56
57
|
raise ConfigurationError, "Key file #{authority_name}.key not found" unless key_file
|
57
58
|
@private_key = OpenSSL::PKey::RSA.new(File.read(key_file))
|
@@ -69,7 +70,7 @@ module HasGlobalSession
|
|
69
70
|
# === Return
|
70
71
|
# trusted(true|false):: whether the local system trusts sessions signed by the specified authority
|
71
72
|
def trusted_authority?(authority)
|
72
|
-
|
73
|
+
@configuration['trust'].include?(authority)
|
73
74
|
end
|
74
75
|
|
75
76
|
# Determine whether the given session UUID is valid. The default implementation only considers
|
@@ -29,8 +29,9 @@ module HasGlobalSession
|
|
29
29
|
# MalformedCookie:: if the cookie was corrupt or malformed
|
30
30
|
# SecurityError:: if signature is invalid or cookie is not signed by a trusted authority
|
31
31
|
def initialize(directory, cookie=nil, valid_signature_digest=nil)
|
32
|
-
@
|
33
|
-
@
|
32
|
+
@configuration = directory.configuration
|
33
|
+
@schema_signed = Set.new((@configuration['attributes']['signed']))
|
34
|
+
@schema_insecure = Set.new((@configuration['attributes']['insecure']))
|
34
35
|
@directory = directory
|
35
36
|
|
36
37
|
if cookie && !cookie.empty?
|
@@ -200,7 +201,7 @@ module HasGlobalSession
|
|
200
201
|
# true:: Always returns true
|
201
202
|
def renew!
|
202
203
|
authority_check
|
203
|
-
@expired_at =
|
204
|
+
@expired_at = @configuration['timeout'].to_i.minutes.from_now.utc
|
204
205
|
@dirty_secure = true
|
205
206
|
end
|
206
207
|
|
@@ -105,5 +105,19 @@ module HasGlobalSession
|
|
105
105
|
@global.each_pair(&block)
|
106
106
|
@local.each_pair(&block)
|
107
107
|
end
|
108
|
+
|
109
|
+
def respond_to?(meth) # :nodoc:
|
110
|
+
return @global.respond_to?(meth) || @local.respond_to?(meth) || super
|
111
|
+
end
|
112
|
+
|
113
|
+
def method_missing(meth, *args) # :nodoc:
|
114
|
+
if @global.respond_to?(meth)
|
115
|
+
@global.__send__(meth, *args)
|
116
|
+
elsif @local.respond_to?(meth)
|
117
|
+
@local.__send__(meth, *args)
|
118
|
+
else
|
119
|
+
super
|
120
|
+
end
|
121
|
+
end
|
108
122
|
end
|
109
123
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module HasGlobalSession
|
2
|
+
module Rails
|
3
|
+
# Module that is mixed into ActionController's eigenclass; provides access to shared
|
4
|
+
# app-wide data such as the configuration object.
|
5
|
+
module ActionControllerClassMethods
|
6
|
+
def global_session_config
|
7
|
+
unless @global_session_config
|
8
|
+
config_file = File.join(RAILS_ROOT, 'config', 'global_session.yml')
|
9
|
+
@global_session_config = HasGlobalSession::Configuration.new(config_file, RAILS_ENV)
|
10
|
+
@global_session_config.config_file = config_file
|
11
|
+
end
|
12
|
+
|
13
|
+
return @global_session_config
|
14
|
+
end
|
15
|
+
|
16
|
+
def global_session_config=(config)
|
17
|
+
@global_session_config = config
|
18
|
+
end
|
19
|
+
|
20
|
+
def has_global_session
|
21
|
+
include HasGlobalSession::Rails::ActionControllerInstanceMethods
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -21,6 +21,15 @@ module HasGlobalSession
|
|
21
21
|
base.after_filter :global_session_update_cookie
|
22
22
|
end
|
23
23
|
|
24
|
+
# Shortcut accessor for global session configuration object. Simply delegates to
|
25
|
+
# the class method of the same name defined by ActionController::Base.
|
26
|
+
#
|
27
|
+
# === Return
|
28
|
+
# config(HasGlobalSession::Configuration)
|
29
|
+
def global_session_config
|
30
|
+
ActionController::Base.global_session_config
|
31
|
+
end
|
32
|
+
|
24
33
|
# Global session reader.
|
25
34
|
#
|
26
35
|
# === Return
|
@@ -35,7 +44,7 @@ module HasGlobalSession
|
|
35
44
|
# === Return
|
36
45
|
# session(IntegratedSession):: the integrated session
|
37
46
|
def session_with_global_session
|
38
|
-
if
|
47
|
+
if global_session_config['integrated'] && @global_session
|
39
48
|
unless @integrated_session &&
|
40
49
|
(@integrated_session.local == session_without_global_session) &&
|
41
50
|
(@integrated_session.global == @global_session)
|
@@ -56,7 +65,7 @@ module HasGlobalSession
|
|
56
65
|
# true:: Always returns true
|
57
66
|
def global_session_read_cookie
|
58
67
|
directory = global_session_create_directory
|
59
|
-
cookie_name =
|
68
|
+
cookie_name = global_session_config['cookie']['name']
|
60
69
|
cookie = cookies[cookie_name]
|
61
70
|
|
62
71
|
begin
|
@@ -89,7 +98,7 @@ module HasGlobalSession
|
|
89
98
|
# true:: Always returns true
|
90
99
|
def global_session_auto_renew
|
91
100
|
#Auto-renew session if needed
|
92
|
-
renew =
|
101
|
+
renew = global_session_config['renew']
|
93
102
|
if @global_session &&
|
94
103
|
renew &&
|
95
104
|
@global_session.directory.local_authority_name &&
|
@@ -105,13 +114,13 @@ module HasGlobalSession
|
|
105
114
|
# === Return
|
106
115
|
# true:: Always returns true
|
107
116
|
def global_session_update_cookie
|
108
|
-
name =
|
109
|
-
domain =
|
117
|
+
name = global_session_config['cookie']['name']
|
118
|
+
domain = global_session_config['cookie']['domain'] || request.env['SERVER_NAME']
|
110
119
|
|
111
120
|
begin
|
112
121
|
if @global_session && @global_session.valid?
|
113
122
|
value = @global_session.to_s
|
114
|
-
expires =
|
123
|
+
expires = global_session_config['ephemeral'] ? nil : @global_session.expired_at
|
115
124
|
|
116
125
|
unless (cookies[name] == value)
|
117
126
|
#Update the cookie only if its value has changed
|
@@ -172,7 +181,7 @@ module HasGlobalSession
|
|
172
181
|
private
|
173
182
|
|
174
183
|
def global_session_create_directory # :nodoc:
|
175
|
-
if (klass =
|
184
|
+
if (klass = global_session_config['directory'])
|
176
185
|
klass = klass.constantize
|
177
186
|
else
|
178
187
|
klass = Directory
|
data/rails/init.rb
CHANGED
@@ -1,21 +1,13 @@
|
|
1
1
|
basedir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
2
2
|
libdir = File.join(basedir, 'lib')
|
3
|
-
require File.join(libdir, 'has_global_session')
|
4
|
-
|
5
3
|
config_file = File.join(RAILS_ROOT, 'config', 'global_session.yml')
|
6
4
|
|
7
5
|
if File.exist?(config_file)
|
8
|
-
|
9
|
-
# and operating environment.
|
10
|
-
HasGlobalSession::Configuration.config_file = config_file
|
11
|
-
HasGlobalSession::Configuration.environment = RAILS_ENV
|
12
|
-
|
6
|
+
require File.join(libdir, 'has_global_session')
|
13
7
|
require File.join(libdir, 'has_global_session', 'rails')
|
14
8
|
|
15
9
|
# Enable ActionController integration.
|
16
|
-
class ActionController::Base
|
17
|
-
|
18
|
-
include HasGlobalSession::Rails::ActionControllerInstanceMethods
|
19
|
-
end
|
10
|
+
class <<ActionController::Base
|
11
|
+
include HasGlobalSession::Rails::ActionControllerClassMethods
|
20
12
|
end
|
21
13
|
end
|
metadata
CHANGED
@@ -1,12 +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: 19
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
version:
|
10
|
+
version: 1.1.0
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Tony Spataro
|
@@ -133,6 +134,7 @@ files:
|
|
133
134
|
- lib/has_global_session/global_session.rb
|
134
135
|
- lib/has_global_session/integrated_session.rb
|
135
136
|
- lib/has_global_session/rails.rb
|
137
|
+
- lib/has_global_session/rails/action_controller_class_methods.rb
|
136
138
|
- lib/has_global_session/rails/action_controller_instance_methods.rb
|
137
139
|
- rails/init.rb
|
138
140
|
- rails_generators/global_session_authority/USAGE
|