Class: GlobalSession::Directory

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

Overview

The global session directory, which provides some lookup and decision services to instances of Session.

The default implementation is simplistic, but should be suitable for most applications. Directory is designed to be specialized via subclassing. To override the behavior to suit your needs, simply create a subclass of Directory and add a configuration file setting to specify the class name of your implementation:

common:
  directory: MyCoolDirectory

The Authority Keystore

Directory uses a filesystem directory as a backing store for RSA public keys of global session authorities. The directory should contain one or more *.pub files containing OpenSSH-format public RSA keys. The name of the pub file determines the name of the authority it represents.

The Local Authority

Directory will infer the name of the local authority (if any) by looking for a private-key file in the keystore. If a *.key file is found, then its name is taken to be the name of the local authority and all GlobalSessions created will be signed by that authority's private key.

If more than one key file is found, Directory will raise an error at initialization time.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(configuration, keystore_directory) ⇒ Directory

Create a new Directory.

Parameters

keystore_directory(String)

Absolute path to authority keystore

Raise

ConfigurationError

if too many or too few keys are found, or if .key/.pub files are malformatted



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/global_session/directory.rb', line 69

def initialize(configuration, keystore_directory)
  @configuration = configuration
  certs = Dir[File.join(keystore_directory, '*.pub')]
  keys  = Dir[File.join(keystore_directory, '*.key')]

  @authorities = {}
  certs.each do |cert_file|
    basename = File.basename(cert_file)
    authority = basename[0...(basename.rindex('.'))] #chop trailing .ext
    @authorities[authority] = OpenSSL::PKey::RSA.new(File.read(cert_file))
    raise ConfigurationError, "Expected #{basename} to contain an RSA public key" unless @authorities[authority].public?
  end

  if local_authority_name
    key_file = keys.detect { |kf| kf =~ /#{local_authority_name}.key$/ }
    raise ConfigurationError, "Key file #{local_authority_name}.key not found" unless key_file        
    @private_key  = OpenSSL::PKey::RSA.new(File.read(key_file))
    raise ConfigurationError, "Expected #{key_file} to contain an RSA private key" unless @private_key.private?
  end

  @invalid_sessions = Set.new
end

Instance Attribute Details

#authorities ⇒ Object (readonly)

Returns the value of attribute authorities.



55
56
57
# File 'lib/global_session/directory.rb', line 55

def authorities
  @authorities
end

#configuration ⇒ Object (readonly)

Returns the value of attribute configuration.



55
56
57
# File 'lib/global_session/directory.rb', line 55

def configuration
  @configuration
end

#private_key ⇒ Object (readonly)

Returns the value of attribute private_key.



55
56
57
# File 'lib/global_session/directory.rb', line 55

def private_key
  @private_key
end

Instance Method Details

#create_session(cookie = nil) ⇒ Object

Create a new Session, initialized against this directory and ready to be used by the app.

DEPRECATED: If a cookie is provided, load an existing session from its serialized form. You should use #load_session for this instead.

Parameters

cookie(String)

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

Return

session(Session)

the newly-initialized session

===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

See Also:



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/global_session/directory.rb', line 111

def create_session(cookie=nil)
  forced_version = configuration['cookie']['version']

  if cookie.nil?
    # Create a legitimately new session
    case forced_version
    when 3, nil
      Session::V3.new(self, cookie)
    when 2
      Session::V2.new(self, cookie)
    when 1
      Session::V1.new(self, cookie)
    else
      raise ArgumentError, "Unknown value #{forced_version} for configuration.cookie.version" 
    end
  else
    warn "GlobalSession::Directory#create_session with an existing session is DEPRECATED -- use #load_session instead"
    load_session(cookie)
  end
end

#inspect ⇒ Object

Returns a representation of the object suitable for printing to the console.

Returns:

  • a representation of the object suitable for printing to the console



58
59
60
# File 'lib/global_session/directory.rb', line 58

def inspect
  "<#{self.class.name} @configuration=#{@configuration.inspect}>"
end

#load_session(cookie) ⇒ Object

Unserialize an existing session cookie

Parameters

cookie(String)

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

Return

session(Session)

the newly-initialized session

===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



145
146
147
# File 'lib/global_session/directory.rb', line 145

def load_session(cookie)
  Session.new(self, cookie)
end

#local_authority_name ⇒ Object



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

def local_authority_name
  @configuration['authority']
end

#report_invalid_session(uuid, expired_at) ⇒ Object

Callback used by Session objects to report when the application code calls #invalidate! on them. The default implementation of this method records invalid session IDs using an in-memory data structure, which is not ideal for most implementations.

uuid(String)

Global session UUID

expired_at(Time)

When the session expired

Return

true

Always returns true



190
191
192
# File 'lib/global_session/directory.rb', line 190

def report_invalid_session(uuid, expired_at)
  @invalid_sessions << uuid
end

#trusted_authority?(authority) ⇒ Boolean

Determine whether this system trusts a particular authority based on the trust settings specified in Configuration.

Parameters

authority(String)

The name of the authority

Return

trusted(true|false)

whether the local system trusts sessions signed by the specified authority

Returns:

  • (Boolean)


161
162
163
# File 'lib/global_session/directory.rb', line 161

def trusted_authority?(authority)
  @configuration['trust'].include?(authority)
end

#valid_session?(uuid, expired_at) ⇒ Boolean

Determine whether the given session UUID is valid. The default implementation only considers a session to be invalid if its expired_at timestamp is in the past. Custom implementations might want to consider other factors, such as whether the user has signed out of this node or another node (perhaps using some sort of centralized lookup or single sign-out mechanism).

Parameters

uuid(String)

Global session UUID

expired_at(Time)

When the session expired (or will expire)

Return

valid(true|false)

whether the specified session is valid

Returns:

  • (Boolean)


176
177
178
# File 'lib/global_session/directory.rb', line 176

def valid_session?(uuid, expired_at)
  (expired_at > Time.now) && !@invalid_sessions.include?(uuid)
end