http_auth_controller.cc revision 868fa2fe829687343ffae624259930155e16dbd8
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_auth_controller.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_util.h" 11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/platform_thread.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/auth.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/dns/host_resolver.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_auth_handler.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_auth_handler_factory.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_network_session.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_request_headers.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_request_info.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_response_headers.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns a log message for all the response headers related to the auth 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// challenge. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string AuthChallengeLogMessage(HttpResponseHeaders* headers) { 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string msg; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string header_val; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* iter = NULL; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (headers->EnumerateHeader(&iter, "proxy-authenticate", &header_val)) { 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) msg.append("\n Has header Proxy-Authenticate: "); 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) msg.append(header_val); 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter = NULL; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (headers->EnumerateHeader(&iter, "www-authenticate", &header_val)) { 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) msg.append("\n Has header WWW-Authenticate: "); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) msg.append(header_val); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // authentication with a "Proxy-Support: Session-Based-Authentication" 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // response header. 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter = NULL; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (headers->EnumerateHeader(&iter, "proxy-support", &header_val)) { 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) msg.append("\n Has header Proxy-Support: "); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) msg.append(header_val); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return msg; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum AuthEvent { 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AUTH_EVENT_START = 0, 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AUTH_EVENT_REJECT, 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AUTH_EVENT_MAX, 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum AuthTarget { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AUTH_TARGET_PROXY = 0, 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AUTH_TARGET_SECURE_PROXY, 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AUTH_TARGET_SERVER, 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AUTH_TARGET_SECURE_SERVER, 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AUTH_TARGET_MAX, 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AuthTarget DetermineAuthTarget(const HttpAuthHandler* handler) { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (handler->target()) { 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case HttpAuth::AUTH_PROXY: 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (handler->origin().SchemeIsSecure()) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return AUTH_TARGET_SECURE_PROXY; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return AUTH_TARGET_PROXY; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case HttpAuth::AUTH_SERVER: 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (handler->origin().SchemeIsSecure()) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return AUTH_TARGET_SECURE_SERVER; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return AUTH_TARGET_SERVER; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return AUTH_TARGET_MAX; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Records the number of authentication events per authentication scheme. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistogramAuthEvent(HttpAuthHandler* handler, AuthEvent auth_event) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(NDEBUG) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: The on-same-thread check is intentionally not using a lock 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to protect access to first_thread. This method is meant to be only 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // used on the same thread, in which case there are no race conditions. If 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // there are race conditions (say, a read completes during a partial write), 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the DCHECK will correctly fail. 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static base::PlatformThreadId first_thread = 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::PlatformThread::CurrentId(); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(first_thread, base::PlatformThread::CurrentId()); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuth::Scheme auth_scheme = handler->auth_scheme(); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(auth_scheme >= 0 && auth_scheme < HttpAuth::AUTH_SCHEME_MAX); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Record start and rejection events for authentication. 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The results map to: 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Basic Start: 0 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Basic Reject: 1 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Digest Start: 2 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Digest Reject: 3 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NTLM Start: 4 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NTLM Reject: 5 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Negotiate Start: 6 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Negotiate Reject: 7 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int kEventBucketsEnd = 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuth::AUTH_SCHEME_MAX * AUTH_EVENT_MAX; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int event_bucket = auth_scheme * AUTH_EVENT_MAX + auth_event; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(event_bucket >= 0 && event_bucket < kEventBucketsEnd); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("Net.HttpAuthCount", event_bucket, 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kEventBucketsEnd); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Record the target of the authentication. 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The results map to: 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Basic Proxy: 0 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Basic Secure Proxy: 1 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Basic Server: 2 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Basic Secure Server: 3 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Digest Proxy: 4 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Digest Secure Proxy: 5 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Digest Server: 6 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Digest Secure Server: 7 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NTLM Proxy: 8 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NTLM Secure Proxy: 9 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NTLM Server: 10 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NTLM Secure Server: 11 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Negotiate Proxy: 12 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Negotiate Secure Proxy: 13 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Negotiate Server: 14 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Negotiate Secure Server: 15 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (auth_event != AUTH_EVENT_START) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int kTargetBucketsEnd = 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuth::AUTH_SCHEME_MAX * AUTH_TARGET_MAX; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AuthTarget auth_target = DetermineAuthTarget(handler); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int target_bucket = auth_scheme * AUTH_TARGET_MAX + auth_target; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(target_bucket >= 0 && target_bucket < kTargetBucketsEnd); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("Net.HttpAuthTarget", target_bucket, 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kTargetBucketsEnd); 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpAuthController::HttpAuthController( 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuth::Target target, 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& auth_url, 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuthCache* http_auth_cache, 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuthHandlerFactory* http_auth_handler_factory) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : target_(target), 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_url_(auth_url), 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_origin_(auth_url.GetOrigin()), 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_path_(HttpAuth::AUTH_PROXY ? std::string() : auth_url.path()), 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) embedded_identity_used_(false), 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_credentials_used_(false), 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) http_auth_cache_(http_auth_cache), 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) http_auth_handler_factory_(http_auth_handler_factory) { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpAuthController::~HttpAuthController() { 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpAuthController::MaybeGenerateAuthToken( 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const HttpRequestInfo* request, const CompletionCallback& callback, 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BoundNetLog& net_log) { 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool needs_auth = HaveAuth() || SelectPreemptiveAuth(net_log); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!needs_auth) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AuthCredentials* credentials = NULL; 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (identity_.source != HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) credentials = &identity_.credentials; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(auth_token_.empty()); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(callback_.is_null()); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = handler_->GenerateAuthToken( 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) credentials, request, 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&HttpAuthController::OnIOComplete, base::Unretained(this)), 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &auth_token_); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (DisableOnAuthHandlerResult(rv)) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = OK; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv == ERR_IO_PENDING) 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_ = callback; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnIOComplete(rv); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpAuthController::SelectPreemptiveAuth(const BoundNetLog& net_log) { 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!HaveAuth()); 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(identity_.invalid); 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Don't do preemptive authorization if the URL contains a username:password, 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // since we must first be challenged in order to use the URL's identity. 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (auth_url_.has_username()) 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SelectPreemptiveAuth() is on the critical path for each request, so it 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is expected to be fast. LookupByPath() is fast in the common case, since 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the number of http auth cache entries is expected to be very small. 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (For most users in fact, it will be 0.) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuthCache::Entry* entry = http_auth_cache_->LookupByPath( 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_origin_, auth_path_); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!entry) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Try to create a handler using the previous auth challenge. 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<HttpAuthHandler> handler_preemptive; 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv_create = http_auth_handler_factory_-> 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreatePreemptiveAuthHandlerFromString(entry->auth_challenge(), target_, 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_origin_, 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry->IncrementNonceCount(), 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log, &handler_preemptive); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv_create != OK) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set the state 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity_.source = HttpAuth::IDENT_SRC_PATH_LOOKUP; 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity_.invalid = false; 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity_.credentials = entry->credentials(); 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handler_.swap(handler_preemptive); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpAuthController::AddAuthorizationHeader( 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpRequestHeaders* authorization_headers) { 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(HaveAuth()); 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // auth_token_ can be empty if we encountered a permanent error with 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the auth scheme and want to retry. 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!auth_token_.empty()) { 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) authorization_headers->SetHeader( 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuth::GetAuthorizationHeaderName(target_), auth_token_); 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_token_.clear(); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpAuthController::HandleAuthChallenge( 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<HttpResponseHeaders> headers, 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool do_not_send_server_auth, 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool establishing_tunnel, 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BoundNetLog& net_log) { 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 254868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(headers.get()); 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(auth_origin_.is_valid()); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "The " << HttpAuth::GetAuthTargetString(target_) << " " 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << auth_origin_ << " requested auth " 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << AuthChallengeLogMessage(headers.get()); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Give the existing auth handler first try at the authentication headers. 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This will also evict the entry in the HttpAuthCache if the previous 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // challenge appeared to be rejected, or is using a stale nonce in the Digest 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // case. 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HaveAuth()) { 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string challenge_used; 266868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) HttpAuth::AuthorizationResult result = 267868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) HttpAuth::HandleChallengeResponse(handler_.get(), 268868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) headers.get(), 269868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) target_, 270868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) disabled_schemes_, 271868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) &challenge_used); 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (result) { 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case HttpAuth::AUTHORIZATION_RESULT_ACCEPT: 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case HttpAuth::AUTHORIZATION_RESULT_INVALID: 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case HttpAuth::AUTHORIZATION_RESULT_REJECT: 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HistogramAuthEvent(handler_.get(), AUTH_EVENT_REJECT); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS); 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case HttpAuth::AUTHORIZATION_RESULT_STALE: 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (http_auth_cache_->UpdateStaleChallenge(auth_origin_, 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handler_->realm(), 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handler_->auth_scheme(), 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) challenge_used)) { 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InvalidateCurrentHandler(INVALIDATE_HANDLER); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It's possible that a server could incorrectly issue a stale 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // response when the entry is not in the cache. Just evict the 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // current value from the cache. 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS); 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case HttpAuth::AUTHORIZATION_RESULT_DIFFERENT_REALM: 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the server changes the authentication realm in a 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // subsequent challenge, invalidate cached credentials for the 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // previous realm. If the server rejects a preemptive 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // authorization and requests credentials for a different 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // realm, we keep the cached credentials. 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InvalidateCurrentHandler( 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (identity_.source == HttpAuth::IDENT_SRC_PATH_LOOKUP) ? 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INVALIDATE_HANDLER : 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS); 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity_.invalid = true; 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool can_send_auth = (target_ != HttpAuth::AUTH_SERVER || 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !do_not_send_server_auth); 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!handler_.get() && can_send_auth) { 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Find the best authentication challenge that we support. 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuth::ChooseBestChallenge(http_auth_handler_factory_, 321868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) headers.get(), 322868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) target_, 323868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) auth_origin_, 324868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) disabled_schemes_, 325868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) net_log, 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &handler_); 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (handler_.get()) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HistogramAuthEvent(handler_.get(), AUTH_EVENT_START); 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!handler_.get()) { 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (establishing_tunnel) { 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Can't perform auth to the " 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << HttpAuth::GetAuthTargetString(target_) << " " 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << auth_origin_ << " when establishing a tunnel" 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << AuthChallengeLogMessage(headers.get()); 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We are establishing a tunnel, we can't show the error page because an 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // active network attacker could control its contents. Instead, we just 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // fail to establish the tunnel. 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(target_ == HttpAuth::AUTH_PROXY); 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_PROXY_AUTH_UNSUPPORTED; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We found no supported challenge -- let the transaction continue so we 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // end up displaying the error page. 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (handler_->NeedsIdentity()) { 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Pick a new auth identity to try, by looking to the URL and auth cache. 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If an identity to try is found, it is saved to identity_. 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SelectNextAuthIdentityToTry(); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Proceed with the existing identity or a null identity. 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity_.invalid = false; 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // From this point on, we are restartable. 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (identity_.invalid) { 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have exhausted all identity possibilities. 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!handler_->AllowsExplicitCredentials()) { 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the handler doesn't accept explicit credentials, then we need to 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // choose a different auth scheme. 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HistogramAuthEvent(handler_.get(), AUTH_EVENT_REJECT); 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_DISABLE_SCHEME); 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Pass the challenge information back to the client. 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PopulateAuthChallenge(); 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_info_ = NULL; 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we get here and we don't have a handler_, that's because we 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // invalidated it due to not having any viable identities to use with it. Go 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // back and try again. 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(asanka): Instead we should create a priority list of 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // <handler,identity> and iterate through that. 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while(!handler_.get()); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpAuthController::ResetAuth(const AuthCredentials& credentials) { 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(identity_.invalid || credentials.Empty()); 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (identity_.invalid) { 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Update the credentials. 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity_.source = HttpAuth::IDENT_SRC_EXTERNAL; 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity_.invalid = false; 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity_.credentials = credentials; 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(identity_.source != HttpAuth::IDENT_SRC_PATH_LOOKUP); 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add the auth entry to the cache before restarting. We don't know whether 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the identity is valid yet, but if it is valid we want other transactions 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to know about it. If an entry for (origin, handler->realm()) already 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // exists, we update it. 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If identity_.source is HttpAuth::IDENT_SRC_NONE or 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS, identity_ contains no 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // identity because identity is not required yet or we're using default 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // credentials. 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(wtc): For NTLM_SSPI, we add the same auth entry to the cache in 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // round 1 and round 2, which is redundant but correct. It would be nice 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to add an auth entry to the cache only once, preferrably in round 1. 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // See http://crbug.com/21015. 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (identity_.source) { 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case HttpAuth::IDENT_SRC_NONE: 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS: 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) http_auth_cache_->Add(auth_origin_, handler_->realm(), 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handler_->auth_scheme(), handler_->challenge(), 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity_.credentials, auth_path_); 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpAuthController::HaveAuthHandler() const { 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return handler_.get() != NULL; 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpAuthController::HaveAuth() const { 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return handler_.get() && !identity_.invalid; 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpAuthController::InvalidateCurrentHandler( 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InvalidateHandlerAction action) { 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(handler_.get()); 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (action == INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS) 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InvalidateRejectedAuthFromCache(); 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (action == INVALIDATE_HANDLER_AND_DISABLE_SCHEME) 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DisableAuthScheme(handler_->auth_scheme()); 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handler_.reset(); 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity_ = HttpAuth::Identity(); 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpAuthController::InvalidateRejectedAuthFromCache() { 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(HaveAuth()); 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Clear the cache entry for the identity we just failed on. 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: we require the credentials to match before invalidating 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // since the entry in the cache may be newer than what we used last time. 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) http_auth_cache_->Remove(auth_origin_, handler_->realm(), 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handler_->auth_scheme(), identity_.credentials); 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpAuthController::SelectNextAuthIdentityToTry() { 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(handler_.get()); 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(identity_.invalid); 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Try to use the username:password encoded into the URL first. 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (target_ == HttpAuth::AUTH_SERVER && auth_url_.has_username() && 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !embedded_identity_used_) { 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity_.source = HttpAuth::IDENT_SRC_URL; 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity_.invalid = false; 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Extract the username:password from the URL. 466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::string16 username; 467c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::string16 password; 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetIdentityFromURL(auth_url_, &username, &password); 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity_.credentials.Set(username, password); 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) embedded_identity_used_ = true; 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(eroman): If the password is blank, should we also try combining 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // with a password from the cache? 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_BOOLEAN("net.HttpIdentSrcURL", true); 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check the auth cache for a realm entry. 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuthCache::Entry* entry = 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) http_auth_cache_->Lookup(auth_origin_, handler_->realm(), 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handler_->auth_scheme()); 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (entry) { 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity_.source = HttpAuth::IDENT_SRC_REALM_LOOKUP; 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity_.invalid = false; 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity_.credentials = entry->credentials(); 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use default credentials (single sign on) if this is the first attempt 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // at identity. Do not allow multiple times as it will infinite loop. 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We use default credentials after checking the auth cache so that if 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // single sign-on doesn't work, we won't try default credentials for future 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // transactions. 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!default_credentials_used_ && handler_->AllowsDefaultCredentials()) { 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity_.source = HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS; 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity_.invalid = false; 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_credentials_used_ = true; 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpAuthController::PopulateAuthChallenge() { 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Populates response_.auth_challenge with the authentication challenge info. 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo(). 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_info_ = new AuthChallengeInfo; 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_info_->is_proxy = (target_ == HttpAuth::AUTH_PROXY); 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_info_->challenger = HostPortPair::FromURL(auth_origin_); 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_info_->scheme = HttpAuth::SchemeToString(handler_->auth_scheme()); 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_info_->realm = handler_->realm(); 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpAuthController::DisableOnAuthHandlerResult(int result) { 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (result) { 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Occurs with GSSAPI, if the user has not already logged in. 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_MISSING_AUTH_CREDENTIALS: 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Can occur with GSSAPI or SSPI if the underlying library reports 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a permanent error. 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_UNSUPPORTED_AUTH_SCHEME: 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // These two error codes represent failures we aren't handling. 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS: 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS: 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Can be returned by SSPI if the authenticating authority or 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // target is not known. 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_MISCONFIGURED_AUTH_ENVIRONMENT: 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In these cases, disable the current scheme as it cannot 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // succeed. 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DisableAuthScheme(handler_->auth_scheme()); 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_token_.clear(); 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpAuthController::OnIOComplete(int result) { 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (DisableOnAuthHandlerResult(result)) 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = OK; 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!callback_.is_null()) { 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CompletionCallback c = callback_; 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_.Reset(); 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c.Run(result); 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_refptr<AuthChallengeInfo> HttpAuthController::auth_info() { 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return auth_info_; 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpAuthController::IsAuthSchemeDisabled(HttpAuth::Scheme scheme) const { 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return disabled_schemes_.find(scheme) != disabled_schemes_.end(); 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpAuthController::DisableAuthScheme(HttpAuth::Scheme scheme) { 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) disabled_schemes_.insert(scheme); 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 574