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 
      6 #include "components/data_reduction_proxy/browser/data_reduction_proxy_auth_request_handler.h"
      7 
      8 #include "base/md5.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/run_loop.h"
     11 #include "base/strings/string16.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_test_utils.h"
     15 #include "components/data_reduction_proxy/browser/data_reduction_proxy_settings_test_utils.h"
     16 #include "net/base/auth.h"
     17 #include "net/base/host_port_pair.h"
     18 #include "testing/gmock/include/gmock/gmock.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 #include "url/gurl.h"
     21 
     22 namespace {
     23 const char kChromeProxyHeader[] = "chrome-proxy";
     24 const char kOtherProxy[] = "testproxy:17";
     25 
     26 
     27 #if defined(OS_ANDROID)
     28   const char kClient[] = "android";
     29 #elif defined(OS_IOS)
     30   const char kClient[] = "ios";
     31 #else
     32   const char kClient[] = "";
     33 #endif
     34 const char kVersion[] = "0.1.2.3";
     35 const char kExpectedBuild[] = "2";
     36 const char kExpectedPatch[] = "3";
     37 const char kBogusVersion[] = "0.0";
     38 const char kTestKey[] = "test-key";
     39 const char kExpectedCredentials[] = "96bd72ec4a050ba60981743d41787768";
     40 const char kExpectedSession[] = "0-1633771873-1633771873-1633771873";
     41 
     42 const char kTestKey2[] = "test-key2";
     43 const char kExpectedCredentials2[] = "c911fdb402f578787562cf7f00eda972";
     44 const char kExpectedSession2[] = "0-1633771873-1633771873-1633771873";
     45 #if defined(OS_ANDROID)
     46 const char kExpectedHeader2[] =
     47     "ps=0-1633771873-1633771873-1633771873, "
     48     "sid=c911fdb402f578787562cf7f00eda972, b=2, p=3, c=android";
     49 const char kExpectedHeader3[] =
     50     "ps=86401-1633771873-1633771873-1633771873, "
     51     "sid=d7c1c34ef6b90303b01c48a6c1db6419, b=2, p=3, c=android";
     52 const char kExpectedHeader4[] =
     53     "ps=0-1633771873-1633771873-1633771873, "
     54     "sid=c911fdb402f578787562cf7f00eda972, c=android";
     55 #elif defined(OS_IOS)
     56 const char kExpectedHeader2[] =
     57     "ps=0-1633771873-1633771873-1633771873, "
     58     "sid=c911fdb402f578787562cf7f00eda972, b=2, p=3, c=ios";
     59 const char kExpectedHeader3[] =
     60     "ps=86401-1633771873-1633771873-1633771873, "
     61     "sid=d7c1c34ef6b90303b01c48a6c1db6419, b=2, p=3, c=ios";
     62 const char kExpectedHeader4[] =
     63     "ps=0-1633771873-1633771873-1633771873, "
     64     "sid=c911fdb402f578787562cf7f00eda972, c=ios";
     65 #else
     66 const char kExpectedHeader2[] =
     67     "ps=0-1633771873-1633771873-1633771873, "
     68     "sid=c911fdb402f578787562cf7f00eda972, b=2, p=3";
     69 const char kExpectedHeader3[] =
     70     "ps=86401-1633771873-1633771873-1633771873, "
     71     "sid=d7c1c34ef6b90303b01c48a6c1db6419, b=2, p=3";
     72 const char kExpectedHeader4[] =
     73     "ps=0-1633771873-1633771873-1633771873, "
     74     "sid=c911fdb402f578787562cf7f00eda972";
     75 #endif
     76 
     77 const char kDataReductionProxyKey[] = "12345";
     78 }  // namespace
     79 
     80 
     81 namespace data_reduction_proxy {
     82 namespace {
     83 class TestDataReductionProxyAuthRequestHandler
     84     : public DataReductionProxyAuthRequestHandler {
     85  public:
     86   TestDataReductionProxyAuthRequestHandler(
     87       const std::string& client,
     88       const std::string& version,
     89       DataReductionProxyParams* params,
     90       base::MessageLoopProxy* loop_proxy)
     91       : DataReductionProxyAuthRequestHandler(
     92             client, version, params, loop_proxy) {}
     93 
     94   virtual std::string GetDefaultKey() const OVERRIDE {
     95     return kTestKey;
     96   }
     97 
     98   virtual base::Time Now() const OVERRIDE {
     99     return base::Time::UnixEpoch() + now_offset_;
    100   }
    101 
    102   virtual void RandBytes(void* output, size_t length) OVERRIDE {
    103     char* c =  static_cast<char*>(output);
    104     for (size_t i = 0; i < length; ++i) {
    105       c[i] = 'a';
    106     }
    107   }
    108 
    109   // Time after the unix epoch that Now() reports.
    110   void set_offset(const base::TimeDelta& now_offset) {
    111     now_offset_ = now_offset;
    112   }
    113 
    114  private:
    115   base::TimeDelta now_offset_;
    116 };
    117 
    118 }  // namespace
    119 
    120 class DataReductionProxyAuthRequestHandlerTest : public testing::Test {
    121  public:
    122   DataReductionProxyAuthRequestHandlerTest()
    123       : loop_proxy_(base::MessageLoopProxy::current().get()) {
    124   }
    125   // Required for MessageLoopProxy::current().
    126   base::MessageLoopForUI loop_;
    127   base::MessageLoopProxy* loop_proxy_;
    128 };
    129 
    130 TEST_F(DataReductionProxyAuthRequestHandlerTest, AuthorizationOnIO) {
    131   scoped_ptr<TestDataReductionProxyParams> params;
    132   params.reset(
    133       new TestDataReductionProxyParams(
    134           DataReductionProxyParams::kAllowed |
    135           DataReductionProxyParams::kFallbackAllowed |
    136           DataReductionProxyParams::kPromoAllowed,
    137           TestDataReductionProxyParams::HAS_EVERYTHING &
    138           ~TestDataReductionProxyParams::HAS_DEV_ORIGIN &
    139           ~TestDataReductionProxyParams::HAS_DEV_FALLBACK_ORIGIN));
    140   // loop_proxy_ is just the current message loop. This means loop_proxy_
    141   // is the network thread used by DataReductionProxyAuthRequestHandler.
    142   TestDataReductionProxyAuthRequestHandler auth_handler(kClient,
    143                                                         kVersion,
    144                                                         params.get(),
    145                                                         loop_proxy_);
    146   auth_handler.Init();
    147   base::RunLoop().RunUntilIdle();
    148   EXPECT_EQ(auth_handler.client_, kClient);
    149   EXPECT_EQ(kExpectedBuild, auth_handler.build_number_);
    150   EXPECT_EQ(kExpectedPatch, auth_handler.patch_number_);
    151   EXPECT_EQ(auth_handler.key_, kTestKey);
    152   EXPECT_EQ(kExpectedCredentials, auth_handler.credentials_);
    153   EXPECT_EQ(kExpectedSession, auth_handler.session_);
    154 
    155   // Now set a key.
    156   auth_handler.InitAuthentication(kTestKey2);
    157   base::RunLoop().RunUntilIdle();
    158   EXPECT_EQ(kTestKey2, auth_handler.key_);
    159   EXPECT_EQ(kExpectedCredentials2, auth_handler.credentials_);
    160   EXPECT_EQ(kExpectedSession2, auth_handler.session_);
    161 
    162   // Don't write headers if the proxy is invalid.
    163   net::HttpRequestHeaders headers;
    164   auth_handler.MaybeAddRequestHeader(NULL, net::ProxyServer(), &headers);
    165   EXPECT_FALSE(headers.HasHeader(kChromeProxyHeader));
    166 
    167   // Don't write headers with a valid proxy, that's not a data reduction proxy.
    168   auth_handler.MaybeAddRequestHeader(
    169       NULL,
    170       net::ProxyServer::FromURI(kOtherProxy, net::ProxyServer::SCHEME_HTTP),
    171       &headers);
    172   EXPECT_FALSE(headers.HasHeader(kChromeProxyHeader));
    173 
    174   // Don't write headers with a valid data reduction ssl proxy.
    175   auth_handler.MaybeAddRequestHeader(
    176       NULL,
    177       net::ProxyServer::FromURI(
    178           net::HostPortPair::FromURL(
    179               GURL(params->DefaultSSLOrigin())).ToString(),
    180           net::ProxyServer::SCHEME_HTTP),
    181       &headers);
    182   EXPECT_FALSE(headers.HasHeader(kChromeProxyHeader));
    183 
    184   // Write headers with a valid data reduction proxy.
    185   auth_handler.MaybeAddRequestHeader(
    186       NULL,
    187       net::ProxyServer::FromURI(
    188           net::HostPortPair::FromURL(GURL(params->DefaultOrigin())).ToString(),
    189           net::ProxyServer::SCHEME_HTTP),
    190       &headers);
    191   EXPECT_TRUE(headers.HasHeader(kChromeProxyHeader));
    192   std::string header_value;
    193   headers.GetHeader(kChromeProxyHeader, &header_value);
    194   EXPECT_EQ(kExpectedHeader2, header_value);
    195 
    196   // Write headers with a valid data reduction ssl proxy when one is expected.
    197   net::HttpRequestHeaders ssl_headers;
    198   auth_handler.MaybeAddProxyTunnelRequestHandler(
    199       net::HostPortPair::FromURL(GURL(params->DefaultSSLOrigin())),
    200       &ssl_headers);
    201   EXPECT_TRUE(ssl_headers.HasHeader(kChromeProxyHeader));
    202   std::string ssl_header_value;
    203   ssl_headers.GetHeader(kChromeProxyHeader, &ssl_header_value);
    204   EXPECT_EQ(kExpectedHeader2, ssl_header_value);
    205 
    206   // Fast forward 24 hours. The header should be the same.
    207   auth_handler.set_offset(base::TimeDelta::FromSeconds(24 * 60 * 60));
    208   net::HttpRequestHeaders headers2;
    209   // Write headers with a valid data reduction proxy.
    210   auth_handler.MaybeAddRequestHeader(
    211       NULL,
    212       net::ProxyServer::FromURI(
    213           net::HostPortPair::FromURL(GURL(params->DefaultOrigin())).ToString(),
    214           net::ProxyServer::SCHEME_HTTP),
    215       &headers2);
    216   EXPECT_TRUE(headers2.HasHeader(kChromeProxyHeader));
    217   std::string header_value2;
    218   headers2.GetHeader(kChromeProxyHeader, &header_value2);
    219   EXPECT_EQ(kExpectedHeader2, header_value2);
    220 
    221   // Fast forward one more second. The header should be new.
    222   auth_handler.set_offset(base::TimeDelta::FromSeconds(24 * 60 * 60 + 1));
    223   net::HttpRequestHeaders headers3;
    224   // Write headers with a valid data reduction proxy.
    225   auth_handler.MaybeAddRequestHeader(
    226       NULL,
    227       net::ProxyServer::FromURI(
    228           net::HostPortPair::FromURL(GURL(params->DefaultOrigin())).ToString(),
    229           net::ProxyServer::SCHEME_HTTP),
    230       &headers3);
    231   EXPECT_TRUE(headers3.HasHeader(kChromeProxyHeader));
    232   std::string header_value3;
    233   headers3.GetHeader(kChromeProxyHeader, &header_value3);
    234   EXPECT_EQ(kExpectedHeader3, header_value3);
    235 }
    236 
    237 TEST_F(DataReductionProxyAuthRequestHandlerTest, AuthorizationIgnoresEmptyKey) {
    238 scoped_ptr<TestDataReductionProxyParams> params;
    239   params.reset(
    240       new TestDataReductionProxyParams(
    241           DataReductionProxyParams::kAllowed |
    242           DataReductionProxyParams::kFallbackAllowed |
    243           DataReductionProxyParams::kPromoAllowed,
    244           TestDataReductionProxyParams::HAS_EVERYTHING &
    245           ~TestDataReductionProxyParams::HAS_DEV_ORIGIN &
    246           ~TestDataReductionProxyParams::HAS_DEV_FALLBACK_ORIGIN));
    247   // loop_proxy_ is just the current message loop. This means loop_proxy_
    248   // is the network thread used by DataReductionProxyAuthRequestHandler.
    249   TestDataReductionProxyAuthRequestHandler auth_handler(kClient,
    250                                                         kVersion,
    251                                                         params.get(),
    252                                                         loop_proxy_);
    253   auth_handler.Init();
    254   base::RunLoop().RunUntilIdle();
    255   EXPECT_EQ(auth_handler.client_, kClient);
    256   EXPECT_EQ(kExpectedBuild, auth_handler.build_number_);
    257   EXPECT_EQ(kExpectedPatch, auth_handler.patch_number_);
    258   EXPECT_EQ(auth_handler.key_, kTestKey);
    259   EXPECT_EQ(kExpectedCredentials, auth_handler.credentials_);
    260   EXPECT_EQ(kExpectedSession, auth_handler.session_);
    261 
    262   // Now set an empty key. The auth handler should ignore that, and the key
    263   // remains |kTestKey|.
    264   auth_handler.InitAuthentication("");
    265   base::RunLoop().RunUntilIdle();
    266   EXPECT_EQ(auth_handler.key_, kTestKey);
    267   EXPECT_EQ(kExpectedCredentials, auth_handler.credentials_);
    268   EXPECT_EQ(kExpectedSession, auth_handler.session_);
    269 }
    270 
    271 TEST_F(DataReductionProxyAuthRequestHandlerTest, AuthorizationBogusVersion) {
    272   scoped_ptr<TestDataReductionProxyParams> params;
    273   params.reset(
    274       new TestDataReductionProxyParams(
    275           DataReductionProxyParams::kAllowed |
    276           DataReductionProxyParams::kFallbackAllowed |
    277           DataReductionProxyParams::kPromoAllowed,
    278           TestDataReductionProxyParams::HAS_EVERYTHING &
    279           ~TestDataReductionProxyParams::HAS_DEV_ORIGIN &
    280           ~TestDataReductionProxyParams::HAS_DEV_FALLBACK_ORIGIN));
    281   TestDataReductionProxyAuthRequestHandler auth_handler(kClient,
    282                                                         kBogusVersion,
    283                                                         params.get(),
    284                                                         loop_proxy_);
    285   EXPECT_TRUE(auth_handler.build_number_.empty());
    286   EXPECT_TRUE(auth_handler.patch_number_.empty());
    287 
    288   // Now set a key.
    289   auth_handler.InitAuthentication(kTestKey2);
    290   base::RunLoop().RunUntilIdle();
    291   EXPECT_EQ(kTestKey2, auth_handler.key_);
    292   EXPECT_EQ(kExpectedCredentials2, auth_handler.credentials_);
    293   EXPECT_EQ(kExpectedSession2, auth_handler.session_);
    294 
    295   net::HttpRequestHeaders headers;
    296   // Write headers with a valid data reduction proxy;
    297   auth_handler.MaybeAddRequestHeader(
    298       NULL,
    299       net::ProxyServer::FromURI(
    300           net::HostPortPair::FromURL(GURL(params->DefaultOrigin())).ToString(),
    301           net::ProxyServer::SCHEME_HTTP),
    302       &headers);
    303   EXPECT_TRUE(headers.HasHeader(kChromeProxyHeader));
    304   std::string header_value;
    305   headers.GetHeader(kChromeProxyHeader, &header_value);
    306   EXPECT_EQ(kExpectedHeader4, header_value);
    307 }
    308 
    309 TEST_F(DataReductionProxyAuthRequestHandlerTest, AuthHashForSalt) {
    310   std::string salt = "8675309"; // Jenny's number to test the hash generator.
    311   std::string salted_key = salt + kDataReductionProxyKey + salt;
    312   base::string16 expected_hash = base::UTF8ToUTF16(base::MD5String(salted_key));
    313   EXPECT_EQ(expected_hash,
    314             DataReductionProxyAuthRequestHandler::AuthHashForSalt(
    315                 8675309, kDataReductionProxyKey));
    316 }
    317 
    318 }  // namespace data_reduction_proxy
    319