1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be 3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file. 4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_auth.h" 6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <algorithm> 8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/basictypes.h" 10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_util.h" 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_errors.h" 12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_auth_handler_basic.h" 13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_auth_handler_digest.h" 14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_auth_handler_negotiate.h" 15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_auth_handler_ntlm.h" 16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_response_headers.h" 17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_util.h" 18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net { 20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 21731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickHttpAuth::Identity::Identity() : source(IDENT_SRC_NONE), invalid(true) {} 22731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HttpAuth::ChooseBestChallenge( 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch HttpAuthHandlerFactory* http_auth_handler_factory, 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const HttpResponseHeaders* headers, 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Target target, 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& origin, 2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const std::set<Scheme>& disabled_schemes, 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const BoundNetLog& net_log, 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<HttpAuthHandler>* handler) { 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(http_auth_handler_factory); 333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(handler->get() == NULL); 34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Choose the challenge whose authentication handler gives the maximum score. 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<HttpAuthHandler> best; 37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const std::string header_name = GetChallengeHeaderName(target); 38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string cur_challenge; 39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void* iter = NULL; 40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (headers->EnumerateHeader(&iter, header_name, &cur_challenge)) { 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<HttpAuthHandler> cur; 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int rv = http_auth_handler_factory->CreateAuthHandlerFromString( 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cur_challenge, target, origin, net_log, &cur); 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (rv != OK) { 45731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "Unable to create AuthHandler. Status: " 46731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick << ErrorToString(rv) << " Challenge: " << cur_challenge; 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (cur.get() && (!best.get() || best->score() < cur->score()) && 5072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen (disabled_schemes.find(cur->auth_scheme()) == disabled_schemes.end())) 513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick best.swap(cur); 52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch handler->swap(best); 54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// static 573345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickHttpAuth::AuthorizationResult HttpAuth::HandleChallengeResponse( 583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick HttpAuthHandler* handler, 593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const HttpResponseHeaders* headers, 603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick Target target, 6172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const std::set<Scheme>& disabled_schemes, 623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::string* challenge_used) { 63731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(handler); 64731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(headers); 653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(challenge_used); 66731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick challenge_used->clear(); 6772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen HttpAuth::Scheme current_scheme = handler->auth_scheme(); 683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (disabled_schemes.find(current_scheme) != disabled_schemes.end()) 693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return HttpAuth::AUTHORIZATION_RESULT_REJECT; 7072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::string current_scheme_name = SchemeToString(current_scheme); 713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const std::string header_name = GetChallengeHeaderName(target); 723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick void* iter = NULL; 733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::string challenge; 743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick HttpAuth::AuthorizationResult authorization_result = 753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick HttpAuth::AUTHORIZATION_RESULT_INVALID; 763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick while (headers->EnumerateHeader(&iter, header_name, &challenge)) { 773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick HttpAuth::ChallengeTokenizer props(challenge.begin(), challenge.end()); 7872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!LowerCaseEqualsASCII(props.scheme(), current_scheme_name.c_str())) 793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick continue; 803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick authorization_result = handler->HandleAnotherChallenge(&props); 813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (authorization_result != HttpAuth::AUTHORIZATION_RESULT_INVALID) { 823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick *challenge_used = challenge; 833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return authorization_result; 843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Finding no matches is equivalent to rejection. 873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return HttpAuth::AUTHORIZATION_RESULT_REJECT; 883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 9072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenHttpUtil::NameValuePairsIterator HttpAuth::ChallengeTokenizer::param_pairs() 9172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const { 9272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return HttpUtil::NameValuePairsIterator(params_begin_, params_end_, ','); 9372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 9472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 9572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstd::string HttpAuth::ChallengeTokenizer::base64_param() const { 9672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Strip off any padding. 9772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // (See https://bugzilla.mozilla.org/show_bug.cgi?id=230351.) 9872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 9972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Our base64 decoder requires that the length be a multiple of 4. 10072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int encoded_length = params_end_ - params_begin_; 10172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen while (encoded_length > 0 && encoded_length % 4 != 0 && 10272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen params_begin_[encoded_length - 1] == '=') { 10372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen --encoded_length; 10472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 10572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return std::string(params_begin_, params_begin_ + encoded_length); 10672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 10772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid HttpAuth::ChallengeTokenizer::Init(std::string::const_iterator begin, 109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string::const_iterator end) { 110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // The first space-separated token is the auth-scheme. 111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // NOTE: we are more permissive than RFC 2617 which says auth-scheme 112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // is separated by 1*SP. 113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott StringTokenizer tok(begin, end, HTTP_LWS); 114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!tok.GetNext()) { 115731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Default param and scheme iterators provide empty strings 116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Save the scheme's position. 120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott scheme_begin_ = tok.token_begin(); 121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott scheme_end_ = tok.token_end(); 122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 123731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick params_begin_ = scheme_end_; 124731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick params_end_ = end; 125731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick HttpUtil::TrimLWS(¶ms_begin_, ¶ms_end_); 126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstd::string HttpAuth::GetChallengeHeaderName(Target target) { 130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott switch (target) { 131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott case AUTH_PROXY: 132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return "Proxy-Authenticate"; 133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott case AUTH_SERVER: 134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return "WWW-Authenticate"; 135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott default: 136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NOTREACHED(); 137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return ""; 138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstd::string HttpAuth::GetAuthorizationHeaderName(Target target) { 143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott switch (target) { 144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott case AUTH_PROXY: 145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return "Proxy-Authorization"; 146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott case AUTH_SERVER: 147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return "Authorization"; 148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott default: 149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NOTREACHED(); 150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return ""; 151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 15572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstd::string HttpAuth::GetAuthTargetString(Target target) { 15672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen switch (target) { 15772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen case AUTH_PROXY: 15872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return "proxy"; 15972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen case AUTH_SERVER: 16072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return "server"; 16172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen default: 16272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen NOTREACHED(); 16372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return ""; 16472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 16572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 16672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 16772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// static 16872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst char* HttpAuth::SchemeToString(Scheme scheme) { 16972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen static const char* const kSchemeNames[] = { 17072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen "basic", 17172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen "digest", 17272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen "ntlm", 17372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen "negotiate", 17472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen "mock", 17572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen }; 17672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen COMPILE_ASSERT(arraysize(kSchemeNames) == AUTH_SCHEME_MAX, 17772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen http_auth_scheme_names_incorrect_size); 17872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (scheme < AUTH_SCHEME_BASIC || scheme >= AUTH_SCHEME_MAX) { 17972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen NOTREACHED(); 18072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return "invalid_scheme"; 18172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 18272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return kSchemeNames[scheme]; 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} // namespace net 186