lib/global_session/session/v1.rb in global_session-2.0.3 vs lib/global_session/session/v1.rb in global_session-3.0.0
- old
+ new
@@ -22,13 +22,24 @@
# Standard library dependencies
require 'set'
require 'zlib'
module GlobalSession::Session
- # Global session V1 uses JSON serialization and Zlib compression. Its encoding looks something
- # like this:
+ # V1 uses JSON serialization and Zlib compression. Its JSON structure is a Hash
+ # with the following format:
+ # {'id': <uuid_string> ,
+ # 'a': <signing_authority_string>,
+ # 'tc': <creation_timestamp_integer>,
+ # 'te': <expiration_timestamp_integer>,
+ # 'ds': {<signed_data_hash>},
+ # 'dx': {<unsigned_data_hash>},
+ # 's': <binary_signature_string>}
#
+ # Limitations of V1 include the following:
+ # * Compressing the JSON usually INCREASES the size of the compressed data
+ # * 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 V1 < Abstract
# Utility method to decode a cookie; good for console debugging. This performs no
# validation or security check of any sort.
#
# === Parameters
@@ -37,57 +48,16 @@
zbin = GlobalSession::Encoding::Base64Cookie.load(cookie)
json = Zlib::Inflate.inflate(zbin)
return GlobalSession::Encoding::JSON.load(json)
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.
- # 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
- def initialize(directory, cookie=nil, valid_signature_digest=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, valid_signature_digest)
- 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 JSON-serialized global session hash
+ # cookie(String):: Base64Cookie-encoded, Zlib-compressed JSON-serialized global session
def to_s
if @cookie && !@dirty_insecure && !@dirty_secure
#use cached cookie if nothing has changed
return @cookie
end
@@ -114,35 +84,10 @@
json = GlobalSession::Encoding::JSON.dump(hash)
zbin = Zlib::Deflate.deflate(json, Zlib::BEST_COMPRESSION)
return GlobalSession::Encoding::Base64Cookie.dump(zbin)
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
@@ -267,11 +212,11 @@
end
return output
end
- def load_from_cookie(cookie, valid_signature_digest) # :nodoc:
+ def load_from_cookie(cookie) # :nodoc:
begin
zbin = GlobalSession::Encoding::Base64Cookie.load(cookie)
json = Zlib::Inflate.inflate(zbin)
hash = GlobalSession::Encoding::JSON.load(json)
rescue Exception => e
@@ -286,18 +231,16 @@
expired_at = Time.at(hash['te'].to_i).utc
signed = hash['ds']
insecure = hash.delete('dx')
signature = hash.delete('s')
- unless valid_signature_digest == digest(signature)
- #Check signature
- expected = canonical_digest(hash)
- signer = @directory.authorities[authority]
- raise SecurityError, "Unknown signing authority #{authority}" unless signer
- got = signer.public_decrypt(GlobalSession::Encoding::Base64Cookie.load(signature))
- unless (got == expected)
- raise SecurityError, "Signature mismatch on global session cookie; tampering suspected"
- end
+ #Check signature
+ expected = canonical_digest(hash)
+ signer = @directory.authorities[authority]
+ raise SecurityError, "Unknown signing authority #{authority}" unless signer
+ got = signer.public_decrypt(GlobalSession::Encoding::Base64Cookie.load(signature))
+ unless (got == expected)
+ raise SecurityError, "Signature mismatch on global session cookie; tampering suspected"
end
#Check trust in signing authority
unless @directory.trusted_authority?(authority)
raise SecurityError, "Global sessions signed by #{authority} are not trusted"