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 22namespace { 23const char kChromeProxyHeader[] = "chrome-proxy"; 24const 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 34const char kVersion[] = "0.1.2.3"; 35const char kExpectedBuild[] = "2"; 36const char kExpectedPatch[] = "3"; 37const char kBogusVersion[] = "0.0"; 38const char kTestKey[] = "test-key"; 39const char kExpectedCredentials[] = "96bd72ec4a050ba60981743d41787768"; 40const char kExpectedSession[] = "0-1633771873-1633771873-1633771873"; 41 42const char kTestKey2[] = "test-key2"; 43const char kExpectedCredentials2[] = "c911fdb402f578787562cf7f00eda972"; 44const char kExpectedSession2[] = "0-1633771873-1633771873-1633771873"; 45#if defined(OS_ANDROID) 46const char kExpectedHeader2[] = 47 "ps=0-1633771873-1633771873-1633771873, " 48 "sid=c911fdb402f578787562cf7f00eda972, b=2, p=3, c=android"; 49const char kExpectedHeader3[] = 50 "ps=86401-1633771873-1633771873-1633771873, " 51 "sid=d7c1c34ef6b90303b01c48a6c1db6419, b=2, p=3, c=android"; 52const char kExpectedHeader4[] = 53 "ps=0-1633771873-1633771873-1633771873, " 54 "sid=c911fdb402f578787562cf7f00eda972, c=android"; 55#elif defined(OS_IOS) 56const char kExpectedHeader2[] = 57 "ps=0-1633771873-1633771873-1633771873, " 58 "sid=c911fdb402f578787562cf7f00eda972, b=2, p=3, c=ios"; 59const char kExpectedHeader3[] = 60 "ps=86401-1633771873-1633771873-1633771873, " 61 "sid=d7c1c34ef6b90303b01c48a6c1db6419, b=2, p=3, c=ios"; 62const char kExpectedHeader4[] = 63 "ps=0-1633771873-1633771873-1633771873, " 64 "sid=c911fdb402f578787562cf7f00eda972, c=ios"; 65#else 66const char kExpectedHeader2[] = 67 "ps=0-1633771873-1633771873-1633771873, " 68 "sid=c911fdb402f578787562cf7f00eda972, b=2, p=3"; 69const char kExpectedHeader3[] = 70 "ps=86401-1633771873-1633771873-1633771873, " 71 "sid=d7c1c34ef6b90303b01c48a6c1db6419, b=2, p=3"; 72const char kExpectedHeader4[] = 73 "ps=0-1633771873-1633771873-1633771873, " 74 "sid=c911fdb402f578787562cf7f00eda972"; 75#endif 76 77const char kDataReductionProxyKey[] = "12345"; 78} // namespace 79 80 81namespace data_reduction_proxy { 82namespace { 83class 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 120class 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 130TEST_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 237TEST_F(DataReductionProxyAuthRequestHandlerTest, AuthorizationIgnoresEmptyKey) { 238scoped_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 271TEST_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 309TEST_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