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. 4 5 #include "components/data_reduction_proxy/browser/data_reduction_proxy_auth_request_handler.h" 6 7 #include "base/bind.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" 24 #include "url/gurl.h" 25 26 namespace data_reduction_proxy { 27 28 // The empty version for the authentication protocol. Currently used by 29 // Android webview. 30 #if defined(OS_ANDROID) 31 const char kAndroidWebViewProtocolVersion[] = ""; 32 #endif 33 34 // The clients supported by the data reduction proxy. 35 const char kClientAndroidWebview[] = "webview"; 36 const char kClientChromeAndroid[] = "android"; 37 const char kClientChromeIOS[] = "ios"; 38 39 // static 40 bool DataReductionProxyAuthRequestHandler::IsKeySetOnCommandLine() { 41 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 42 return command_line.HasSwitch( 43 data_reduction_proxy::switches::kDataReductionProxyKey); 44 } 45 46 DataReductionProxyAuthRequestHandler::DataReductionProxyAuthRequestHandler( 47 const std::string& client, 48 DataReductionProxyParams* params, 49 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner) 50 : client_(client), 51 data_reduction_proxy_params_(params), 52 network_task_runner_(network_task_runner) { 53 GetChromiumBuildAndPatch(ChromiumVersion(), &build_number_, &patch_number_); 54 Init(); 55 } 56 57 DataReductionProxyAuthRequestHandler::DataReductionProxyAuthRequestHandler( 58 const std::string& client, 59 const std::string& version, 60 DataReductionProxyParams* params, 61 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner) 62 : client_(client), 63 data_reduction_proxy_params_(params), 64 network_task_runner_(network_task_runner) { 65 GetChromiumBuildAndPatch(version, &build_number_, &patch_number_); 66 Init(); 67 } 68 69 std::string DataReductionProxyAuthRequestHandler::ChromiumVersion() const { 70 #if defined(PRODUCT_VERSION) 71 return PRODUCT_VERSION; 72 #else 73 return std::string(); 74 #endif 75 } 76 77 78 void DataReductionProxyAuthRequestHandler::GetChromiumBuildAndPatch( 79 const std::string& version, 80 std::string* build, 81 std::string* patch) const { 82 std::vector<std::string> version_parts; 83 base::SplitString(version, '.', &version_parts); 84 if (version_parts.size() != 4) 85 return; 86 *build = version_parts[2]; 87 *patch = version_parts[3]; 88 } 89 90 void DataReductionProxyAuthRequestHandler::Init() { 91 InitAuthentication(GetDefaultKey()); 92 } 93 94 95 DataReductionProxyAuthRequestHandler::~DataReductionProxyAuthRequestHandler() { 96 } 97 98 // static 99 base::string16 DataReductionProxyAuthRequestHandler::AuthHashForSalt( 100 int64 salt, 101 const std::string& key) { 102 std::string salted_key = 103 base::StringPrintf("%lld%s%lld", 104 static_cast<long long>(salt), 105 key.c_str(), 106 static_cast<long long>(salt)); 107 return base::UTF8ToUTF16(base::MD5String(salted_key)); 108 } 109 110 111 112 base::Time DataReductionProxyAuthRequestHandler::Now() const { 113 return base::Time::Now(); 114 } 115 116 void DataReductionProxyAuthRequestHandler::RandBytes( 117 void* output, size_t length) { 118 crypto::RandBytes(output, length); 119 } 120 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()) 127 return; 128 if (proxy_server.is_direct()) 129 return; 130 MaybeAddRequestHeaderImpl(proxy_server.host_port_pair(), 131 false, 132 request_headers); 133 } 134 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); 140 } 141 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_); 148 } 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 += ", "; 155 } 156 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); 163 } 164 165 void DataReductionProxyAuthRequestHandler::ComputeCredentials( 166 const base::Time& now, 167 std::string* session, 168 std::string* credentials) { 169 DCHECK(session); 170 DCHECK(credentials); 171 int64 timestamp = 172 (now - base::Time::UnixEpoch()).InMilliseconds() / 1000; 173 174 int32 rand[3]; 175 RandBytes(rand, 3 * sizeof(rand[0])); 176 *session = base::StringPrintf("%lld-%u-%u-%u", 177 static_cast<long long>(timestamp), 178 rand[0], 179 rand[1], 180 rand[2]); 181 *credentials = base::UTF16ToUTF8(AuthHashForSalt(timestamp, key_)); 182 183 DVLOG(1) << "session: [" << *session << "] " 184 << "password: [" << *credentials << "]"; 185 } 186 187 void DataReductionProxyAuthRequestHandler::InitAuthentication( 188 const std::string& key) { 189 if (!network_task_runner_->BelongsToCurrentThread()) { 190 network_task_runner_->PostTask( 191 FROM_HERE, 192 base::Bind(&DataReductionProxyAuthRequestHandler::InitAuthentication, 193 base::Unretained(this), 194 key)); 195 return; 196 } 197 198 if (key.empty()) 199 return; 200 201 key_ = key; 202 last_update_time_ = Now(); 203 ComputeCredentials(last_update_time_, &session_, &credentials_); 204 } 205 206 std::string DataReductionProxyAuthRequestHandler::GetDefaultKey() const { 207 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 208 std::string key = 209 command_line.GetSwitchValueASCII(switches::kDataReductionProxyKey); 210 #if defined(SPDY_PROXY_AUTH_VALUE) 211 if (key.empty()) 212 key = SPDY_PROXY_AUTH_VALUE; 213 #endif 214 return key; 215 } 216 217 void DataReductionProxyAuthRequestHandler::MaybeAddRequestHeaderImpl( 218 const net::HostPortPair& proxy_server, 219 bool expect_ssl, 220 net::HttpRequestHeaders* request_headers) { 221 if (proxy_server.IsEmpty()) 222 return; 223 if (data_reduction_proxy_params_ && 224 data_reduction_proxy_params_->IsDataReductionProxy(proxy_server, NULL) && 225 net::HostPortPair::FromURL( 226 data_reduction_proxy_params_->ssl_origin()).Equals( 227 proxy_server) == expect_ssl) { 228 AddAuthorizationHeader(request_headers); 229 } 230 } 231 232 } // namespace data_reduction_proxy 233