global_session 1.0.10 → 1.0.13

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.
@@ -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.10'
11
- s.date = '2012-03-07'
10
+ s.version = '1.0.13'
11
+ s.date = '2012-09-26'
12
12
 
13
13
  s.authors = ['Tony Spataro']
14
14
  s.email = 'support@rightscale.com'
@@ -17,7 +17,7 @@ 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 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
- s.add_runtime_dependency('uuidtools', ["~> 2.1"])
20
+ s.add_runtime_dependency('uuidtools', [">= 1.0"])
21
21
  s.add_runtime_dependency('json', ["~> 1.4"])
22
22
  s.add_runtime_dependency('rack-contrib', ["~> 1.0"])
23
23
 
@@ -73,6 +73,11 @@ module GlobalSession
73
73
  # you are integrating; see GlobalSession::Rails for more information.
74
74
  #
75
75
  class Configuration
76
+ # @return a representation of the object suitable for printing to the console
77
+ def inspect
78
+ "<#{self.class.name} @environment=#{@environment.inspect}>"
79
+ end
80
+
76
81
  # Create a new Configuration object
77
82
  #
78
83
  # === Parameters
@@ -54,12 +54,17 @@ module GlobalSession
54
54
  class Directory
55
55
  attr_reader :configuration, :authorities, :private_key
56
56
 
57
+ # @return a representation of the object suitable for printing to the console
58
+ def inspect
59
+ "<#{self.class.name} @configuration=#{@configuration.inspect}>"
60
+ end
61
+
57
62
  # Create a new Directory.
58
63
  #
59
64
  # === Parameters
60
65
  # keystore_directory(String):: Absolute path to authority keystore
61
66
  #
62
- # ===Raise
67
+ # === Raise
63
68
  # ConfigurationError:: if too many or too few keys are found, or if *.key/*.pub files are malformatted
64
69
  def initialize(configuration, keystore_directory)
65
70
  @configuration = configuration
@@ -84,6 +89,26 @@ module GlobalSession
84
89
  @invalid_sessions = Set.new
85
90
  end
86
91
 
92
+ # Create a new Session, initialized against this directory and ready to
93
+ # be used by the app.
94
+ #
95
+ # === Parameters
96
+ # directory(Directory):: directory implementation that the session should use for various operations
97
+ # cookie(String):: Optional, serialized global session cookie. If none is supplied, a new session is created.
98
+ # valid_signature_digest(String):: Optional, already-trusted signature. If supplied, the expensive RSA-verify operation will be skipped if the cookie's signature matches the value supplied.
99
+ #
100
+ # === Return
101
+ # session(Session):: the newly-initialized session
102
+ #
103
+ # ===Raise
104
+ # InvalidSession:: if the session contained in the cookie has been invalidated
105
+ # ExpiredSession:: if the session contained in the cookie has expired
106
+ # MalformedCookie:: if the cookie was corrupt or malformed
107
+ # SecurityError:: if signature is invalid or cookie is not signed by a trusted authority
108
+ def create_session(*params)
109
+ Session.new(self, *params)
110
+ end
111
+
87
112
  def local_authority_name
88
113
  @configuration['authority']
89
114
  end
@@ -128,5 +153,18 @@ module GlobalSession
128
153
  def report_invalid_session(uuid, expired_at)
129
154
  @invalid_sessions << uuid
130
155
  end
156
+
157
+ # Callback used by GlobalSession::Rack::Middleware when the application invalidated
158
+ # current global_session object. This callback could help application to get data related
159
+ # to the previous global session (old_global_session_id), and put it to new global session
160
+ # (new_global_sesion_id)
161
+
162
+ # invalidated_uuid(String):: Invalidated Global session UUID
163
+ # new_uuid(String):: Newly created Global session UUID
164
+ # === Return
165
+ # true: Always returns true
166
+ def session_invalidated(invalidated_uuid, new_uuid)
167
+ true
168
+ end
131
169
  end
132
170
  end
@@ -88,7 +88,7 @@ module GlobalSession
88
88
  begin
89
89
  read_cookie(env)
90
90
  rescue Exception => e
91
- env['global_session'] = Session.new(@directory)
91
+ env['global_session'] = @directory.create_session
92
92
  handle_error('reading session cookie', env, e)
93
93
  end
94
94
 
@@ -114,12 +114,11 @@ module GlobalSession
114
114
  # env(Hash): Rack environment.
115
115
  def read_cookie(env)
116
116
  if env['rack.cookies'].has_key?(@cookie_name)
117
- env['global_session'] = Session.new(@directory,
118
- env['rack.cookies'][@cookie_name])
117
+ env['global_session'] = @directory.create_session(env['rack.cookies'][@cookie_name])
119
118
  elsif @cookie_retrieval && cookie = @cookie_retrieval.call(env)
120
- env['global_session'] = Session.new(@directory, cookie)
119
+ env['global_session'] = @directory.create_session(cookie)
121
120
  else
122
- env['global_session'] = Session.new(@directory)
121
+ env['global_session'] = @directory.create_session
123
122
  end
124
123
 
125
124
  true
@@ -149,9 +148,15 @@ module GlobalSession
149
148
 
150
149
  begin
151
150
  domain = @configuration['cookie']['domain'] || env['SERVER_NAME']
152
- if env['global_session'] && env['global_session'].valid?
153
- value = env['global_session'].to_s
154
- expires = @configuration['ephemeral'] ? nil : env['global_session'].expired_at
151
+ if env['global_session']
152
+ global_session = env['global_session']
153
+ unless global_session.valid?
154
+ invalidated_uuid = global_session.id
155
+ global_session = @directory.create_session
156
+ @directory.session_invalidated(invalidated_uuid, global_session.id)
157
+ end
158
+ value = global_session.to_s
159
+ expires = @configuration['ephemeral'] ? nil : global_session.expired_at
155
160
  unless env['rack.cookies'].has_key?(@cookie_name) && env['rack.cookies'][@cookie_name] == value
156
161
  env['rack.cookies'][@cookie_name] =
157
162
  {:value => value, :domain => domain, :expires => expires, :httponly=>true}
@@ -25,24 +25,23 @@ module GlobalSession
25
25
  # app-wide data such as the configuration object, and implements the DSL used to
26
26
  # configure controllers' use of the global session.
27
27
  module ActionControllerClassMethods
28
- def global_session_config
29
- unless @global_session_config
30
- config_file = File.join(::Rails.root, 'config', 'global_session.yml')
31
- @global_session_config = GlobalSession::Configuration.new(config_file, RAILS_ENV)
32
- end
33
-
34
- return @global_session_config
35
- end
36
-
37
- def global_session_config=(config)
38
- @global_session_config = config
39
- end
28
+ VALID_OPTIONS = [:raise, :renew, :only, :except]
29
+ DEFAULT_OPTIONS = {
30
+ :raise=>true,
31
+ :renew=>true
32
+ }
40
33
 
41
34
  def has_global_session(options={})
42
- odefault = {:integrated=>false, :raise=>true}
43
- obase = self.superclass.global_session_options if self.superclass.respond_to?(:global_session_options)
44
- obase ||= {}
45
- options = odefault.merge(obase).merge(options)
35
+ #validate our options
36
+ options.assert_valid_keys(VALID_OPTIONS)
37
+ if options.key?(:only) && options.key?(:except)
38
+ raise ArgumentError, "Must specify :only OR :except, you specified both"
39
+ end
40
+
41
+ #start with default options; merge any options inherited from our base class;
42
+ #merge any options provided by the caller.
43
+ obase = self.superclass.global_session_options
44
+ options = DEFAULT_OPTIONS.merge(obase).merge(options)
46
45
 
47
46
  #ensure derived-class options don't conflict with mutually exclusive base-class options
48
47
  options.delete(:only) if obase.has_key?(:only) && options.has_key?(:except)
@@ -51,20 +50,23 @@ module GlobalSession
51
50
  #mark the global session as enabled (a hidden option) and store our
52
51
  #calculated, merged options
53
52
  options[:enabled] = true
54
- self.global_session_options = options
55
53
 
56
- before_filter :global_session_initialize
54
+ self.global_session_options = options
57
55
  end
58
56
 
59
57
  def no_global_session
60
- @global_session_options[:enabled] = false if @global_session_options
61
- skip_before_filter :global_session_initialize
58
+ #mark the global session as not-enabled (a hidden option)
59
+ self.global_session_options={:enabled=>false}
62
60
  end
63
61
 
64
62
  def global_session_options
65
- obase = self.superclass.global_session_options if self.superclass.respond_to?(:global_session_options)
66
- obase ||= {}
67
- @global_session_options || obase
63
+ if @global_session_options
64
+ @global_session_options
65
+ elsif self.superclass.respond_to?(:global_session_options)
66
+ self.superclass.global_session_options
67
+ else
68
+ {}
69
+ end
68
70
  end
69
71
 
70
72
  def global_session_options=(options)
@@ -43,6 +43,8 @@ module GlobalSession
43
43
  unless base.instance_methods.include?("log_processing_without_global_session")
44
44
  base.alias_method_chain :log_processing, :global_session
45
45
  end
46
+
47
+ base.before_filter :global_session_initialize
46
48
  end
47
49
 
48
50
  # Shortcut accessor for global session configuration object.
@@ -41,14 +41,40 @@ end
41
41
 
42
42
  module GlobalSession
43
43
  module Rails
44
- def self.activate(config)
45
- authorities = File.join(::Rails.root, 'config', 'authorities')
46
- hgs_config = ActionController::Base.global_session_config
47
- hgs_dir = GlobalSession::Directory.new(hgs_config, authorities)
44
+ class <<self
45
+ # Single Configuration object used by entire Rails app
46
+ attr_accessor :configuration
47
+
48
+ # Single Directory object used by entire Rails app
49
+ attr_accessor :directory
50
+ end
51
+
52
+ def self.activate(rails_config, &block)
53
+ config_file = File.join(::Rails.root, 'config', 'global_session.yml')
54
+ self.configuration = GlobalSession::Configuration.new(config_file, ::Rails.env)
55
+
56
+ dir_name = self.configuration['directory'] || 'GlobalSession::Directory'
57
+ begin
58
+ dir_klass = dir_name.constantize
59
+ rescue NameError => e
60
+ raise GlobalSession::ConfigurationError,
61
+ "Unknown/malformed directory class '#{dir_name}' in config file: #{e.message}"
62
+ end
63
+
64
+ unless dir_klass.ancestors.include?(GlobalSession::Directory)
65
+ raise GlobalSession::ConfigurationError,
66
+ "Specified directory class '#{dir_name}' does not inherit from GlobalSession::Directory"
67
+ end
68
+
69
+ authorities_dir = File.join(::Rails.root, 'config', 'authorities')
70
+ self.directory = dir_klass.new(self.configuration, authorities_dir)
48
71
 
49
72
  # Add our middleware to the stack.
50
- config.middleware.use ::Rack::Cookies
51
- config.middleware.use ::Rack::GlobalSession, hgs_config, hgs_dir
73
+ rails_config.middleware.insert_before(ActionController::Base.session_store, ::Rack::Cookies)
74
+ rails_config.middleware.insert_before(ActionController::Base.session_store, ::Rack::GlobalSession,
75
+ self.configuration,
76
+ self.directory,
77
+ &block)
52
78
 
53
79
  return true
54
80
  end
@@ -48,6 +48,11 @@ module GlobalSession
48
48
  return Encoding::JSON.load(json)
49
49
  end
50
50
 
51
+ # @return a representation of the object suitable for printing to the console
52
+ def inspect
53
+ "<#{self.class.name} @id=#{@id.inspect}>"
54
+ end
55
+
51
56
  # Create a new global session object.
52
57
  #
53
58
  # === Parameters
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: 3
4
+ hash: 13
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
- - 10
10
- version: 1.0.10
9
+ - 13
10
+ version: 1.0.13
11
11
  platform: ruby
12
12
  authors:
13
13
  - Tony Spataro
@@ -15,20 +15,20 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-03-07 00:00:00 -08:00
18
+ date: 2012-09-26 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  version_requirements: &id001 !ruby/object:Gem::Requirement
23
23
  none: false
24
24
  requirements:
25
- - - ~>
25
+ - - ">="
26
26
  - !ruby/object:Gem::Version
27
- hash: 1
27
+ hash: 15
28
28
  segments:
29
- - 2
30
29
  - 1
31
- version: "2.1"
30
+ - 0
31
+ version: "1.0"
32
32
  requirement: *id001
33
33
  name: uuidtools
34
34
  prerelease: false