http_auth.cc revision c7f5f8508d98d5952d42ed7648c2a8f30a4da156
1c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Copyright (c) 2006-2008 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" 11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_auth_handler_basic.h" 12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_auth_handler_digest.h" 13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_auth_handler_negotiate.h" 14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_auth_handler_ntlm.h" 15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_response_headers.h" 16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_util.h" 17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net { 19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid HttpAuth::ChooseBestChallenge(const HttpResponseHeaders* headers, 22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Target target, 23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const GURL& origin, 24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott scoped_refptr<HttpAuthHandler>* handler) { 25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // A connection-based authentication scheme must continue to use the 26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // existing handler object in |*handler|. 27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (*handler && (*handler)->is_connection_based()) { 28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const std::string header_name = GetChallengeHeaderName(target); 29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string challenge; 30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void* iter = NULL; 31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (headers->EnumerateHeader(&iter, header_name, &challenge)) { 32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ChallengeTokenizer props(challenge.begin(), challenge.end()); 33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (LowerCaseEqualsASCII(props.scheme(), (*handler)->scheme().c_str()) && 34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott (*handler)->InitFromChallenge(challenge.begin(), challenge.end(), 35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott target, origin)) 36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Choose the challenge whose authentication handler gives the maximum score. 41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott scoped_refptr<HttpAuthHandler> best; 42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const std::string header_name = GetChallengeHeaderName(target); 43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string cur_challenge; 44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void* iter = NULL; 45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (headers->EnumerateHeader(&iter, header_name, &cur_challenge)) { 46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott scoped_refptr<HttpAuthHandler> cur; 47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott CreateAuthHandler(cur_challenge, target, origin, &cur); 48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (cur && (!best || best->score() < cur->score())) 49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott best.swap(cur); 50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott handler->swap(best); 52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid HttpAuth::CreateAuthHandler(const std::string& challenge, 56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Target target, 57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const GURL& origin, 58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott scoped_refptr<HttpAuthHandler>* handler) { 59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Find the right auth handler for the challenge's scheme. 60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ChallengeTokenizer props(challenge.begin(), challenge.end()); 61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!props.valid()) { 62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *handler = NULL; 63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott scoped_refptr<HttpAuthHandler> tmp_handler; 67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (LowerCaseEqualsASCII(props.scheme(), "basic")) { 68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott tmp_handler = new HttpAuthHandlerBasic(); 69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else if (LowerCaseEqualsASCII(props.scheme(), "digest")) { 70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott tmp_handler = new HttpAuthHandlerDigest(); 71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else if (LowerCaseEqualsASCII(props.scheme(), "negotiate")) { 72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott tmp_handler = new HttpAuthHandlerNegotiate(); 73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else if (LowerCaseEqualsASCII(props.scheme(), "ntlm")) { 74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott tmp_handler = new HttpAuthHandlerNTLM(); 75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (tmp_handler) { 77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!tmp_handler->InitFromChallenge(challenge.begin(), challenge.end(), 78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott target, origin)) { 79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Invalid/unsupported challenge. 80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott tmp_handler = NULL; 81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott handler->swap(tmp_handler); 84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid HttpAuth::ChallengeTokenizer::Init(std::string::const_iterator begin, 87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string::const_iterator end) { 88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // The first space-separated token is the auth-scheme. 89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // NOTE: we are more permissive than RFC 2617 which says auth-scheme 90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // is separated by 1*SP. 91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott StringTokenizer tok(begin, end, HTTP_LWS); 92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!tok.GetNext()) { 93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott valid_ = false; 94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Save the scheme's position. 98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott scheme_begin_ = tok.token_begin(); 99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott scheme_end_ = tok.token_end(); 100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Everything past scheme_end_ is a (comma separated) value list. 102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott props_ = HttpUtil::ValuesIterator(scheme_end_, end, ','); 103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// We expect properties to be formatted as one of: 106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// name="value" 107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// name=value 108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// name= 109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool HttpAuth::ChallengeTokenizer::GetNext() { 110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!props_.GetNext()) 111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Set the value as everything. Next we will split out the name. 114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott value_begin_ = props_.value_begin(); 115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott value_end_ = props_.value_end(); 116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott name_begin_ = name_end_ = value_end_; 117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Scan for the equals sign. 119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string::const_iterator equals = std::find(value_begin_, value_end_, '='); 120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (equals == value_end_ || equals == value_begin_) 121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return valid_ = false; // Malformed 122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Verify that the equals sign we found wasn't inside of quote marks. 124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott for (std::string::const_iterator it = value_begin_; it != equals; ++it) { 125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (HttpUtil::IsQuote(*it)) 126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return valid_ = false; // Malformed 127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott name_begin_ = value_begin_; 130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott name_end_ = equals; 131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott value_begin_ = equals + 1; 132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (value_begin_ != value_end_ && HttpUtil::IsQuote(*value_begin_)) { 134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Trim surrounding quotemarks off the value 135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (*value_begin_ != *(value_end_ - 1)) 136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return valid_ = false; // Malformed -- mismatching quotes. 137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott value_is_quoted_ = true; 138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else { 139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott value_is_quoted_ = false; 140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// If value() has quotemarks, unquote it. 145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstd::string HttpAuth::ChallengeTokenizer::unquoted_value() const { 146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return HttpUtil::Unquote(value_begin_, value_end_); 147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstd::string HttpAuth::GetChallengeHeaderName(Target target) { 151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott switch (target) { 152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott case AUTH_PROXY: 153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return "Proxy-Authenticate"; 154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott case AUTH_SERVER: 155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return "WWW-Authenticate"; 156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott default: 157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NOTREACHED(); 158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return ""; 159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstd::string HttpAuth::GetAuthorizationHeaderName(Target target) { 164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott switch (target) { 165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott case AUTH_PROXY: 166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return "Proxy-Authorization"; 167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott case AUTH_SERVER: 168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return "Authorization"; 169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott default: 170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NOTREACHED(); 171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return ""; 172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} // namespace net 176