| 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
|
| index 7c5526c772fe079f77dab601538ee53bfae6262f..e8cb819cef70ec390e5aebc5a3fefd7187d9eeb9 100644
|
| --- a/net/http/http_auth_handler_digest.cc
|
| +++ b/net/http/http_auth_handler_digest.cc
|
| @@ -74,46 +74,60 @@ std::string HttpAuthHandlerDigest::FixedNonceGenerator::GenerateNonce() const {
|
| return nonce_;
|
| }
|
|
|
| -// static
|
| -std::string HttpAuthHandlerDigest::QopToString(QualityOfProtection qop) {
|
| - switch (qop) {
|
| - case QOP_UNSPECIFIED:
|
| - return "";
|
| - case QOP_AUTH:
|
| - return "auth";
|
| - default:
|
| - NOTREACHED();
|
| - return "";
|
| - }
|
| +HttpAuthHandlerDigest::Factory::Factory()
|
| + : nonce_generator_(new DynamicNonceGenerator()) {
|
| }
|
|
|
| -// static
|
| -std::string HttpAuthHandlerDigest::AlgorithmToString(
|
| - DigestAlgorithm algorithm) {
|
| - switch (algorithm) {
|
| - case ALGORITHM_UNSPECIFIED:
|
| - return "";
|
| - case ALGORITHM_MD5:
|
| - return "MD5";
|
| - case ALGORITHM_MD5_SESS:
|
| - return "MD5-sess";
|
| - default:
|
| - NOTREACHED();
|
| - return "";
|
| - }
|
| +HttpAuthHandlerDigest::Factory::~Factory() {
|
| }
|
|
|
| -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_);
|
| +void HttpAuthHandlerDigest::Factory::set_nonce_generator(
|
| + const NonceGenerator* nonce_generator) {
|
| + nonce_generator_.reset(nonce_generator);
|
| }
|
|
|
| -HttpAuthHandlerDigest::~HttpAuthHandlerDigest() {
|
| +int HttpAuthHandlerDigest::Factory::CreateAuthHandler(
|
| + HttpAuth::ChallengeTokenizer* 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(
|
| + HttpAuth::ChallengeTokenizer* 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.
|
| + while (parameters.GetNext()) {
|
| + if (!LowerCaseEqualsASCII(parameters.name(), "stale"))
|
| + continue;
|
| + if (LowerCaseEqualsASCII(parameters.value(), "true"))
|
| + return HttpAuth::AUTHORIZATION_RESULT_STALE;
|
| + }
|
| +
|
| + return HttpAuth::AUTHORIZATION_RESULT_REJECT;
|
| +}
|
| +
|
| +bool HttpAuthHandlerDigest::Init(HttpAuth::ChallengeTokenizer* challenge) {
|
| + return ParseChallenge(challenge);
|
| }
|
|
|
| int HttpAuthHandlerDigest::GenerateAuthTokenImpl(
|
| @@ -138,112 +152,17 @@ int HttpAuthHandlerDigest::GenerateAuthTokenImpl(
|
| return OK;
|
| }
|
|
|
| -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")) {
|
| - *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 string16& username,
|
| - const string16& password,
|
| - const std::string& cnonce,
|
| - const std::string& nc) const {
|
| - // ha1 = MD5(A1)
|
| - // TODO(eroman): is this the right encoding?
|
| - std::string ha1 = MD5String(UTF16ToUTF8(username) + ":" + realm_ + ":" +
|
| - UTF16ToUTF8(password));
|
| - if (algorithm_ == HttpAuthHandlerDigest::ALGORITHM_MD5_SESS)
|
| - ha1 = MD5String(ha1 + ":" + nonce_ + ":" + cnonce);
|
| -
|
| - // ha2 = MD5(A2)
|
| - // TODO(eroman): need to add MD5(req-entity-body) for qop=auth-int.
|
| - std::string ha2 = MD5String(method + ":" + path);
|
| -
|
| - std::string nc_part;
|
| - if (qop_ != HttpAuthHandlerDigest::QOP_UNSPECIFIED) {
|
| - nc_part = nc + ":" + cnonce + ":" + QopToString(qop_) + ":";
|
| - }
|
| -
|
| - return MD5String(ha1 + ":" + nonce_ + ":" + nc_part + ha2);
|
| -}
|
| -
|
| -std::string HttpAuthHandlerDigest::AssembleCredentials(
|
| - const std::string& method,
|
| - const std::string& path,
|
| - const string16& username,
|
| - const string16& password,
|
| - 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(UTF16ToUTF8(username)));
|
| - authorization += ", realm=" + HttpUtil::Quote(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, username,
|
| - password, 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;
|
| -}
|
| -
|
| -bool HttpAuthHandlerDigest::Init(HttpAuth::ChallengeTokenizer* challenge) {
|
| - return ParseChallenge(challenge);
|
| +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_);
|
| }
|
|
|
| -HttpAuth::AuthorizationResult HttpAuthHandlerDigest::HandleAnotherChallenge(
|
| - HttpAuth::ChallengeTokenizer* 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.
|
| - while (parameters.GetNext()) {
|
| - if (!LowerCaseEqualsASCII(parameters.name(), "stale"))
|
| - continue;
|
| - if (LowerCaseEqualsASCII(parameters.value(), "true"))
|
| - return HttpAuth::AUTHORIZATION_RESULT_STALE;
|
| - }
|
| -
|
| - return HttpAuth::AUTHORIZATION_RESULT_REJECT;
|
| +HttpAuthHandlerDigest::~HttpAuthHandlerDigest() {
|
| }
|
|
|
| // The digest challenge header looks like:
|
| @@ -342,34 +261,115 @@ bool HttpAuthHandlerDigest::ParseChallengeProperty(const std::string& name,
|
| return true;
|
| }
|
|
|
| -HttpAuthHandlerDigest::Factory::Factory()
|
| - : nonce_generator_(new DynamicNonceGenerator()) {
|
| +// static
|
| +std::string HttpAuthHandlerDigest::QopToString(QualityOfProtection qop) {
|
| + switch (qop) {
|
| + case QOP_UNSPECIFIED:
|
| + return "";
|
| + case QOP_AUTH:
|
| + return "auth";
|
| + default:
|
| + NOTREACHED();
|
| + return "";
|
| + }
|
| }
|
|
|
| -HttpAuthHandlerDigest::Factory::~Factory() {
|
| +// static
|
| +std::string HttpAuthHandlerDigest::AlgorithmToString(
|
| + DigestAlgorithm algorithm) {
|
| + switch (algorithm) {
|
| + case ALGORITHM_UNSPECIFIED:
|
| + return "";
|
| + case ALGORITHM_MD5:
|
| + return "MD5";
|
| + case ALGORITHM_MD5_SESS:
|
| + return "MD5-sess";
|
| + default:
|
| + NOTREACHED();
|
| + return "";
|
| + }
|
| }
|
|
|
| -void HttpAuthHandlerDigest::Factory::set_nonce_generator(
|
| - const NonceGenerator* nonce_generator) {
|
| - nonce_generator_.reset(nonce_generator);
|
| +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")) {
|
| + *method = "CONNECT";
|
| + *path = GetHostAndPort(url);
|
| + } else {
|
| + *method = request->method;
|
| + *path = HttpUtil::PathForRequest(url);
|
| + }
|
| }
|
|
|
| -int HttpAuthHandlerDigest::Factory::CreateAuthHandler(
|
| - HttpAuth::ChallengeTokenizer* 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;
|
| +std::string HttpAuthHandlerDigest::AssembleResponseDigest(
|
| + const std::string& method,
|
| + const std::string& path,
|
| + const string16& username,
|
| + const string16& password,
|
| + const std::string& cnonce,
|
| + const std::string& nc) const {
|
| + // ha1 = MD5(A1)
|
| + // TODO(eroman): is this the right encoding?
|
| + std::string ha1 = MD5String(UTF16ToUTF8(username) + ":" + realm_ + ":" +
|
| + UTF16ToUTF8(password));
|
| + if (algorithm_ == HttpAuthHandlerDigest::ALGORITHM_MD5_SESS)
|
| + ha1 = MD5String(ha1 + ":" + nonce_ + ":" + cnonce);
|
| +
|
| + // ha2 = MD5(A2)
|
| + // TODO(eroman): need to add MD5(req-entity-body) for qop=auth-int.
|
| + std::string ha2 = MD5String(method + ":" + path);
|
| +
|
| + std::string nc_part;
|
| + if (qop_ != HttpAuthHandlerDigest::QOP_UNSPECIFIED) {
|
| + nc_part = nc + ":" + cnonce + ":" + QopToString(qop_) + ":";
|
| + }
|
| +
|
| + return MD5String(ha1 + ":" + nonce_ + ":" + nc_part + ha2);
|
| +}
|
| +
|
| +std::string HttpAuthHandlerDigest::AssembleCredentials(
|
| + const std::string& method,
|
| + const std::string& path,
|
| + const string16& username,
|
| + const string16& password,
|
| + 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(UTF16ToUTF8(username)));
|
| + authorization += ", realm=" + HttpUtil::Quote(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, username,
|
| + password, 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
|
|
|