This source file includes following definitions.
- GenerateNonce
- GenerateNonce
- set_nonce_generator
- CreateAuthHandler
- HandleAnotherChallenge
- Init
- GenerateAuthTokenImpl
- nonce_generator_
- ParseChallenge
- ParseChallengeProperty
- QopToString
- AlgorithmToString
- GetRequestMethodAndPath
- AssembleResponseDigest
- AssembleCredentials
#include "net/http/http_auth_handler_digest.h"
#include <string>
#include "base/i18n/icu_string_conversions.h"
#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_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 {
HttpAuthHandlerDigest::NonceGenerator::NonceGenerator() {
}
HttpAuthHandlerDigest::NonceGenerator::~NonceGenerator() {
}
HttpAuthHandlerDigest::DynamicNonceGenerator::DynamicNonceGenerator() {
}
std::string HttpAuthHandlerDigest::DynamicNonceGenerator::GenerateNonce()
const {
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) {
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) {
if (!LowerCaseEqualsASCII(challenge->scheme(), "digest"))
return HttpAuth::AUTHORIZATION_RESULT_INVALID;
HttpUtil::NameValuePairsIterator parameters = challenge->param_pairs();
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) {
std::string cnonce = nonce_generator_->GenerateNonce();
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() {
}
bool HttpAuthHandlerDigest::ParseChallenge(
HttpAuthChallengeTokenizer* challenge) {
auth_scheme_ = HttpAuth::AUTH_SCHEME_DIGEST;
score_ = 2;
properties_ = ENCRYPTS_IDENTITY;
stale_ = false;
algorithm_ = ALGORITHM_UNSPECIFIED;
qop_ = QOP_UNSPECIFIED;
realm_ = original_realm_ = nonce_ = domain_ = opaque_ = std::string();
if (!LowerCaseEqualsASCII(challenge->scheme(), "digest"))
return false;
HttpUtil::NameValuePairsIterator parameters = challenge->param_pairs();
while (parameters.GetNext()) {
if (!ParseChallengeProperty(parameters.name(),
parameters.value()))
return false;
}
if (!parameters.valid())
return false;
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 (!base::ConvertToUtf8AndNormalize(value, base::kCodepageLatin1, &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")) {
stale_ = LowerCaseEqualsASCII(value, "true");
} else if (LowerCaseEqualsASCII(name, "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;
}
} else if (LowerCaseEqualsASCII(name, "qop")) {
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";
}
return true;
}
std::string HttpAuthHandlerDigest::QopToString(QualityOfProtection qop) {
switch (qop) {
case QOP_UNSPECIFIED:
return std::string();
case QOP_AUTH:
return "auth";
default:
NOTREACHED();
return std::string();
}
}
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 {
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);
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 {
std::string nc = base::StringPrintf("%08x", nonce_count);
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);
authorization += ", response=\"" + response + "\"";
if (!opaque_.empty()) {
authorization += ", opaque=" + HttpUtil::Quote(opaque_);
}
if (qop_ != QOP_UNSPECIFIED) {
authorization += ", qop=" + QopToString(qop_);
authorization += ", nc=" + nc;
authorization += ", cnonce=" + HttpUtil::Quote(cnonce);
}
return authorization;
}
}