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/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/browser/data_reduction_proxy_params.h"
15 #include "components/data_reduction_proxy/browser/data_reduction_proxy_protocol.h"
16 #include "components/data_reduction_proxy/browser/data_reduction_proxy_settings.h"
17 #include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
18 #include "components/data_reduction_proxy/common/data_reduction_proxy_switches.h"
19 #include "components/data_reduction_proxy/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 namespace data_reduction_proxy {
28 // The empty version for the authentication protocol. Currently used by
30 #if defined(OS_ANDROID)
31 const char kAndroidWebViewProtocolVersion[] = "";
34 // The clients supported by the data reduction proxy.
35 const char kClientAndroidWebview[] = "webview";
36 const char kClientChromeAndroid[] = "android";
37 const char kClientChromeIOS[] = "ios";
40 bool DataReductionProxyAuthRequestHandler::IsKeySetOnCommandLine() {
41 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
42 return command_line.HasSwitch(
43 data_reduction_proxy::switches::kDataReductionProxyKey);
46 DataReductionProxyAuthRequestHandler::DataReductionProxyAuthRequestHandler(
47 const std::string& client,
48 DataReductionProxyParams* params,
49 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner)
51 data_reduction_proxy_params_(params),
52 network_task_runner_(network_task_runner) {
53 GetChromiumBuildAndPatch(ChromiumVersion(), &build_number_, &patch_number_);
57 DataReductionProxyAuthRequestHandler::DataReductionProxyAuthRequestHandler(
58 const std::string& client,
59 const std::string& version,
60 DataReductionProxyParams* params,
61 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner)
63 data_reduction_proxy_params_(params),
64 network_task_runner_(network_task_runner) {
65 GetChromiumBuildAndPatch(version, &build_number_, &patch_number_);
69 std::string DataReductionProxyAuthRequestHandler::ChromiumVersion() const {
70 #if defined(PRODUCT_VERSION)
71 return PRODUCT_VERSION;
78 void DataReductionProxyAuthRequestHandler::GetChromiumBuildAndPatch(
79 const std::string& version,
81 std::string* patch) const {
82 std::vector<std::string> version_parts;
83 base::SplitString(version, '.', &version_parts);
84 if (version_parts.size() != 4)
86 *build = version_parts[2];
87 *patch = version_parts[3];
90 void DataReductionProxyAuthRequestHandler::Init() {
91 InitAuthenticationOnUI(GetDefaultKey());
95 DataReductionProxyAuthRequestHandler::~DataReductionProxyAuthRequestHandler() {
99 base::string16 DataReductionProxyAuthRequestHandler::AuthHashForSalt(
101 const std::string& key) {
102 std::string salted_key =
103 base::StringPrintf("%lld%s%lld",
104 static_cast<long long>(salt),
106 static_cast<long long>(salt));
107 return base::UTF8ToUTF16(base::MD5String(salted_key));
112 base::Time DataReductionProxyAuthRequestHandler::Now() const {
113 return base::Time::Now();
116 void DataReductionProxyAuthRequestHandler::RandBytes(
117 void* output, size_t length) {
118 crypto::RandBytes(output, length);
121 void DataReductionProxyAuthRequestHandler::MaybeAddRequestHeader(
122 net::URLRequest* request,
123 const net::ProxyServer& proxy_server,
124 net::HttpRequestHeaders* request_headers) {
125 DCHECK(network_task_runner_->BelongsToCurrentThread());
126 if (!proxy_server.is_valid())
128 if (proxy_server.is_direct())
130 MaybeAddRequestHeaderImpl(proxy_server.host_port_pair(),
135 void DataReductionProxyAuthRequestHandler::MaybeAddProxyTunnelRequestHandler(
136 const net::HostPortPair& proxy_server,
137 net::HttpRequestHeaders* request_headers) {
138 DCHECK(network_task_runner_->BelongsToCurrentThread());
139 MaybeAddRequestHeaderImpl(proxy_server, true, request_headers);
142 void DataReductionProxyAuthRequestHandler::AddAuthorizationHeader(
143 net::HttpRequestHeaders* headers) {
144 base::Time now = Now();
145 if (now - last_update_time_ > base::TimeDelta::FromHours(24)) {
146 last_update_time_ = now;
147 ComputeCredentials(last_update_time_, &session_, &credentials_);
149 const char kChromeProxyHeader[] = "Chrome-Proxy";
150 std::string header_value;
151 if (headers->HasHeader(kChromeProxyHeader)) {
152 headers->GetHeader(kChromeProxyHeader, &header_value);
153 headers->RemoveHeader(kChromeProxyHeader);
154 header_value += ", ";
157 "ps=" + session_ + ", sid=" + credentials_;
158 if (!build_number_.empty() && !patch_number_.empty())
159 header_value += ", b=" + build_number_ + ", p=" + patch_number_;
160 if (!client_.empty())
161 header_value += ", c=" + client_;
162 headers->SetHeader(kChromeProxyHeader, header_value);
165 void DataReductionProxyAuthRequestHandler::InitAuthenticationOnUI(
166 const std::string& key) {
167 network_task_runner_->PostTask(FROM_HERE, base::Bind(
168 &DataReductionProxyAuthRequestHandler::InitAuthentication,
169 base::Unretained(this),
173 void DataReductionProxyAuthRequestHandler::ComputeCredentials(
174 const base::Time& now,
175 std::string* session,
176 std::string* credentials) {
180 (now - base::Time::UnixEpoch()).InMilliseconds() / 1000;
183 RandBytes(rand, 3 * sizeof(rand[0]));
184 *session = base::StringPrintf("%lld-%u-%u-%u",
185 static_cast<long long>(timestamp),
189 *credentials = base::UTF16ToUTF8(AuthHashForSalt(timestamp, key_));
191 DVLOG(1) << "session: [" << *session << "] "
192 << "password: [" << *credentials << "]";
195 void DataReductionProxyAuthRequestHandler::InitAuthentication(
196 const std::string& key) {
197 DCHECK(network_task_runner_->BelongsToCurrentThread());
199 last_update_time_ = Now();
200 ComputeCredentials(last_update_time_, &session_, &credentials_);
203 void DataReductionProxyAuthRequestHandler::SetKeyOnUI(const std::string& key) {
205 InitAuthenticationOnUI(key);
209 std::string DataReductionProxyAuthRequestHandler::GetDefaultKey() const {
210 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
212 command_line.GetSwitchValueASCII(switches::kDataReductionProxyKey);
213 #if defined(SPDY_PROXY_AUTH_VALUE)
215 key = SPDY_PROXY_AUTH_VALUE;
220 void DataReductionProxyAuthRequestHandler::MaybeAddRequestHeaderImpl(
221 const net::HostPortPair& proxy_server,
223 net::HttpRequestHeaders* request_headers) {
224 if (proxy_server.IsEmpty())
226 if (data_reduction_proxy_params_ &&
227 data_reduction_proxy_params_->IsDataReductionProxy(proxy_server, NULL) &&
228 net::HostPortPair::FromURL(
229 data_reduction_proxy_params_->ssl_origin()).Equals(
230 proxy_server) == expect_ssl) {
231 AddAuthorizationHeader(request_headers);
235 } // namespace data_reduction_proxy