global_session 1.0.0 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.0'
11
- s.date = '2011-01-01'
10
+ s.version = '1.0.2'
11
+ s.date = '2011-01-15'
12
12
 
13
13
  s.authors = ['Tony Spataro']
14
14
  s.email = 'code@tracker.xeger.net'
@@ -21,11 +21,11 @@ spec = Gem::Specification.new do |s|
21
21
  s.add_runtime_dependency('json', [">= 1.1.7"])
22
22
  s.add_runtime_dependency('rack-contrib', [">= 1.0"])
23
23
 
24
- s.add_development_dependency('rake', ["~> 0.8.7"])
25
- s.add_development_dependency('ruby-debug', ["~> 0.10.3"])
26
- s.add_development_dependency('rspec', [">= 1.3.0"])
27
- s.add_development_dependency('flexmock', [">= 0.8.6"])
28
- s.add_development_dependency('actionpack', [">= 2.1.2"])
24
+ s.add_development_dependency('rake', [">= 0.8.7"])
25
+ s.add_development_dependency('ruby-debug', [">= 0.10.3"])
26
+ s.add_development_dependency('rspec', ["~> 1.3"])
27
+ s.add_development_dependency('flexmock', ["~> 0.8"])
28
+ s.add_development_dependency('actionpack', ["~> 2.3"])
29
29
 
30
30
  basedir = File.dirname(__FILE__)
31
31
  candidates = ['global_session.gemspec', 'init.rb', 'MIT-LICENSE', 'README.rdoc'] +
@@ -1,3 +1,5 @@
1
+ require 'set'
2
+
1
3
  module GlobalSession
2
4
  # The global session directory, which provides some lookup and decision services
3
5
  # to instances of Session.
@@ -29,7 +31,7 @@ module GlobalSession
29
31
  # at initialization time.
30
32
  #
31
33
  class Directory
32
- attr_reader :configuration, :authorities, :private_key, :local_authority_name
34
+ attr_reader :configuration, :authorities, :private_key
33
35
 
34
36
  # Create a new Directory.
35
37
  #
@@ -52,15 +54,20 @@ module GlobalSession
52
54
  raise ConfigurationError, "Expected #{basename} to contain an RSA public key" unless @authorities[authority].public?
53
55
  end
54
56
 
55
- if (authority_name = @configuration['authority'])
56
- key_file = keys.detect { |kf| kf =~ /#{authority_name}.key$/ }
57
- raise ConfigurationError, "Key file #{authority_name}.key not found" unless key_file
57
+ if local_authority_name
58
+ key_file = keys.detect { |kf| kf =~ /#{local_authority_name}.key$/ }
59
+ raise ConfigurationError, "Key file #{local_authority_name}.key not found" unless key_file
58
60
  @private_key = OpenSSL::PKey::RSA.new(File.read(key_file))
59
61
  raise ConfigurationError, "Expected #{key_file} to contain an RSA private key" unless @private_key.private?
60
- @local_authority_name = authority_name
61
62
  end
63
+
64
+ @invalid_sessions = Set.new
62
65
  end
63
66
 
67
+ def local_authority_name
68
+ @configuration['authority']
69
+ end
70
+
64
71
  # Determine whether this system trusts a particular authority based on
65
72
  # the trust settings specified in Configuration.
66
73
  #
@@ -85,11 +92,13 @@ module GlobalSession
85
92
  # === Return
86
93
  # valid(true|false):: whether the specified session is valid
87
94
  def valid_session?(uuid, expired_at)
88
- expired_at > Time.now
95
+ (expired_at > Time.now) && !@invalid_sessions.include?(uuid)
89
96
  end
90
97
 
91
98
  # Callback used by Session objects to report when the application code calls
92
- # #invalidate! on them. The default implementation of this method does nothing.
99
+ # #invalidate! on them. The default implementation of this method records
100
+ # invalid session IDs using an in-memory data structure, which is not ideal
101
+ # for most implementations.
93
102
  #
94
103
  # uuid(String):: Global session UUID
95
104
  # expired_at(Time):: When the session expired
@@ -97,7 +106,7 @@ module GlobalSession
97
106
  # === Return
98
107
  # true:: Always returns true
99
108
  def report_invalid_session(uuid, expired_at)
100
- true
109
+ @invalid_sessions << uuid
101
110
  end
102
111
  end
103
112
  end
@@ -1,4 +1,4 @@
1
- basedir = File.dirname(__FILE__)
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "global_session"))
2
2
 
3
3
  # Make sure the namespace exists, to satisfy Rails auto-loading
4
4
  module GlobalSession
@@ -37,8 +37,20 @@ module GlobalSession
37
37
  @configuration = configuration
38
38
  end
39
39
 
40
+ begin
41
+ klass_name = @configuration['directory'] || 'GlobalSession::Directory'
42
+
43
+ #Constantize the type name that was given as a string
44
+ parts = klass_name.split('::')
45
+ namespace = Object
46
+ namespace = namespace.const_get(parts.shift.to_sym) until parts.empty?
47
+ directory_klass = namespace
48
+ rescue Exception => e
49
+ raise ConfigurationError, "Invalid/unknown directory class name #{@configuration['directory']}"
50
+ end
51
+
40
52
  if directory.instance_of?(String)
41
- @directory = Directory.new(@configuration, directory)
53
+ @directory = directory_klass.new(@configuration, directory)
42
54
  else
43
55
  @directory = directory
44
56
  end
@@ -47,6 +59,34 @@ module GlobalSession
47
59
  @cookie_name = @configuration['cookie']['name']
48
60
  end
49
61
 
62
+ # Rack request chain. Sets up the global session ticket from
63
+ # the environment and passes it up the chain.
64
+ def call(env)
65
+ env['rack.cookies'] = {} unless env['rack.cookies']
66
+
67
+ begin
68
+ read_cookie(env)
69
+ rescue Exception => e
70
+ env['global_session'] = Session.new(@directory)
71
+ handle_error('reading session cookie', env, e)
72
+ end
73
+
74
+ tuple = nil
75
+
76
+ begin
77
+ tuple = @app.call(env)
78
+ rescue Exception => e
79
+ handle_error('processing request', env, e)
80
+ return tuple
81
+ else
82
+ renew_cookie(env)
83
+ update_cookie(env)
84
+ return tuple
85
+ end
86
+ end
87
+
88
+ protected
89
+
50
90
  # Read a cookie from the Rack environment.
51
91
  #
52
92
  # === Parameters
@@ -71,7 +111,7 @@ module GlobalSession
71
111
  def renew_cookie(env)
72
112
  return unless env['global_session'].directory.local_authority_name
73
113
  return if env['global_session.req.renew'] == false
74
-
114
+
75
115
  if (renew = @configuration['renew']) && env['global_session'] &&
76
116
  env['global_session'].expired_at < Time.at(Time.now.utc + 60 * renew.to_i)
77
117
  env['global_session'].renew!
@@ -110,6 +150,9 @@ module GlobalSession
110
150
  # === Parameters
111
151
  # env(Hash): Rack environment
112
152
  def wipe_cookie(env)
153
+ return unless env['global_session'].directory.local_authority_name
154
+ return if env['global_session.req.update'] == false
155
+
113
156
  domain = @configuration['cookie']['domain'] || env['SERVER_NAME']
114
157
  env['rack.cookies'][@cookie_name] = {:value => nil, :domain => domain, :expires => Time.at(0)}
115
158
  end
@@ -123,42 +166,17 @@ module GlobalSession
123
166
  # env(Hash): Rack environment
124
167
  # e(Exception): error that happened
125
168
  def handle_error(activity, env, e)
126
- if e.is_a? ClientError
169
+ env['rack.logger'].error("#{e.class} while #{activity}: #{e} #{e.backtrace}") if env['rack.logger']
170
+
171
+ if e.is_a?(ClientError) || e.is_a?(SecurityError)
127
172
  env['global_session.error'] = e
128
173
  wipe_cookie(env)
129
174
  elsif e.is_a? ConfigurationError
130
- env['rack.logger'].error("#{e.class} while #{activity}: #{e} #{e.backtrace}") if env['rack.logger']
131
175
  env['global_session.error'] = e
132
176
  else
133
177
  raise e
134
178
  end
135
179
  end
136
-
137
- # Rack request chain. Sets up the global session ticket from
138
- # the environment and passes it up the chain.
139
- def call(env)
140
- env['rack.cookies'] = {} unless env['rack.cookies']
141
-
142
- begin
143
- read_cookie(env)
144
- rescue Exception => e
145
- env['global_session'] = Session.new(@directory)
146
- handle_error('reading session cookie', env, e)
147
- end
148
-
149
- tuple = nil
150
-
151
- begin
152
- tuple = @app.call(env)
153
- rescue Exception => e
154
- handle_error('processing request', env, e)
155
- return tuple
156
- else
157
- renew_cookie(env)
158
- update_cookie(env)
159
- return tuple
160
- end
161
- end
162
180
  end
163
181
  end
164
182
  end
@@ -19,6 +19,9 @@ module GlobalSession
19
19
  unless base.instance_methods.include?("session_without_global_session")
20
20
  base.alias_method_chain :session, :global_session
21
21
  end
22
+ unless base.instance_methods.include?("log_processing_without_global_session")
23
+ base.alias_method_chain :log_processing, :global_session
24
+ end
22
25
  end
23
26
 
24
27
  # Shortcut accessor for global session configuration object.
@@ -115,16 +118,13 @@ module GlobalSession
115
118
  #
116
119
  # === Return
117
120
  # name(Type):: Description
118
- def log_processing
119
- if logger && logger.info?
120
- log_processing_for_request_id
121
- log_processing_for_parameters
122
- end
123
- end
121
+ def log_processing_with_global_session
122
+ return unless logger && logger.info?
124
123
 
125
- def log_processing_for_request_id # :nodoc:
126
- if global_session && global_session.id
127
- session_id = global_session.id + " (#{session[:session_id]})"
124
+ gs = request.env['global_session']
125
+
126
+ if gs && gs.id
127
+ session_id = gs.id + " (#{session[:session_id] || request.session_options[:id]})"
128
128
  elsif session[:session_id]
129
129
  session_id = session[:session_id]
130
130
  elsif request.session_options[:id]
@@ -137,9 +137,7 @@ module GlobalSession
137
137
  request_id << "\n Session ID: #{session_id}" if session_id
138
138
 
139
139
  logger.info(request_id)
140
- end
141
140
 
142
- def log_processing_for_parameters # :nodoc:
143
141
  parameters = respond_to?(:filter_parameters) ? filter_parameters(params) : params.dup
144
142
  parameters = parameters.except!(:controller, :action, :format, :_method)
145
143
 
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: 23
4
+ hash: 19
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
- - 0
10
- version: 1.0.0
9
+ - 2
10
+ version: 1.0.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: 2011-01-01 00:00:00 -08:00
18
+ date: 2011-01-15 00:00:00 -08:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -71,7 +71,7 @@ dependencies:
71
71
  requirement: &id004 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
- - - ~>
74
+ - - ">="
75
75
  - !ruby/object:Gem::Version
76
76
  hash: 49
77
77
  segments:
@@ -87,7 +87,7 @@ dependencies:
87
87
  requirement: &id005 !ruby/object:Gem::Requirement
88
88
  none: false
89
89
  requirements:
90
- - - ~>
90
+ - - ">="
91
91
  - !ruby/object:Gem::Version
92
92
  hash: 49
93
93
  segments:
@@ -103,14 +103,13 @@ dependencies:
103
103
  requirement: &id006 !ruby/object:Gem::Requirement
104
104
  none: false
105
105
  requirements:
106
- - - ">="
106
+ - - ~>
107
107
  - !ruby/object:Gem::Version
108
- hash: 27
108
+ hash: 9
109
109
  segments:
110
110
  - 1
111
111
  - 3
112
- - 0
113
- version: 1.3.0
112
+ version: "1.3"
114
113
  type: :development
115
114
  version_requirements: *id006
116
115
  - !ruby/object:Gem::Dependency
@@ -119,14 +118,13 @@ dependencies:
119
118
  requirement: &id007 !ruby/object:Gem::Requirement
120
119
  none: false
121
120
  requirements:
122
- - - ">="
121
+ - - ~>
123
122
  - !ruby/object:Gem::Version
124
- hash: 51
123
+ hash: 27
125
124
  segments:
126
125
  - 0
127
126
  - 8
128
- - 6
129
- version: 0.8.6
127
+ version: "0.8"
130
128
  type: :development
131
129
  version_requirements: *id007
132
130
  - !ruby/object:Gem::Dependency
@@ -135,14 +133,13 @@ dependencies:
135
133
  requirement: &id008 !ruby/object:Gem::Requirement
136
134
  none: false
137
135
  requirements:
138
- - - ">="
136
+ - - ~>
139
137
  - !ruby/object:Gem::Version
140
- hash: 15
138
+ hash: 5
141
139
  segments:
142
140
  - 2
143
- - 1
144
- - 2
145
- version: 2.1.2
141
+ - 3
142
+ version: "2.3"
146
143
  type: :development
147
144
  version_requirements: *id008
148
145
  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.