class RoadForest::HTTP::Keychain

Manages user credentials for HTTP Basic auth

Constants

ATTEMPT_LIMIT
BASIC_SCHEME

Public Class Methods

new() click to toggle source
# File lib/roadforest/http/keychain.rb, line 51
def initialize
  @realm_for_url = {}
  @with_realm = {}
  @sources = []
  @source_enums = Hash.new{|h,k| @sources.each}
  @attempt_enums = Hash.new{|h,k| (0...ATTEMPT_LIMIT).each}
end

Public Instance Methods

add_source(source) click to toggle source
# File lib/roadforest/http/keychain.rb, line 59
def add_source(source)
  @sources << source
  @source_enums.clear
  @attempt_enums.clear
end
cached_response(url, realm) click to toggle source
# File lib/roadforest/http/keychain.rb, line 101
def cached_response(url, realm)
  creds = credentials(url, realm)
  return nil if creds.nil?
  return creds.header_value
end
canonical_root(url) click to toggle source
# File lib/roadforest/http/keychain.rb, line 65
def canonical_root(url)
  url = Addressable::URI.parse(url)
  url.path = "/"
  url.fragment = nil
  url.query = nil
  url.to_s
end
challenge_response(url, challenge) click to toggle source
# File lib/roadforest/http/keychain.rb, line 82
def challenge_response(url, challenge)
  url = stripped_url(url).to_s
  #Future note: the RFC means that the creds selection mechanics are
  #valid for all HTTP WWW-Authenticate reponses
  if (match = BASIC_SCHEME.match(challenge)).nil?
    return nil
  end
  realm = match[:realm]
  @realm_for_url[url] = realm

  cached_response(canonical_root(url), realm) || missing_credentials(url, realm)
end
credentials(url, realm = nil) click to toggle source
# File lib/roadforest/http/keychain.rb, line 113
def credentials(url, realm = nil)
  @with_realm[[url, realm]]
end
credentials_for(url) click to toggle source
# File lib/roadforest/http/keychain.rb, line 107
def credentials_for(url)
  realm = realm_for_url(url)
  url = canonical_root(url)
  credentials(url, realm)
end
current_source(url, realm) click to toggle source
# File lib/roadforest/http/keychain.rb, line 137
def current_source(url, realm)
  @source_enums[[url, realm]].peek
end
forget(url, realm) click to toggle source
# File lib/roadforest/http/keychain.rb, line 133
def forget(url, realm)
  @with_realm.delete([url, realm])
end
missing_credentials(url, realm) click to toggle source
# File lib/roadforest/http/keychain.rb, line 117
def missing_credentials(url, realm)
  loop do
    attempt = next_attempt(url, realm)
    creds = current_source(url, realm).respond_to_challenge(url, realm, attempt)
    if creds.nil?
      next_source(url, realm)
    else
      @with_realm[[canonical_root(url), realm]] = creds
      return creds.header_value
    end
  end
  return nil
rescue StopIteration
  nil
end
next_attempt(url, realm) click to toggle source
# File lib/roadforest/http/keychain.rb, line 149
def next_attempt(url, realm)
  @attempt_enums[[url, realm]].next
rescue StopIteration
  next_source(url, realm)
  retry
end
next_source(url, realm) click to toggle source
# File lib/roadforest/http/keychain.rb, line 141
def next_source(url, realm)
  @attempt_enums.delete([url, realm])
  @source_enums[[url, realm]].next
rescue StopIteration
  @source_enums.delete([url, realm])
  raise
end
preemptive_response(url) click to toggle source
# File lib/roadforest/http/keychain.rb, line 95
def preemptive_response(url)
  realm = realm_for_url(url)
  url = canonical_root(url)
  return cached_response(url, realm)
end
realm_for_url(url) click to toggle source
# File lib/roadforest/http/keychain.rb, line 156
def realm_for_url(url)
  url = stripped_url(url)
  while (realm = @realm_for_url[url.to_s]).nil?
    new_url = url.join("..")
    return realm if new_url == url
    url = new_url
  end
  return realm || :default
end
stripped_url(url) click to toggle source
# File lib/roadforest/http/keychain.rb, line 73
def stripped_url(url)
  url = Addressable::URI.parse(url)
  url.fragment = nil
  url.query = nil
  url
end