class ADAL::CacheDriver

Performs logical operations on the TokenCache in the context of one token request.

Constants

FIELDS

Public Class Methods

new( authority, client, token_cache = NoopCache.new, expiration_buffer_sec = 0) click to toggle source

Constructs a CacheDriver to interact with a token cache.

@param String authority

The URL of the authority endpoint.

@param ClientAssertion|ClientCredential|etc client

The credentials representing the calling application. We need this
instead of just the client id so that the tokens can be refreshed if
necessary.

@param TokenCache token_cache

The cache implementation to store tokens.

@optional Fixnum expiration_buffer_sec

The number of seconds to use as a leeway when dealing with cache expiry.
# File lib/adal/cache_driver.rb, line 54
def initialize(
  authority, client, token_cache = NoopCache.new, expiration_buffer_sec = 0)
  @authority = authority
  @client = client
  @expiration_buffer_sec = expiration_buffer_sec
  @token_cache = token_cache
end

Public Instance Methods

add(token_response) click to toggle source

Checks if a TokenResponse is successful and if so adds it to the token cache for future retrieval.

@param SuccessResponse token_response

The successful token response to be cached. If it is not successful, it
fails silently.
# File lib/adal/cache_driver.rb, line 69
def add(token_response)
  return unless token_response.instance_of? SuccessResponse
  logger.verbose('Adding successful TokenResponse to cache.')
  entry = CachedTokenResponse.new(@client, @authority, token_response)
  update_refresh_tokens(entry) if entry.mrrt?
  @token_cache.add(entry)
end
find(query = {}) click to toggle source

Searches the cache for a token matching a specific query of fields.

@param Hash query

The fields to match against.

@return TokenResponse

# File lib/adal/cache_driver.rb, line 83
def find(query = {})
  query = query.map { |k, v| [FIELDS[k], v] if FIELDS[k] }.compact.to_h
  resource = query.delete(RESOURCE)
  matches = validate(
    find_all_cached_entries(
      query.reverse_merge(
        authority: @authority, client_id: @client.client_id))
  )
  resource_specific(matches, resource) || refresh_mrrt(matches, resource)
end

Private Instance Methods

find_all_cached_entries(query) click to toggle source

All cache entries that match a query. This matches keys in values against a hash to method calls on an object.

@param Hash query

The fields to be matched and the values to match them to.

@return Array<CachedTokenResponse>

# File lib/adal/cache_driver.rb, line 103
def find_all_cached_entries(query)
  logger.verbose("Searching cache for tokens by keys: #{query.keys}.")
  @token_cache.find do |entry|
    query.map do |k, v|
      (entry.respond_to? k.to_sym) && (v == entry.send(k.to_sym))
    end.reduce(:&)
  end
end
refresh_mrrt(responses, resource) click to toggle source

Attempts to obtain an access token for a resource with refresh tokens from a list of MRRTs.

@param Array @return SuccessResponse|nil

# File lib/adal/cache_driver.rb, line 118
def refresh_mrrt(responses, resource)
  logger.verbose("Attempting to obtain access token for #{resource} by " \
                 "refreshing 1 of #{responses.count(&:mrrt?)} matching " \
                 'MRRTs.')
  responses.each do |response|
    if response.mrrt?
      refresh_response = response.refresh(resource)
      return refresh_response if add(refresh_response)
    end
  end
  nil
end
resource_specific(responses, resource) click to toggle source

Searches a list of CachedTokenResponses for one that matches the resource.

@param Array @return SuccessResponse|nil

# File lib/adal/cache_driver.rb, line 136
def resource_specific(responses, resource)
  logger.verbose("Looking through #{responses.size} matching cache " \
                 "entries for resource #{resource}.")
  responses.select { |response| response.resource == resource }
    .map(&:token_response).first
end
update_refresh_tokens(mrrt) click to toggle source

Updates the refresh tokens of all tokens in the cache that match a given MRRT.

@param CachedTokenResponse mrrt

A new MRRT containing a refresh token to update other matching cache
entries with.
# File lib/adal/cache_driver.rb, line 150
def update_refresh_tokens(mrrt)
  fail ArgumentError, 'Token must contain an MRRT.' unless mrrt.mrrt?
  @token_cache.find.each do |entry|
    entry.refresh_token = mrrt.refresh_token if mrrt.can_refresh?(entry)
  end
end
validate(entries) click to toggle source

Checks if an array of current cache entries are still valid, attempts to refresh those that have expired and discards those that cannot be.

@param Array entries

The tokens to validate.

@return Array

# File lib/adal/cache_driver.rb, line 164
def validate(entries)
  logger.verbose("Validating #{entries.size} possible cache matches.")
  valid_entries = entries.group_by(&:validate)
  @token_cache.remove(valid_entries[false] || [])
  valid_entries[true] || []
end