| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/http/http_auth_controller.h" | 5 #include "net/http/http_auth_controller.h" |
| 6 | 6 |
| 7 #include "base/string_util.h" |
| 7 #include "base/utf_string_conversions.h" | 8 #include "base/utf_string_conversions.h" |
| 8 #include "net/base/auth.h" | 9 #include "net/base/auth.h" |
| 9 #include "net/base/host_resolver.h" | 10 #include "net/base/host_resolver.h" |
| 10 #include "net/base/net_util.h" | 11 #include "net/base/net_util.h" |
| 11 #include "net/http/http_auth_handler.h" | 12 #include "net/http/http_auth_handler.h" |
| 12 #include "net/http/http_auth_handler_factory.h" | 13 #include "net/http/http_auth_handler_factory.h" |
| 13 #include "net/http/http_network_session.h" | 14 #include "net/http/http_network_session.h" |
| 14 #include "net/http/http_request_headers.h" | 15 #include "net/http/http_request_headers.h" |
| 15 #include "net/http/http_request_info.h" | 16 #include "net/http/http_request_info.h" |
| 16 #include "net/http/http_response_headers.h" | 17 #include "net/http/http_response_headers.h" |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 auth_token_.clear(); | 145 auth_token_.clear(); |
| 145 } | 146 } |
| 146 | 147 |
| 147 int HttpAuthController::HandleAuthChallenge( | 148 int HttpAuthController::HandleAuthChallenge( |
| 148 scoped_refptr<HttpResponseHeaders> headers, | 149 scoped_refptr<HttpResponseHeaders> headers, |
| 149 bool do_not_send_server_auth, | 150 bool do_not_send_server_auth, |
| 150 bool establishing_tunnel, | 151 bool establishing_tunnel, |
| 151 const BoundNetLog& net_log) { | 152 const BoundNetLog& net_log) { |
| 152 DCHECK(headers); | 153 DCHECK(headers); |
| 153 DCHECK(auth_origin_.is_valid()); | 154 DCHECK(auth_origin_.is_valid()); |
| 154 | |
| 155 LOG(INFO) << "The " << HttpAuth::GetAuthTargetString(target_) << " " | 155 LOG(INFO) << "The " << HttpAuth::GetAuthTargetString(target_) << " " |
| 156 << auth_origin_ << " requested auth" | 156 << auth_origin_ << " requested auth" |
| 157 << AuthChallengeLogMessage(headers.get()); | 157 << AuthChallengeLogMessage(headers.get()); |
| 158 | 158 |
| 159 // The auth we tried just failed, hence it can't be valid. Remove it from | 159 // Give the existing auth handler first try at the authentication headers. |
| 160 // the cache so it won't be used again. | 160 // This will also evict the entry in the HttpAuthCache if the previous |
| 161 // TODO(wtc): IsFinalRound is not the right condition. In a multi-round | 161 // challenge appeared to be rejected, or is using a stale nonce in the Digest |
| 162 // auth sequence, the server may fail the auth in round 1 if our first | 162 // case. |
| 163 // authorization header is broken. We should inspect response_.headers to | 163 if (HaveAuth()) { |
| 164 // determine if the server already failed the auth or wants us to continue. | 164 HttpAuth::AuthorizationResult result = HttpAuth::HandleChallengeResponse( |
| 165 // See http://crbug.com/21015. | 165 handler_.get(), headers, target_, disabled_schemes_); |
| 166 if (HaveAuth() && handler_->IsFinalRound()) { | 166 switch (result) { |
| 167 InvalidateRejectedAuthFromCache(); | 167 case HttpAuth::AUTHORIZATION_RESULT_ACCEPT: |
| 168 handler_.reset(); | 168 break; |
| 169 identity_ = HttpAuth::Identity(); | 169 case HttpAuth::AUTHORIZATION_RESULT_INVALID: |
| 170 case HttpAuth::AUTHORIZATION_RESULT_REJECT: |
| 171 InvalidateCurrentHandler(); |
| 172 break; |
| 173 case HttpAuth::AUTHORIZATION_RESULT_STALE: |
| 174 // TODO(cbentzel): Support "stale" invalidation in HttpAuthCache. |
| 175 // Right now this does the same invalidation as before. |
| 176 InvalidateCurrentHandler(); |
| 177 break; |
| 178 default: |
| 179 NOTREACHED(); |
| 180 break; |
| 181 } |
| 170 } | 182 } |
| 171 | 183 |
| 172 identity_.invalid = true; | 184 identity_.invalid = true; |
| 173 | 185 |
| 174 if (target_ != HttpAuth::AUTH_SERVER || !do_not_send_server_auth) { | 186 bool can_send_auth = (target_ != HttpAuth::AUTH_SERVER || |
| 187 !do_not_send_server_auth); |
| 188 if (!handler_.get() && can_send_auth) { |
| 175 // Find the best authentication challenge that we support. | 189 // Find the best authentication challenge that we support. |
| 176 HttpAuth::ChooseBestChallenge(session_->http_auth_handler_factory(), | 190 HttpAuth::ChooseBestChallenge(session_->http_auth_handler_factory(), |
| 177 headers, target_, auth_origin_, | 191 headers, target_, auth_origin_, |
| 178 disabled_schemes_, net_log, | 192 disabled_schemes_, net_log, |
| 179 &handler_); | 193 &handler_); |
| 180 } | 194 } |
| 181 | 195 |
| 182 if (!handler_.get()) { | 196 if (!handler_.get()) { |
| 183 if (establishing_tunnel) { | 197 if (establishing_tunnel) { |
| 184 LOG(ERROR) << "Can't perform auth to the " | 198 LOG(ERROR) << "Can't perform auth to the " |
| (...skipping 11 matching lines...) Expand all Loading... |
| 196 // so we end up displaying the error page. | 210 // so we end up displaying the error page. |
| 197 return OK; | 211 return OK; |
| 198 } | 212 } |
| 199 | 213 |
| 200 if (handler_->NeedsIdentity()) { | 214 if (handler_->NeedsIdentity()) { |
| 201 // Pick a new auth identity to try, by looking to the URL and auth cache. | 215 // Pick a new auth identity to try, by looking to the URL and auth cache. |
| 202 // If an identity to try is found, it is saved to identity_. | 216 // If an identity to try is found, it is saved to identity_. |
| 203 SelectNextAuthIdentityToTry(); | 217 SelectNextAuthIdentityToTry(); |
| 204 } else { | 218 } else { |
| 205 // Proceed with the existing identity or a null identity. | 219 // Proceed with the existing identity or a null identity. |
| 206 // | |
| 207 // TODO(wtc): Add a safeguard against infinite transaction restarts, if | |
| 208 // the server keeps returning "NTLM". | |
| 209 identity_.invalid = false; | 220 identity_.invalid = false; |
| 210 } | 221 } |
| 211 | 222 |
| 212 // From this point on, we are restartable. | 223 // From this point on, we are restartable. |
| 213 | 224 |
| 214 if (identity_.invalid) { | 225 if (identity_.invalid) { |
| 215 // We have exhausted all identity possibilities, all we can do now is | 226 // We have exhausted all identity possibilities, all we can do now is |
| 216 // pass the challenge information back to the client. | 227 // pass the challenge information back to the client. |
| 217 PopulateAuthChallenge(); | 228 PopulateAuthChallenge(); |
| 218 } else { | 229 } else { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 break; | 267 break; |
| 257 default: | 268 default: |
| 258 session_->auth_cache()->Add(auth_origin_, handler_->realm(), | 269 session_->auth_cache()->Add(auth_origin_, handler_->realm(), |
| 259 handler_->scheme(), handler_->challenge(), | 270 handler_->scheme(), handler_->challenge(), |
| 260 identity_.username, identity_.password, | 271 identity_.username, identity_.password, |
| 261 auth_path_); | 272 auth_path_); |
| 262 break; | 273 break; |
| 263 } | 274 } |
| 264 } | 275 } |
| 265 | 276 |
| 277 void HttpAuthController::InvalidateCurrentHandler() { |
| 278 InvalidateRejectedAuthFromCache(); |
| 279 handler_.reset(); |
| 280 identity_ = HttpAuth::Identity(); |
| 281 } |
| 282 |
| 266 void HttpAuthController::InvalidateRejectedAuthFromCache() { | 283 void HttpAuthController::InvalidateRejectedAuthFromCache() { |
| 267 DCHECK(HaveAuth()); | 284 DCHECK(HaveAuth()); |
| 268 | 285 |
| 269 // TODO(eroman): this short-circuit can be relaxed. If the realm of | 286 // TODO(eroman): this short-circuit can be relaxed. If the realm of |
| 270 // the preemptively used auth entry matches the realm of the subsequent | 287 // the preemptively used auth entry matches the realm of the subsequent |
| 271 // challenge, then we can invalidate the preemptively used entry. | 288 // challenge, then we can invalidate the preemptively used entry. |
| 272 // Otherwise as-is we may send the failed credentials one extra time. | 289 // Otherwise as-is we may send the failed credentials one extra time. |
| 273 if (identity_.source == HttpAuth::IDENT_SRC_PATH_LOOKUP) | 290 if (identity_.source == HttpAuth::IDENT_SRC_PATH_LOOKUP) |
| 274 return; | 291 return; |
| 275 | 292 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 295 &identity_.username, | 312 &identity_.username, |
| 296 &identity_.password); | 313 &identity_.password); |
| 297 embedded_identity_used_ = true; | 314 embedded_identity_used_ = true; |
| 298 // TODO(eroman): If the password is blank, should we also try combining | 315 // TODO(eroman): If the password is blank, should we also try combining |
| 299 // with a password from the cache? | 316 // with a password from the cache? |
| 300 return true; | 317 return true; |
| 301 } | 318 } |
| 302 | 319 |
| 303 // Check the auth cache for a realm entry. | 320 // Check the auth cache for a realm entry. |
| 304 HttpAuthCache::Entry* entry = | 321 HttpAuthCache::Entry* entry = |
| 305 session_->auth_cache()->Lookup(auth_origin_, handler_->realm(), | 322 session_->auth_cache()->Lookup(auth_origin_, handler_->realm(), |
| 306 handler_->scheme()); | 323 handler_->scheme()); |
| 307 | 324 |
| 308 if (entry) { | 325 if (entry) { |
| 309 identity_.source = HttpAuth::IDENT_SRC_REALM_LOOKUP; | 326 identity_.source = HttpAuth::IDENT_SRC_REALM_LOOKUP; |
| 310 identity_.invalid = false; | 327 identity_.invalid = false; |
| 311 identity_.username = entry->username(); | 328 identity_.username = entry->username(); |
| 312 identity_.password = entry->password(); | 329 identity_.password = entry->password(); |
| 313 return true; | 330 return true; |
| 314 } | 331 } |
| 315 | 332 |
| 316 // Use default credentials (single sign on) if this is the first attempt | 333 // Use default credentials (single sign on) if this is the first attempt |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 361 | 378 |
| 362 bool HttpAuthController::IsAuthSchemeDisabled(const std::string& scheme) const { | 379 bool HttpAuthController::IsAuthSchemeDisabled(const std::string& scheme) const { |
| 363 return disabled_schemes_.find(scheme) != disabled_schemes_.end(); | 380 return disabled_schemes_.find(scheme) != disabled_schemes_.end(); |
| 364 } | 381 } |
| 365 | 382 |
| 366 void HttpAuthController::DisableAuthScheme(const std::string& scheme) { | 383 void HttpAuthController::DisableAuthScheme(const std::string& scheme) { |
| 367 disabled_schemes_.insert(scheme); | 384 disabled_schemes_.insert(scheme); |
| 368 } | 385 } |
| 369 | 386 |
| 370 } // namespace net | 387 } // namespace net |
| OLD | NEW |