class FmRest::V1::TokenSession

FM Data API authentication middleware using the credentials strategy

Constants

HEADER_KEY
LOGOUT_PATH_MATCHER
TOKEN_STORE_INTERFACE

Public Class Methods

new(app, settings) click to toggle source

@param app [#call] @param settings [FmRest::ConnectionSettings]

Calls superclass method
# File lib/fmrest/v1/token_session.rb, line 18
def initialize(app, settings)
  super(app)
  @settings = settings
end

Public Instance Methods

call(env) click to toggle source

Entry point for the middleware when sending a request

# File lib/fmrest/v1/token_session.rb, line 25
def call(env)
  return handle_logout(env) if is_logout_request?(env)

  set_auth_header(env)

  request_body = env[:body] # After failure env[:body] is set to the response body

  @app.call(env).on_complete do |response_env|
    if response_env[:status] == 401 # Unauthorized
      delete_token_store_key

      if @settings.autologin
        env[:body] = request_body
        set_auth_header(env)
        return @app.call(env)
      end
    end
  end
end

Private Instance Methods

auth_connection() click to toggle source
# File lib/fmrest/v1/token_session.rb, line 134
def auth_connection
  @auth_connection ||= V1.auth_connection(@settings)
end
delete_token_store_key() click to toggle source
# File lib/fmrest/v1/token_session.rb, line 47
def delete_token_store_key
  token_store.delete(token_store_key)
  # Sometimes we may want to pass the :token in settings manually, and
  # refrain from passing a :username. In that case the call to
  # #token_store_key above would fail as it tries to fetch :username, so
  # we purposely ignore that error.
rescue FmRest::ConnectionSettings::MissingSetting
end
handle_logout(env) click to toggle source
# File lib/fmrest/v1/token_session.rb, line 56
def handle_logout(env)
  token = @settings.token? ? @settings.token : token_store.load(token_store_key)

  raise NoSessionTokenSet, "Couldn't send logout request because no session token was set" unless token

  env.url.path = env.url.path.gsub(LOGOUT_PATH_MATCHER, "\\1#{token}")

  @app.call(env).on_complete do |response_env|
    delete_token_store_key if response_env[:status] == 200
  end
end
is_logout_request?(env) click to toggle source
# File lib/fmrest/v1/token_session.rb, line 68
def is_logout_request?(env)
  return false unless env.method == :delete
  return env.url.path.match?(LOGOUT_PATH_MATCHER)
end
set_auth_header(env) click to toggle source
# File lib/fmrest/v1/token_session.rb, line 73
def set_auth_header(env)
  env.request_headers[HEADER_KEY] = "Bearer #{token}"
end
token() click to toggle source

Uses the token given in connection settings if available, otherwisek tries to get an existing token from the token store, otherwise requests one through basic auth, otherwise raises an exception.

# File lib/fmrest/v1/token_session.rb, line 82
def token
  return @settings.token if @settings.token?

  token = token_store.load(token_store_key)
  return token if token

  return nil unless @settings.autologin

  token = V1.request_auth_token!(auth_connection)
  token_store.store(token_store_key, token)
  token
end
token_store() click to toggle source
# File lib/fmrest/v1/token_session.rb, line 113
def token_store
  @token_store ||=
    begin
      if TOKEN_STORE_INTERFACE.all? { |method| token_store_option.respond_to?(method) }
        token_store_option
      elsif token_store_option.kind_of?(Class)
        if token_store_option.respond_to?(:instance)
          token_store_option.instance
        else
          token_store_option.new
        end
      else
        FmRest::TokenStore::Memory.new
      end
    end
end
token_store_key() click to toggle source

The key to use to store a token, uses the format host:database:username

# File lib/fmrest/v1/token_session.rb, line 97
def token_store_key
  @token_store_key ||=
    begin
      # Strip the host part to just the hostname (i.e. no scheme or port)
      host = @settings.host!
      host = URI(host).hostname if host =~ /\Ahttps?:\/\//
      identity_segment = if fmid_token = @settings.fmid_token
                           require "digest"
                           Digest::SHA256.hexdigest(fmid_token)
                         else
                           @settings.username!
                         end
      "#{host}:#{@settings.database!}:#{identity_segment}"
    end
end
token_store_option() click to toggle source
# File lib/fmrest/v1/token_session.rb, line 130
def token_store_option
  @settings.token_store || FmRest.token_store
end