Class: GlobalSession::Directory

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

Overview

The global session directory, which provides 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:
    class: MyCoolDirectory

Key Management

All key-related functionality has been delegated to the Keystore class as of v3.1. Directory retains its key management hooks for downrev compatibility, but mostly they are stubs for Keystore functionality.

For more information about key mangement, please refer to the Keystore class.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(configuration, keystore_directory = nil) ⇒ Directory

Create a new Directory.

Parameters:

  • shared (Configuration)

    configuration

  • optional (String)

    keystore_directory (DEPRECATED) if present, directory where keys can be found

Raises:

  • (ConfigurationError)

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



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
90
# File 'lib/global_session/directory.rb', line 62

def initialize(configuration, keystore_directory=nil)
  @configuration = configuration
  @authorities = {}

  # Propagate a deprecated parameter
  # @deprecated remove for v4.0
  if keystore_directory.is_a?(String)
    all_files = Dir.glob(File.join(keystore_directory, '*'))
    public_keys = all_files.select { |kf| kf =~ /\.pub$/ }
    raise ConfigurationError, "No public keys (*.pub) found in #{keystore_directory}" if public_keys.empty?

    @configuration['common'] ||= {}
    @configuration['common']['keystore'] ||= {}
    @configuration['common']['keystore']['public'] = [keystore_directory]

    # Propagate a deprecated configuration option
    # @deprecated remove for v4.0
    if (private_key = @configuration['authority'])
      key_file = all_files.detect { |kf| kf =~ /#{private_key}\.key$/ }
      raise ConfigurationError, "Key file #{private_key}.key not found in #{keystore_directory}" unless key_file
      @configuration['common'] ||= {}
      @configuration['common']['keystore'] ||= {}
      @configuration['common']['keystore']['private'] = key_file
    end
  end

  @keystore = Keystore.new(configuration)
  @invalid_sessions = Set.new
end

Instance Attribute Details

#configurationConfiguration (readonly)

Returns shared configuration object.

Returns:



47
48
49
# File 'lib/global_session/directory.rb', line 47

def configuration
  @configuration
end

#keystoreKeystore (readonly)

Returns asymmetric crypto keys for signing authorities.

Returns:

  • (Keystore)

    asymmetric crypto keys for signing authorities



50
51
52
# File 'lib/global_session/directory.rb', line 50

def keystore
  @keystore
end

Instance Method Details

#authoritiesHash

Deprecated.

will be removed in GlobalSession v4; please use Keystore instead

Returns map of String authority-names to OpenSSL::PKey public-keys.

Returns:

  • (Hash)

    map of String authority-names to OpenSSL::PKey public-keys

See Also:



155
156
157
# File 'lib/global_session/directory.rb', line 155

def authorities
  @keystore.public_keys
end

#create_session(cookie = nil) ⇒ Object

Deprecated.

will be removed in GlobalSession v4; please use #load_session instead

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

InvalidSignature

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

See Also:



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

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

  if cookie.nil?
    # Create a legitimately new session
    case forced_version
    when 4
      Session::V4.new(self, cookie)
    when nil, 3
      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

#inspectObject

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

Returns:

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



53
54
55
# File 'lib/global_session/directory.rb', line 53

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

InvalidSignature

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



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

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

#local_authority_nameObject

Deprecated.

will be removed in GlobalSession v4; please use Keystore instead

Determine the authority name associated with this directory’s private session-signing key.

See Also:



172
173
174
# File 'lib/global_session/directory.rb', line 172

def local_authority_name
  @keystore.private_key_name
end

#private_keynil, OpenSSL::PKey

Deprecated.

will be removed in GlobalSession v4; please use Keystore instead

Determine the private key associated with this directory, to be used for signing.

Returns:

  • (nil, OpenSSL::PKey)

    local authority key if we are an authority, else nil

See Also:



164
165
166
# File 'lib/global_session/directory.rb', line 164

def private_key
  @keystore.private_key || @private_key
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



220
221
222
# File 'lib/global_session/directory.rb', line 220

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

#trusted_authority?(authority) ⇒ Boolean

Determine whether this system trusts a particular named authority based on the settings specified in Configuration and/or the presence of public key files on disk.

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)


185
186
187
188
189
190
191
192
193
# File 'lib/global_session/directory.rb', line 185

def trusted_authority?(authority)
  if @configuration.has_key?('trust')
    # Explicit trust in just the authorities specified in the configuration
    @configuration['trust'].include?(authority)
  else
    # Implicit trust in any public key we found on disk
    @keystore.public_keys.keys.include?(authority)
  end
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)


206
207
208
# File 'lib/global_session/directory.rb', line 206

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