Home | History | Annotate | Download | only in browser
      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