1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_auth_request_handler.h"
8 #include "base/command_line.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/strings/string_split.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/time/time.h"
14 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_protocol.h"
15 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
16 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
17 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
18 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
19 #include "components/data_reduction_proxy/core/common/version.h"
20 #include "crypto/random.h"
21 #include "net/base/host_port_pair.h"
22 #include "net/proxy/proxy_server.h"
23 #include "net/url_request/url_request.h"
26 #if !defined(OS_ANDROID) && !defined(OS_IOS)
27 #include "google_apis/google_api_keys.h"
30 namespace data_reduction_proxy {
32 // The empty version for the authentication protocol. Currently used by
34 #if defined(OS_ANDROID)
35 const char kAndroidWebViewProtocolVersion[] = "";
38 #define CLIENT_ENUM(name, str_value) \
39 case name: return str_value;
40 const char* GetString(Client client) {
50 bool DataReductionProxyAuthRequestHandler::IsKeySetOnCommandLine() {
51 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
52 return command_line.HasSwitch(
53 data_reduction_proxy::switches::kDataReductionProxyKey);
56 DataReductionProxyAuthRequestHandler::DataReductionProxyAuthRequestHandler(
58 DataReductionProxyParams* params,
59 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner)
60 : client_(GetString(client)),
61 data_reduction_proxy_params_(params),
62 network_task_runner_(network_task_runner) {
63 GetChromiumBuildAndPatch(ChromiumVersion(), &build_number_, &patch_number_);
67 DataReductionProxyAuthRequestHandler::DataReductionProxyAuthRequestHandler(
69 const std::string& version,
70 DataReductionProxyParams* params,
71 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner)
72 : client_(GetString(client)),
73 data_reduction_proxy_params_(params),
74 network_task_runner_(network_task_runner) {
75 GetChromiumBuildAndPatch(version, &build_number_, &patch_number_);
79 std::string DataReductionProxyAuthRequestHandler::ChromiumVersion() const {
80 #if defined(PRODUCT_VERSION)
81 return PRODUCT_VERSION;
88 void DataReductionProxyAuthRequestHandler::GetChromiumBuildAndPatch(
89 const std::string& version,
91 std::string* patch) const {
92 std::vector<std::string> version_parts;
93 base::SplitString(version, '.', &version_parts);
94 if (version_parts.size() != 4)
96 *build = version_parts[2];
97 *patch = version_parts[3];
100 void DataReductionProxyAuthRequestHandler::Init() {
101 InitAuthentication(GetDefaultKey());
105 DataReductionProxyAuthRequestHandler::~DataReductionProxyAuthRequestHandler() {
109 base::string16 DataReductionProxyAuthRequestHandler::AuthHashForSalt(
111 const std::string& key) {
112 std::string salted_key =
113 base::StringPrintf("%lld%s%lld",
114 static_cast<long long>(salt),
116 static_cast<long long>(salt));
117 return base::UTF8ToUTF16(base::MD5String(salted_key));
122 base::Time DataReductionProxyAuthRequestHandler::Now() const {
123 return base::Time::Now();
126 void DataReductionProxyAuthRequestHandler::RandBytes(
127 void* output, size_t length) {
128 crypto::RandBytes(output, length);
131 void DataReductionProxyAuthRequestHandler::MaybeAddRequestHeader(
132 net::URLRequest* request,
133 const net::ProxyServer& proxy_server,
134 net::HttpRequestHeaders* request_headers) {
135 DCHECK(network_task_runner_->BelongsToCurrentThread());
136 if (!proxy_server.is_valid())
138 if (proxy_server.is_direct())
140 MaybeAddRequestHeaderImpl(proxy_server.host_port_pair(),
145 void DataReductionProxyAuthRequestHandler::MaybeAddProxyTunnelRequestHandler(
146 const net::HostPortPair& proxy_server,
147 net::HttpRequestHeaders* request_headers) {
148 DCHECK(network_task_runner_->BelongsToCurrentThread());
149 MaybeAddRequestHeaderImpl(proxy_server, true, request_headers);
152 void DataReductionProxyAuthRequestHandler::AddAuthorizationHeader(
153 net::HttpRequestHeaders* headers) {
154 base::Time now = Now();
155 if (now - last_update_time_ > base::TimeDelta::FromHours(24)) {
156 last_update_time_ = now;
157 ComputeCredentials(last_update_time_, &session_, &credentials_);
159 const char kChromeProxyHeader[] = "Chrome-Proxy";
160 std::string header_value;
161 if (headers->HasHeader(kChromeProxyHeader)) {
162 headers->GetHeader(kChromeProxyHeader, &header_value);
163 headers->RemoveHeader(kChromeProxyHeader);
164 header_value += ", ";
167 "ps=" + session_ + ", sid=" + credentials_;
168 if (!build_number_.empty() && !patch_number_.empty())
169 header_value += ", b=" + build_number_ + ", p=" + patch_number_;
170 if (!client_.empty())
171 header_value += ", c=" + client_;
172 headers->SetHeader(kChromeProxyHeader, header_value);
175 void DataReductionProxyAuthRequestHandler::ComputeCredentials(
176 const base::Time& now,
177 std::string* session,
178 std::string* credentials) {
182 (now - base::Time::UnixEpoch()).InMilliseconds() / 1000;
185 RandBytes(rand, 3 * sizeof(rand[0]));
186 *session = base::StringPrintf("%lld-%u-%u-%u",
187 static_cast<long long>(timestamp),
191 *credentials = base::UTF16ToUTF8(AuthHashForSalt(timestamp, key_));
193 DVLOG(1) << "session: [" << *session << "] "
194 << "password: [" << *credentials << "]";
197 void DataReductionProxyAuthRequestHandler::InitAuthentication(
198 const std::string& key) {
199 if (!network_task_runner_->BelongsToCurrentThread()) {
200 network_task_runner_->PostTask(
202 base::Bind(&DataReductionProxyAuthRequestHandler::InitAuthentication,
203 base::Unretained(this),
212 last_update_time_ = Now();
213 ComputeCredentials(last_update_time_, &session_, &credentials_);
216 std::string DataReductionProxyAuthRequestHandler::GetDefaultKey() const {
217 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
219 command_line.GetSwitchValueASCII(switches::kDataReductionProxyKey);
220 // Android and iOS get the default key from a preprocessor constant. All other
221 // platforms get the key from google_apis
222 #if defined(OS_ANDROID) || defined(OS_IOS)
223 #if defined(SPDY_PROXY_AUTH_VALUE)
225 key = SPDY_PROXY_AUTH_VALUE;
229 key = google_apis::GetSpdyProxyAuthValue();
231 #endif // defined(OS_ANDROID) || defined(OS_IOS)
235 void DataReductionProxyAuthRequestHandler::MaybeAddRequestHeaderImpl(
236 const net::HostPortPair& proxy_server,
238 net::HttpRequestHeaders* request_headers) {
239 if (proxy_server.IsEmpty())
241 if (data_reduction_proxy_params_ &&
242 data_reduction_proxy_params_->IsDataReductionProxy(proxy_server, NULL) &&
243 net::HostPortPair::FromURL(
244 data_reduction_proxy_params_->ssl_origin()).Equals(
245 proxy_server) == expect_ssl) {
246 AddAuthorizationHeader(request_headers);
250 } // namespace data_reduction_proxy