lib/global_session/session/v2.rb in global_session-2.0.3 vs lib/global_session/session/v2.rb in global_session-3.0.0
- old
+ new
@@ -20,14 +20,28 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# Standard library dependencies
require 'set'
-# Dependencies on other gems
-require 'msgpack'
-
module GlobalSession::Session
+ # Global session V2 uses msgpack serialization and no compression. Its msgpack structure is an
+ # Array with the following format:
+ # [<uuid_string>,
+ # <signing_authority_string>,
+ # <creation_timestamp_integer>,
+ # <expiration_timestamp_integer>,
+ # {<signed_data_hash>},
+ # {<unsigned_data_hash>},
+ # <binary_signature_string>]
+ #
+ # The design goal of V2 is to minimize the size of the base64-encoded session state in order
+ # to make GlobalSession more amenable to use as a browser cookie.
+ #
+ # Limitations of V2 include the following:
+ # * Some Ruby implementations (e.g. JRuby) lack a msgpack library
+ # * The sign and verify algorithms, while safe, do not comply fully with PKCS7; they rely on the
+ # OpenSSL low-level crypto API instead of using the higher-level EVP (envelope) API.
class V2 < Abstract
# Utility method to decode a cookie; good for console debugging. This performs no
# validation or security check of any sort.
#
# === Parameters
@@ -35,57 +49,16 @@
def self.decode_cookie(cookie)
msgpack = GlobalSession::Encoding::Base64Cookie.load(cookie)
return GlobalSession::Encoding::Msgpack.load(msgpack)
end
- # 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.
- # unused(Object):: Optional, already-trusted signature. This is ignored for v2.
- #
- # ===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
- def initialize(directory, cookie=nil)
- super(directory)
- @configuration = directory.configuration
- @schema_signed = Set.new((@configuration['attributes']['signed']))
- @schema_insecure = Set.new((@configuration['attributes']['insecure']))
-
- if cookie && !cookie.empty?
- load_from_cookie(cookie)
- elsif @directory.local_authority_name
- create_from_scratch
- else
- create_invalid
- end
- end
-
- # @return [true,false] true if this session was created in-process, false if it was initialized from a cookie
- def new_record?
- @cookie.nil?
- end
-
- # 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
- def valid?
- @directory.valid_session?(@id, @expired_at)
- end
-
# 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 Msgpack-serialized global session hash
+ # cookie(String):: Base64Cookie-encoded, Msgpack-serialized global session
def to_s
if @cookie && !@dirty_insecure && !@dirty_secure
#use cached cookie if nothing has changed
return @cookie
end
@@ -115,35 +88,10 @@
array = attribute_hash_to_array(hash)
msgpack = GlobalSession::Encoding::Msgpack.dump(array)
return GlobalSession::Encoding::Base64Cookie.dump(msgpack)
end
- # 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
- def supports_key?(key)
- @schema_signed.include?(key) || @schema_insecure.include?(key)
- end
-
- # 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.
- def has_key?(key)
- @signed.has_key?(key) || @insecure.has_key?(key)
- end
-
- alias :key? :has_key?
-
# Return the keys that are currently present in the global session.
#
# === Return
# keys(Array):: List of keys contained in the global session
def keys
@@ -312,15 +260,13 @@
:encoding=>GlobalSession::Encoding::Msgpack,
:public_key=>@directory.authorities[authority])
begin
signed_hash.verify!(signature, expired_at)
- rescue SecurityError => e
- if e.message =~ /expired/
- raise GlobalSession::ExpiredSession, "Session expired at #{expired_at}"
- else
- raise SecurityError, "Global session verification failure; suspected tampering: " + e.message
- end
+ rescue RightSupport::Crypto::ExpiredSignature
+ raise GlobalSession::ExpiredSession, "Session expired at #{expired_at}"
+ rescue RightSupport::Crypto::InvalidSignature => e
+ raise SecurityError, "Global session signature verification failed: " + e.message
end
#Check other validity (delegate to directory)
unless @directory.valid_session?(id, expired_at)
raise GlobalSession::InvalidSession, "Global session has been invalidated"