blob: 12b91964064a8c4dbecbef1ea94b11e0d2a1c7b7 [file] [log] [blame]
// Copyright 2014 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 "components/data_reduction_proxy/browser/data_reduction_proxy_auth_request_handler.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "components/data_reduction_proxy/browser/data_reduction_proxy_params.h"
#include "components/data_reduction_proxy/browser/data_reduction_proxy_protocol.h"
#include "components/data_reduction_proxy/browser/data_reduction_proxy_settings.h"
#include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
#include "components/data_reduction_proxy/common/data_reduction_proxy_switches.h"
#include "components/data_reduction_proxy/common/version.h"
#include "crypto/random.h"
#include "net/proxy/proxy_server.h"
#include "net/url_request/url_request.h"
#include "url/gurl.h"
namespace data_reduction_proxy {
// The empty version for the authentication protocol. Currently used by
// Android webview.
#if defined(OS_ANDROID)
const char kAndroidWebViewProtocolVersion[] = "";
#endif
// The clients supported by the data reduction proxy.
const char kClientAndroidWebview[] = "webview";
const char kClientChromeAndroid[] = "android";
const char kClientChromeIOS[] = "ios";
// static
bool DataReductionProxyAuthRequestHandler::IsKeySetOnCommandLine() {
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
return command_line.HasSwitch(
data_reduction_proxy::switches::kDataReductionProxyKey);
}
DataReductionProxyAuthRequestHandler::DataReductionProxyAuthRequestHandler(
const std::string& client,
DataReductionProxyParams* params,
scoped_refptr<base::SingleThreadTaskRunner> network_task_runner)
: client_(client),
data_reduction_proxy_params_(params),
network_task_runner_(network_task_runner) {
GetChromiumBuildAndPatch(ChromiumVersion(), &build_number_, &patch_number_);
Init();
}
DataReductionProxyAuthRequestHandler::DataReductionProxyAuthRequestHandler(
const std::string& client,
const std::string& version,
DataReductionProxyParams* params,
scoped_refptr<base::SingleThreadTaskRunner> network_task_runner)
: client_(client),
data_reduction_proxy_params_(params),
network_task_runner_(network_task_runner) {
GetChromiumBuildAndPatch(version, &build_number_, &patch_number_);
Init();
}
std::string DataReductionProxyAuthRequestHandler::ChromiumVersion() const {
#if defined(PRODUCT_VERSION)
return PRODUCT_VERSION;
#else
return std::string();
#endif
}
void DataReductionProxyAuthRequestHandler::GetChromiumBuildAndPatch(
const std::string& version,
std::string* build,
std::string* patch) const {
std::vector<std::string> version_parts;
base::SplitString(version, '.', &version_parts);
if (version_parts.size() != 4)
return;
*build = version_parts[2];
*patch = version_parts[3];
}
void DataReductionProxyAuthRequestHandler::Init() {
InitAuthenticationOnUI(GetDefaultKey());
}
DataReductionProxyAuthRequestHandler::~DataReductionProxyAuthRequestHandler() {
}
// static
base::string16 DataReductionProxyAuthRequestHandler::AuthHashForSalt(
int64 salt,
const std::string& key) {
std::string salted_key =
base::StringPrintf("%lld%s%lld",
static_cast<long long>(salt),
key.c_str(),
static_cast<long long>(salt));
return base::UTF8ToUTF16(base::MD5String(salted_key));
}
base::Time DataReductionProxyAuthRequestHandler::Now() const {
return base::Time::Now();
}
void DataReductionProxyAuthRequestHandler::RandBytes(
void* output, size_t length) {
crypto::RandBytes(output, length);
}
void DataReductionProxyAuthRequestHandler::MaybeAddRequestHeader(
net::URLRequest* request,
const net::ProxyServer& proxy_server,
net::HttpRequestHeaders* request_headers) {
DCHECK(network_task_runner_->BelongsToCurrentThread());
if (!proxy_server.is_valid())
return;
if (data_reduction_proxy_params_ &&
data_reduction_proxy_params_->IsDataReductionProxy(
proxy_server.host_port_pair(), NULL)) {
AddAuthorizationHeader(request_headers);
}
}
void DataReductionProxyAuthRequestHandler::AddAuthorizationHeader(
net::HttpRequestHeaders* headers) {
base::Time now = Now();
if (now - last_update_time_ > base::TimeDelta::FromHours(24)) {
last_update_time_ = now;
ComputeCredentials(last_update_time_, &session_, &credentials_);
}
const char kChromeProxyHeader[] = "Chrome-Proxy";
std::string header_value;
if (headers->HasHeader(kChromeProxyHeader)) {
headers->GetHeader(kChromeProxyHeader, &header_value);
headers->RemoveHeader(kChromeProxyHeader);
header_value += ", ";
}
header_value +=
"ps=" + session_ + ", sid=" + credentials_;
if (!build_number_.empty() && !patch_number_.empty())
header_value += ", b=" + build_number_ + ", p=" + patch_number_;
if (!client_.empty())
header_value += ", c=" + client_;
headers->SetHeader(kChromeProxyHeader, header_value);
}
void DataReductionProxyAuthRequestHandler::InitAuthenticationOnUI(
const std::string& key) {
network_task_runner_->PostTask(FROM_HERE, base::Bind(
&DataReductionProxyAuthRequestHandler::InitAuthentication,
base::Unretained(this),
key));
}
void DataReductionProxyAuthRequestHandler::ComputeCredentials(
const base::Time& now,
std::string* session,
std::string* credentials) {
DCHECK(session);
DCHECK(credentials);
int64 timestamp =
(now - base::Time::UnixEpoch()).InMilliseconds() / 1000;
int32 rand[3];
RandBytes(rand, 3 * sizeof(rand[0]));
*session = base::StringPrintf("%lld-%u-%u-%u",
static_cast<long long>(timestamp),
rand[0],
rand[1],
rand[2]);
*credentials = base::UTF16ToUTF8(AuthHashForSalt(timestamp, key_));
DVLOG(1) << "session: [" << *session << "] "
<< "password: [" << *credentials << "]";
}
void DataReductionProxyAuthRequestHandler::InitAuthentication(
const std::string& key) {
DCHECK(network_task_runner_->BelongsToCurrentThread());
key_ = key;
last_update_time_ = Now();
ComputeCredentials(last_update_time_, &session_, &credentials_);
}
void DataReductionProxyAuthRequestHandler::SetKeyOnUI(const std::string& key) {
if (!key.empty())
InitAuthenticationOnUI(key);
}
std::string DataReductionProxyAuthRequestHandler::GetDefaultKey() const {
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
std::string key =
command_line.GetSwitchValueASCII(switches::kDataReductionProxyKey);
#if defined(SPDY_PROXY_AUTH_VALUE)
if (key.empty())
key = SPDY_PROXY_AUTH_VALUE;
#endif
return key;
}
} // namespace data_reduction_proxy