Class: HasGlobalSession::GlobalSession

Inherits:
Object
  • Object
show all
Defined in:
lib/has_global_session/global_session.rb

Overview

Ladies and gentlemen: the one and only, star of the show, GLOBAL SESSION!

GlobalSession is designed to act as much like a Hash as possible. You can use most of the methods you would use with Hash: [], has_key?, each, etc. It has a few additional methods that are specific to itself, mostly involving whether it’s expired, valid, supports a certain key, etc.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(directory, cookie = nil, valid_signature_digest = nil) ⇒ GlobalSession

Create a new global session object.

Parameters

directory(Directory)

directory implementation that the session should use for various operations

cookie(String)

Optional, serialized global session cookie. If none is supplied, a new session is created.

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.

Raise

InvalidSession

if the session contained in the cookie has been invalidated

ExpiredSession

if the session contained in the cookie has expired

MalformedCookie

if the cookie was corrupt or malformed

SecurityError

if signature is invalid or cookie is not signed by a trusted authority



31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/has_global_session/global_session.rb', line 31

def initialize(directory, cookie=nil, valid_signature_digest=nil)
  @configuration   = directory.configuration
  @schema_signed   = Set.new((@configuration['attributes']['signed']))
  @schema_insecure = Set.new((@configuration['attributes']['insecure']))
  @directory       = directory

  if cookie && !cookie.empty?
    load_from_cookie(cookie, valid_signature_digest)
  elsif @directory.local_authority_name
    create_from_scratch
  else
    create_invalid
  end
end

Instance Attribute Details

#authorityObject (readonly)

Returns the value of attribute authority.



17
18
19
# File 'lib/has_global_session/global_session.rb', line 17

def authority
  @authority
end

#created_atObject (readonly)

Returns the value of attribute created_at.



17
18
19
# File 'lib/has_global_session/global_session.rb', line 17

def created_at
  @created_at
end

#directoryObject (readonly)

Returns the value of attribute directory.



17
18
19
# File 'lib/has_global_session/global_session.rb', line 17

def directory
  @directory
end

#expired_atObject (readonly)

Returns the value of attribute expired_at.



17
18
19
# File 'lib/has_global_session/global_session.rb', line 17

def expired_at
  @expired_at
end

#idObject (readonly)

Returns the value of attribute id.



17
18
19
# File 'lib/has_global_session/global_session.rb', line 17

def id
  @id
end

Instance Method Details

#[](key) ⇒ Object

Lookup a value by its key.

Parameters

key(String)

the key

Return

value(Object)

The value associated with key, or nil if key is not present



149
150
151
# File 'lib/has_global_session/global_session.rb', line 149

def [](key)
  @signed[key] || @insecure[key]
end

#[]=(key, value) ⇒ Object

Set a value in the global session hash. If the supplied key is denoted as secure by the global session schema, causes a new signature to be computed when the session is next serialized.

Parameters

key(String)

The key to set

value(Object)

The value to set

Return

value(Object)

Always returns the value that was set

Raise

InvalidSession

if the session has been invalidated (and therefore can’t be written to)

ArgumentError

if the configuration doesn’t define the specified key as part of the global session

NoAuthority

if the specified key is secure and the local node is not an authority

UnserializableType

if the specified value can’t be serialized as JSON

Raises:



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/has_global_session/global_session.rb', line 169

def []=(key, value)
  raise InvalidSession unless valid?

  #Ensure that the value is serializable (will raise if not)
  canonicalize(value)

  if @schema_signed.include?(key)
    authority_check
    @signed[key]  = value
    @dirty_secure = true
  elsif @schema_insecure.include?(key)
    @insecure[key] = value
    @dirty_insecure = true
  else
    raise ArgumentError, "Attribute '#{key}' is not specified in global session configuration"
  end

  return value
end

#each_pair(&block) ⇒ Object

Iterate over each key/value pair

Block

An iterator which will be called with each key/value pair

Return

Returns the value of the last expression evaluated by the block



137
138
139
140
# File 'lib/has_global_session/global_session.rb', line 137

def each_pair(&block) # :yields: |key, value|
  @signed.each_pair(&block)
  @insecure.each_pair(&block)
end

#has_key?(key) ⇒ Boolean

Determine whether this session contains a value with the specified key.

Parameters

key(String)

The name of the key

Return

contained(true|false)

Whether the session currently has a value for the specified key.

Returns:

  • (Boolean)


110
111
112
# File 'lib/has_global_session/global_session.rb', line 110

def has_key?(key)
  @signed.has_key(key) || @insecure.has_key?(key)
end

#invalidate!Object

Invalidate this session by reporting its UUID to the Directory.

Return

unknown(Object)

Returns whatever the Directory returns



193
194
195
# File 'lib/has_global_session/global_session.rb', line 193

def invalidate!
  @directory.report_invalid_session(@id, @expired_at)
end

#keysObject

Return the keys that are currently present in the global session.

Return

keys(Array)

List of keys contained in the global session



118
119
120
# File 'lib/has_global_session/global_session.rb', line 118

def keys
  @signed.keys + @insecure.keys
end

#renew!Object

Renews this global session, changing its expiry timestamp into the future. Causes a new signature will be computed when the session is next serialized.

Return

true

Always returns true



202
203
204
205
206
# File 'lib/has_global_session/global_session.rb', line 202

def renew!
  authority_check
  @expired_at = @configuration['timeout'].to_i.minutes.from_now.utc
  @dirty_secure = true
end

#signature_digestObject

Return the SHA1 hash of the most recently-computed RSA signature of this session. This isn’t really intended for the end user; it exists so the Web framework integration code can optimize request speed by caching the most recently verified signature in the local session and avoid re-verifying it on every request.

Return

digest(String)

SHA1 hex-digest of most-recently-computed signature



215
216
217
# File 'lib/has_global_session/global_session.rb', line 215

def signature_digest
  @signature ? digest(@signature) : nil
end

#supports_key?(key) ⇒ Boolean

Determine whether the global session schema allows a given key to be placed in the global session.

Parameters

key(String)

The name of the key

Return

supported(true|false)

Whether the specified key is supported

Returns:

  • (Boolean)


99
100
101
# File 'lib/has_global_session/global_session.rb', line 99

def supports_key?(key)
  @schema_signed.include?(key) || @schema_insecure.include?(key)
end

#to_sObject

Serialize the session to a form suitable for use with HTTP cookies. If any secure attributes have changed since the session was instantiated, compute a fresh RSA signature.

Return

cookie(String)

The B64cookie-encoded Zlib-compressed JSON-serialized global session hash



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/has_global_session/global_session.rb', line 61

def to_s
  if @cookie && !@dirty_insecure && !@dirty_secure
    #use cached cookie if nothing has changed
    return @cookie
  end

  hash = {'id'=>@id,
          'tc'=>@created_at.to_i, 'te'=>@expired_at.to_i,
          'ds'=>@signed}

  if @signature && !@dirty_secure
    #use cached signature unless we've changed secure state
    authority = @authority
  else
    authority_check
    authority = @directory.local_authority_name
    hash['a'] = authority
    digest    = canonical_digest(hash)
    @signature = Encoding::Base64Cookie.dump(@directory.private_key.private_encrypt(digest))
  end

  hash['dx'] = @insecure
  hash['s']  = @signature
  hash['a']  = authority
  
  json = Encoding::JSON.dump(hash)
  zbin = Zlib::Deflate.deflate(json, Zlib::BEST_COMPRESSION)
  return Encoding::Base64Cookie.dump(zbin)
end

#valid?Boolean

Determine whether the session is valid. This method simply delegates to the directory associated with this session.

Return

valid(true|false)

True if the session is valid, false otherwise

Returns:

  • (Boolean)


51
52
53
# File 'lib/has_global_session/global_session.rb', line 51

def valid?
  @directory.valid_session?(@id, @expired_at)
end

#valuesObject

Return the values that are currently present in the global session.

Return

values(Array)

List of values contained in the global session



126
127
128
# File 'lib/has_global_session/global_session.rb', line 126

def values
  @signed.values + @insecure.values
end