Class: RoadForest::HTTP::Keychain
- Inherits:
-
Object
- Object
- RoadForest::HTTP::Keychain
- Defined in:
- lib/roadforest/http/keychain.rb
Overview
Manages user credentials for HTTP Basic auth
Constant Summary collapse
- ATTEMPT_LIMIT =
5
- BASIC_SCHEME =
/basic\s+realm=(?<q>['"])(?<realm>(?:(?!['"]).)*)\k<q>/i
Instance Method Summary collapse
- #add_source(source) ⇒ Object
- #cached_response(url, realm) ⇒ Object
- #canonical_root(url) ⇒ Object
- #challenge_response(url, challenge) ⇒ Object
- #credentials(url, realm = nil) ⇒ Object
- #credentials_for(url) ⇒ Object
- #current_source(url, realm) ⇒ Object
- #forget(url, realm) ⇒ Object
-
#initialize ⇒ Keychain
constructor
A new instance of Keychain.
- #missing_credentials(url, realm) ⇒ Object
- #next_attempt(url, realm) ⇒ Object
- #next_source(url, realm) ⇒ Object
- #preemptive_response(url) ⇒ Object
- #realm_for_url(url) ⇒ Object
- #stripped_url(url) ⇒ Object
Constructor Details
#initialize ⇒ Keychain
Returns a new instance of Keychain.
51 52 53 54 55 56 57 |
# 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 |
Instance Method Details
#add_source(source) ⇒ Object
59 60 61 62 63 |
# 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) ⇒ Object
101 102 103 104 105 |
# 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) ⇒ Object
65 66 67 68 69 70 71 |
# 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) ⇒ Object
82 83 84 85 86 87 88 89 90 91 92 93 |
# 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) ⇒ Object
113 114 115 |
# File 'lib/roadforest/http/keychain.rb', line 113 def credentials(url, realm = nil) @with_realm[[url, realm]] end |
#credentials_for(url) ⇒ Object
107 108 109 110 111 |
# 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) ⇒ Object
137 138 139 |
# File 'lib/roadforest/http/keychain.rb', line 137 def current_source(url, realm) @source_enums[[url, realm]].peek end |
#forget(url, realm) ⇒ Object
133 134 135 |
# File 'lib/roadforest/http/keychain.rb', line 133 def forget(url, realm) @with_realm.delete([url, realm]) end |
#missing_credentials(url, realm) ⇒ Object
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# 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) ⇒ Object
149 150 151 152 153 154 |
# 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) ⇒ Object
141 142 143 144 145 146 147 |
# 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) ⇒ Object
95 96 97 98 99 |
# 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) ⇒ Object
156 157 158 159 160 161 162 163 164 |
# 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) ⇒ Object
73 74 75 76 77 78 |
# 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 |