| Index: net/http/http_auth_handler_digest.cc
|
| diff --git a/net/http/http_auth_handler_digest.cc b/net/http/http_auth_handler_digest.cc
|
| deleted file mode 100644
|
| index 7dee081ddbe9ed7de7ea60ac6a6fa3a64419f2f9..0000000000000000000000000000000000000000
|
| --- a/net/http/http_auth_handler_digest.cc
|
| +++ /dev/null
|
| @@ -1,383 +0,0 @@
|
| -// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "net/http/http_auth_handler_digest.h"
|
| -
|
| -#include <string>
|
| -
|
| -#include "base/logging.h"
|
| -#include "base/md5.h"
|
| -#include "base/rand_util.h"
|
| -#include "base/strings/string_util.h"
|
| -#include "base/strings/stringprintf.h"
|
| -#include "base/strings/utf_string_conversions.h"
|
| -#include "net/base/net_errors.h"
|
| -#include "net/base/net_string_util.h"
|
| -#include "net/base/net_util.h"
|
| -#include "net/http/http_auth.h"
|
| -#include "net/http/http_auth_challenge_tokenizer.h"
|
| -#include "net/http/http_request_info.h"
|
| -#include "net/http/http_util.h"
|
| -#include "url/gurl.h"
|
| -
|
| -namespace net {
|
| -
|
| -// Digest authentication is specified in RFC 2617.
|
| -// The expanded derivations are listed in the tables below.
|
| -
|
| -//==========+==========+==========================================+
|
| -// qop |algorithm | response |
|
| -//==========+==========+==========================================+
|
| -// ? | ?, md5, | MD5(MD5(A1):nonce:MD5(A2)) |
|
| -// | md5-sess | |
|
| -//--------- +----------+------------------------------------------+
|
| -// auth, | ?, md5, | MD5(MD5(A1):nonce:nc:cnonce:qop:MD5(A2)) |
|
| -// auth-int | md5-sess | |
|
| -//==========+==========+==========================================+
|
| -// qop |algorithm | A1 |
|
| -//==========+==========+==========================================+
|
| -// | ?, md5 | user:realm:password |
|
| -//----------+----------+------------------------------------------+
|
| -// | md5-sess | MD5(user:realm:password):nonce:cnonce |
|
| -//==========+==========+==========================================+
|
| -// qop |algorithm | A2 |
|
| -//==========+==========+==========================================+
|
| -// ?, auth | | req-method:req-uri |
|
| -//----------+----------+------------------------------------------+
|
| -// auth-int | | req-method:req-uri:MD5(req-entity-body) |
|
| -//=====================+==========================================+
|
| -
|
| -HttpAuthHandlerDigest::NonceGenerator::NonceGenerator() {
|
| -}
|
| -
|
| -HttpAuthHandlerDigest::NonceGenerator::~NonceGenerator() {
|
| -}
|
| -
|
| -HttpAuthHandlerDigest::DynamicNonceGenerator::DynamicNonceGenerator() {
|
| -}
|
| -
|
| -std::string HttpAuthHandlerDigest::DynamicNonceGenerator::GenerateNonce()
|
| - const {
|
| - // This is how mozilla generates their cnonce -- a 16 digit hex string.
|
| - static const char domain[] = "0123456789abcdef";
|
| - std::string cnonce;
|
| - cnonce.reserve(16);
|
| - for (int i = 0; i < 16; ++i)
|
| - cnonce.push_back(domain[base::RandInt(0, 15)]);
|
| - return cnonce;
|
| -}
|
| -
|
| -HttpAuthHandlerDigest::FixedNonceGenerator::FixedNonceGenerator(
|
| - const std::string& nonce)
|
| - : nonce_(nonce) {
|
| -}
|
| -
|
| -std::string HttpAuthHandlerDigest::FixedNonceGenerator::GenerateNonce() const {
|
| - return nonce_;
|
| -}
|
| -
|
| -HttpAuthHandlerDigest::Factory::Factory()
|
| - : nonce_generator_(new DynamicNonceGenerator()) {
|
| -}
|
| -
|
| -HttpAuthHandlerDigest::Factory::~Factory() {
|
| -}
|
| -
|
| -void HttpAuthHandlerDigest::Factory::set_nonce_generator(
|
| - const NonceGenerator* nonce_generator) {
|
| - nonce_generator_.reset(nonce_generator);
|
| -}
|
| -
|
| -int HttpAuthHandlerDigest::Factory::CreateAuthHandler(
|
| - HttpAuthChallengeTokenizer* challenge,
|
| - HttpAuth::Target target,
|
| - const GURL& origin,
|
| - CreateReason reason,
|
| - int digest_nonce_count,
|
| - const BoundNetLog& net_log,
|
| - scoped_ptr<HttpAuthHandler>* handler) {
|
| - // TODO(cbentzel): Move towards model of parsing in the factory
|
| - // method and only constructing when valid.
|
| - scoped_ptr<HttpAuthHandler> tmp_handler(
|
| - new HttpAuthHandlerDigest(digest_nonce_count, nonce_generator_.get()));
|
| - if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log))
|
| - return ERR_INVALID_RESPONSE;
|
| - handler->swap(tmp_handler);
|
| - return OK;
|
| -}
|
| -
|
| -HttpAuth::AuthorizationResult HttpAuthHandlerDigest::HandleAnotherChallenge(
|
| - HttpAuthChallengeTokenizer* challenge) {
|
| - // Even though Digest is not connection based, a "second round" is parsed
|
| - // to differentiate between stale and rejected responses.
|
| - // Note that the state of the current handler is not mutated - this way if
|
| - // there is a rejection the realm hasn't changed.
|
| - if (!LowerCaseEqualsASCII(challenge->scheme(), "digest"))
|
| - return HttpAuth::AUTHORIZATION_RESULT_INVALID;
|
| -
|
| - HttpUtil::NameValuePairsIterator parameters = challenge->param_pairs();
|
| -
|
| - // Try to find the "stale" value, and also keep track of the realm
|
| - // for the new challenge.
|
| - std::string original_realm;
|
| - while (parameters.GetNext()) {
|
| - if (LowerCaseEqualsASCII(parameters.name(), "stale")) {
|
| - if (LowerCaseEqualsASCII(parameters.value(), "true"))
|
| - return HttpAuth::AUTHORIZATION_RESULT_STALE;
|
| - } else if (LowerCaseEqualsASCII(parameters.name(), "realm")) {
|
| - original_realm = parameters.value();
|
| - }
|
| - }
|
| - return (original_realm_ != original_realm) ?
|
| - HttpAuth::AUTHORIZATION_RESULT_DIFFERENT_REALM :
|
| - HttpAuth::AUTHORIZATION_RESULT_REJECT;
|
| -}
|
| -
|
| -bool HttpAuthHandlerDigest::Init(HttpAuthChallengeTokenizer* challenge) {
|
| - return ParseChallenge(challenge);
|
| -}
|
| -
|
| -int HttpAuthHandlerDigest::GenerateAuthTokenImpl(
|
| - const AuthCredentials* credentials, const HttpRequestInfo* request,
|
| - const CompletionCallback& callback, std::string* auth_token) {
|
| - // Generate a random client nonce.
|
| - std::string cnonce = nonce_generator_->GenerateNonce();
|
| -
|
| - // Extract the request method and path -- the meaning of 'path' is overloaded
|
| - // in certain cases, to be a hostname.
|
| - std::string method;
|
| - std::string path;
|
| - GetRequestMethodAndPath(request, &method, &path);
|
| -
|
| - *auth_token = AssembleCredentials(method, path, *credentials,
|
| - cnonce, nonce_count_);
|
| - return OK;
|
| -}
|
| -
|
| -HttpAuthHandlerDigest::HttpAuthHandlerDigest(
|
| - int nonce_count, const NonceGenerator* nonce_generator)
|
| - : stale_(false),
|
| - algorithm_(ALGORITHM_UNSPECIFIED),
|
| - qop_(QOP_UNSPECIFIED),
|
| - nonce_count_(nonce_count),
|
| - nonce_generator_(nonce_generator) {
|
| - DCHECK(nonce_generator_);
|
| -}
|
| -
|
| -HttpAuthHandlerDigest::~HttpAuthHandlerDigest() {
|
| -}
|
| -
|
| -// The digest challenge header looks like:
|
| -// WWW-Authenticate: Digest
|
| -// [realm="<realm-value>"]
|
| -// nonce="<nonce-value>"
|
| -// [domain="<list-of-URIs>"]
|
| -// [opaque="<opaque-token-value>"]
|
| -// [stale="<true-or-false>"]
|
| -// [algorithm="<digest-algorithm>"]
|
| -// [qop="<list-of-qop-values>"]
|
| -// [<extension-directive>]
|
| -//
|
| -// Note that according to RFC 2617 (section 1.2) the realm is required.
|
| -// However we allow it to be omitted, in which case it will default to the
|
| -// empty string.
|
| -//
|
| -// This allowance is for better compatibility with webservers that fail to
|
| -// send the realm (See http://crbug.com/20984 for an instance where a
|
| -// webserver was not sending the realm with a BASIC challenge).
|
| -bool HttpAuthHandlerDigest::ParseChallenge(
|
| - HttpAuthChallengeTokenizer* challenge) {
|
| - auth_scheme_ = HttpAuth::AUTH_SCHEME_DIGEST;
|
| - score_ = 2;
|
| - properties_ = ENCRYPTS_IDENTITY;
|
| -
|
| - // Initialize to defaults.
|
| - stale_ = false;
|
| - algorithm_ = ALGORITHM_UNSPECIFIED;
|
| - qop_ = QOP_UNSPECIFIED;
|
| - realm_ = original_realm_ = nonce_ = domain_ = opaque_ = std::string();
|
| -
|
| - // FAIL -- Couldn't match auth-scheme.
|
| - if (!LowerCaseEqualsASCII(challenge->scheme(), "digest"))
|
| - return false;
|
| -
|
| - HttpUtil::NameValuePairsIterator parameters = challenge->param_pairs();
|
| -
|
| - // Loop through all the properties.
|
| - while (parameters.GetNext()) {
|
| - // FAIL -- couldn't parse a property.
|
| - if (!ParseChallengeProperty(parameters.name(),
|
| - parameters.value()))
|
| - return false;
|
| - }
|
| -
|
| - // Check if tokenizer failed.
|
| - if (!parameters.valid())
|
| - return false;
|
| -
|
| - // Check that a minimum set of properties were provided.
|
| - if (nonce_.empty())
|
| - return false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool HttpAuthHandlerDigest::ParseChallengeProperty(const std::string& name,
|
| - const std::string& value) {
|
| - if (LowerCaseEqualsASCII(name, "realm")) {
|
| - std::string realm;
|
| - if (!net::ConvertToUtf8AndNormalize(value, kCharsetLatin1, &realm))
|
| - return false;
|
| - realm_ = realm;
|
| - original_realm_ = value;
|
| - } else if (LowerCaseEqualsASCII(name, "nonce")) {
|
| - nonce_ = value;
|
| - } else if (LowerCaseEqualsASCII(name, "domain")) {
|
| - domain_ = value;
|
| - } else if (LowerCaseEqualsASCII(name, "opaque")) {
|
| - opaque_ = value;
|
| - } else if (LowerCaseEqualsASCII(name, "stale")) {
|
| - // Parse the stale boolean.
|
| - stale_ = LowerCaseEqualsASCII(value, "true");
|
| - } else if (LowerCaseEqualsASCII(name, "algorithm")) {
|
| - // Parse the algorithm.
|
| - if (LowerCaseEqualsASCII(value, "md5")) {
|
| - algorithm_ = ALGORITHM_MD5;
|
| - } else if (LowerCaseEqualsASCII(value, "md5-sess")) {
|
| - algorithm_ = ALGORITHM_MD5_SESS;
|
| - } else {
|
| - DVLOG(1) << "Unknown value of algorithm";
|
| - return false; // FAIL -- unsupported value of algorithm.
|
| - }
|
| - } else if (LowerCaseEqualsASCII(name, "qop")) {
|
| - // Parse the comma separated list of qops.
|
| - // auth is the only supported qop, and all other values are ignored.
|
| - HttpUtil::ValuesIterator qop_values(value.begin(), value.end(), ',');
|
| - qop_ = QOP_UNSPECIFIED;
|
| - while (qop_values.GetNext()) {
|
| - if (LowerCaseEqualsASCII(qop_values.value(), "auth")) {
|
| - qop_ = QOP_AUTH;
|
| - break;
|
| - }
|
| - }
|
| - } else {
|
| - DVLOG(1) << "Skipping unrecognized digest property";
|
| - // TODO(eroman): perhaps we should fail instead of silently skipping?
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -// static
|
| -std::string HttpAuthHandlerDigest::QopToString(QualityOfProtection qop) {
|
| - switch (qop) {
|
| - case QOP_UNSPECIFIED:
|
| - return std::string();
|
| - case QOP_AUTH:
|
| - return "auth";
|
| - default:
|
| - NOTREACHED();
|
| - return std::string();
|
| - }
|
| -}
|
| -
|
| -// static
|
| -std::string HttpAuthHandlerDigest::AlgorithmToString(
|
| - DigestAlgorithm algorithm) {
|
| - switch (algorithm) {
|
| - case ALGORITHM_UNSPECIFIED:
|
| - return std::string();
|
| - case ALGORITHM_MD5:
|
| - return "MD5";
|
| - case ALGORITHM_MD5_SESS:
|
| - return "MD5-sess";
|
| - default:
|
| - NOTREACHED();
|
| - return std::string();
|
| - }
|
| -}
|
| -
|
| -void HttpAuthHandlerDigest::GetRequestMethodAndPath(
|
| - const HttpRequestInfo* request,
|
| - std::string* method,
|
| - std::string* path) const {
|
| - DCHECK(request);
|
| -
|
| - const GURL& url = request->url;
|
| -
|
| - if (target_ == HttpAuth::AUTH_PROXY &&
|
| - (url.SchemeIs("https") || url.SchemeIsWSOrWSS())) {
|
| - *method = "CONNECT";
|
| - *path = GetHostAndPort(url);
|
| - } else {
|
| - *method = request->method;
|
| - *path = HttpUtil::PathForRequest(url);
|
| - }
|
| -}
|
| -
|
| -std::string HttpAuthHandlerDigest::AssembleResponseDigest(
|
| - const std::string& method,
|
| - const std::string& path,
|
| - const AuthCredentials& credentials,
|
| - const std::string& cnonce,
|
| - const std::string& nc) const {
|
| - // ha1 = MD5(A1)
|
| - // TODO(eroman): is this the right encoding?
|
| - std::string ha1 = base::MD5String(base::UTF16ToUTF8(credentials.username()) +
|
| - ":" + original_realm_ + ":" +
|
| - base::UTF16ToUTF8(credentials.password()));
|
| - if (algorithm_ == HttpAuthHandlerDigest::ALGORITHM_MD5_SESS)
|
| - ha1 = base::MD5String(ha1 + ":" + nonce_ + ":" + cnonce);
|
| -
|
| - // ha2 = MD5(A2)
|
| - // TODO(eroman): need to add MD5(req-entity-body) for qop=auth-int.
|
| - std::string ha2 = base::MD5String(method + ":" + path);
|
| -
|
| - std::string nc_part;
|
| - if (qop_ != HttpAuthHandlerDigest::QOP_UNSPECIFIED) {
|
| - nc_part = nc + ":" + cnonce + ":" + QopToString(qop_) + ":";
|
| - }
|
| -
|
| - return base::MD5String(ha1 + ":" + nonce_ + ":" + nc_part + ha2);
|
| -}
|
| -
|
| -std::string HttpAuthHandlerDigest::AssembleCredentials(
|
| - const std::string& method,
|
| - const std::string& path,
|
| - const AuthCredentials& credentials,
|
| - const std::string& cnonce,
|
| - int nonce_count) const {
|
| - // the nonce-count is an 8 digit hex string.
|
| - std::string nc = base::StringPrintf("%08x", nonce_count);
|
| -
|
| - // TODO(eroman): is this the right encoding?
|
| - std::string authorization = (std::string("Digest username=") +
|
| - HttpUtil::Quote(
|
| - base::UTF16ToUTF8(credentials.username())));
|
| - authorization += ", realm=" + HttpUtil::Quote(original_realm_);
|
| - authorization += ", nonce=" + HttpUtil::Quote(nonce_);
|
| - authorization += ", uri=" + HttpUtil::Quote(path);
|
| -
|
| - if (algorithm_ != ALGORITHM_UNSPECIFIED) {
|
| - authorization += ", algorithm=" + AlgorithmToString(algorithm_);
|
| - }
|
| - std::string response = AssembleResponseDigest(method, path, credentials,
|
| - cnonce, nc);
|
| - // No need to call HttpUtil::Quote() as the response digest cannot contain
|
| - // any characters needing to be escaped.
|
| - authorization += ", response=\"" + response + "\"";
|
| -
|
| - if (!opaque_.empty()) {
|
| - authorization += ", opaque=" + HttpUtil::Quote(opaque_);
|
| - }
|
| - if (qop_ != QOP_UNSPECIFIED) {
|
| - // TODO(eroman): Supposedly IIS server requires quotes surrounding qop.
|
| - authorization += ", qop=" + QopToString(qop_);
|
| - authorization += ", nc=" + nc;
|
| - authorization += ", cnonce=" + HttpUtil::Quote(cnonce);
|
| - }
|
| -
|
| - return authorization;
|
| -}
|
| -
|
| -} // namespace net
|
|
|