blob: 1a73b37aa1e5ef0c8b762b6a8dbdddbd550c665e [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/data_reduction_proxy/browser/data_reduction_proxy_auth_request_handler.h"
#include "base/md5.h"
#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "components/data_reduction_proxy/browser/data_reduction_proxy_params_test_utils.h"
#include "components/data_reduction_proxy/browser/data_reduction_proxy_settings_test_utils.h"
#include "net/base/auth.h"
#include "net/base/host_port_pair.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace {
const char kChromeProxyHeader[] = "chrome-proxy";
const char kOtherProxy[] = "testproxy:17";
#if defined(OS_ANDROID)
const char kClient[] = "android";
#elif defined(OS_IOS)
const char kClient[] = "ios";
#else
const char kClient[] = "";
#endif
const char kVersion[] = "0.1.2.3";
const char kExpectedBuild[] = "2";
const char kExpectedPatch[] = "3";
const char kBogusVersion[] = "0.0";
const char kTestKey[] = "test-key";
const char kExpectedCredentials[] = "96bd72ec4a050ba60981743d41787768";
const char kExpectedSession[] = "0-1633771873-1633771873-1633771873";
const char kTestKey2[] = "test-key2";
const char kExpectedCredentials2[] = "c911fdb402f578787562cf7f00eda972";
const char kExpectedSession2[] = "0-1633771873-1633771873-1633771873";
#if defined(OS_ANDROID)
const char kExpectedHeader2[] =
"ps=0-1633771873-1633771873-1633771873, "
"sid=c911fdb402f578787562cf7f00eda972, b=2, p=3, c=android";
const char kExpectedHeader3[] =
"ps=86401-1633771873-1633771873-1633771873, "
"sid=d7c1c34ef6b90303b01c48a6c1db6419, b=2, p=3, c=android";
const char kExpectedHeader4[] =
"ps=0-1633771873-1633771873-1633771873, "
"sid=c911fdb402f578787562cf7f00eda972, c=android";
#elif defined(OS_IOS)
const char kExpectedHeader2[] =
"ps=0-1633771873-1633771873-1633771873, "
"sid=c911fdb402f578787562cf7f00eda972, b=2, p=3, c=ios";
const char kExpectedHeader3[] =
"ps=86401-1633771873-1633771873-1633771873, "
"sid=d7c1c34ef6b90303b01c48a6c1db6419, b=2, p=3, c=ios";
const char kExpectedHeader4[] =
"ps=0-1633771873-1633771873-1633771873, "
"sid=c911fdb402f578787562cf7f00eda972, c=ios";
#else
const char kExpectedHeader2[] =
"ps=0-1633771873-1633771873-1633771873, "
"sid=c911fdb402f578787562cf7f00eda972, b=2, p=3";
const char kExpectedHeader3[] =
"ps=86401-1633771873-1633771873-1633771873, "
"sid=d7c1c34ef6b90303b01c48a6c1db6419, b=2, p=3";
const char kExpectedHeader4[] =
"ps=0-1633771873-1633771873-1633771873, "
"sid=c911fdb402f578787562cf7f00eda972";
#endif
const char kDataReductionProxyKey[] = "12345";
} // namespace
namespace data_reduction_proxy {
namespace {
class TestDataReductionProxyAuthRequestHandler
: public DataReductionProxyAuthRequestHandler {
public:
TestDataReductionProxyAuthRequestHandler(
const std::string& client,
const std::string& version,
DataReductionProxyParams* params,
base::MessageLoopProxy* loop_proxy)
: DataReductionProxyAuthRequestHandler(
client, version, params, loop_proxy) {}
virtual std::string GetDefaultKey() const OVERRIDE {
return kTestKey;
}
virtual base::Time Now() const OVERRIDE {
return base::Time::UnixEpoch() + now_offset_;
}
virtual void RandBytes(void* output, size_t length) OVERRIDE {
char* c = static_cast<char*>(output);
for (size_t i = 0; i < length; ++i) {
c[i] = 'a';
}
}
// Time after the unix epoch that Now() reports.
void set_offset(const base::TimeDelta& now_offset) {
now_offset_ = now_offset;
}
private:
base::TimeDelta now_offset_;
};
} // namespace
class DataReductionProxyAuthRequestHandlerTest : public testing::Test {
public:
DataReductionProxyAuthRequestHandlerTest()
: loop_proxy_(base::MessageLoopProxy::current().get()) {
}
// Required for MessageLoopProxy::current().
base::MessageLoopForUI loop_;
base::MessageLoopProxy* loop_proxy_;
};
TEST_F(DataReductionProxyAuthRequestHandlerTest, Authorization) {
scoped_ptr<TestDataReductionProxyParams> params;
params.reset(
new TestDataReductionProxyParams(
DataReductionProxyParams::kAllowed |
DataReductionProxyParams::kFallbackAllowed |
DataReductionProxyParams::kPromoAllowed,
TestDataReductionProxyParams::HAS_EVERYTHING &
~TestDataReductionProxyParams::HAS_DEV_ORIGIN &
~TestDataReductionProxyParams::HAS_DEV_FALLBACK_ORIGIN));
TestDataReductionProxyAuthRequestHandler auth_handler(kClient,
kVersion,
params.get(),
loop_proxy_);
auth_handler.Init();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(auth_handler.client_, kClient);
EXPECT_EQ(kExpectedBuild, auth_handler.build_number_);
EXPECT_EQ(kExpectedPatch, auth_handler.patch_number_);
EXPECT_EQ(auth_handler.key_, kTestKey);
EXPECT_EQ(kExpectedCredentials, auth_handler.credentials_);
EXPECT_EQ(kExpectedSession, auth_handler.session_);
// Now set a key.
auth_handler.SetKeyOnUI(kTestKey2);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(kTestKey2, auth_handler.key_);
EXPECT_EQ(kExpectedCredentials2, auth_handler.credentials_);
EXPECT_EQ(kExpectedSession2, auth_handler.session_);
// Don't write headers if the proxy is invalid.
net::HttpRequestHeaders headers;
auth_handler.MaybeAddRequestHeader(NULL, net::ProxyServer(), &headers);
EXPECT_FALSE(headers.HasHeader(kChromeProxyHeader));
// Don't write headers with a valid proxy, that's not a data reduction proxy.
auth_handler.MaybeAddRequestHeader(
NULL,
net::ProxyServer::FromURI(kOtherProxy, net::ProxyServer::SCHEME_HTTP),
&headers);
EXPECT_FALSE(headers.HasHeader(kChromeProxyHeader));
// Don't write headers with a valid data reduction ssl proxy.
auth_handler.MaybeAddRequestHeader(
NULL,
net::ProxyServer::FromURI(
net::HostPortPair::FromURL(
GURL(params->DefaultSSLOrigin())).ToString(),
net::ProxyServer::SCHEME_HTTP),
&headers);
EXPECT_FALSE(headers.HasHeader(kChromeProxyHeader));
// Write headers with a valid data reduction proxy.
auth_handler.MaybeAddRequestHeader(
NULL,
net::ProxyServer::FromURI(
net::HostPortPair::FromURL(GURL(params->DefaultOrigin())).ToString(),
net::ProxyServer::SCHEME_HTTP),
&headers);
EXPECT_TRUE(headers.HasHeader(kChromeProxyHeader));
std::string header_value;
headers.GetHeader(kChromeProxyHeader, &header_value);
EXPECT_EQ(kExpectedHeader2, header_value);
// Write headers with a valid data reduction ssl proxy when one is expected.
net::HttpRequestHeaders ssl_headers;
auth_handler.MaybeAddProxyTunnelRequestHandler(
net::HostPortPair::FromURL(GURL(params->DefaultSSLOrigin())),
&ssl_headers);
EXPECT_TRUE(ssl_headers.HasHeader(kChromeProxyHeader));
std::string ssl_header_value;
ssl_headers.GetHeader(kChromeProxyHeader, &ssl_header_value);
EXPECT_EQ(kExpectedHeader2, ssl_header_value);
// Fast forward 24 hours. The header should be the same.
auth_handler.set_offset(base::TimeDelta::FromSeconds(24 * 60 * 60));
net::HttpRequestHeaders headers2;
// Write headers with a valid data reduction proxy.
auth_handler.MaybeAddRequestHeader(
NULL,
net::ProxyServer::FromURI(
net::HostPortPair::FromURL(GURL(params->DefaultOrigin())).ToString(),
net::ProxyServer::SCHEME_HTTP),
&headers2);
EXPECT_TRUE(headers2.HasHeader(kChromeProxyHeader));
std::string header_value2;
headers2.GetHeader(kChromeProxyHeader, &header_value2);
EXPECT_EQ(kExpectedHeader2, header_value2);
// Fast forward one more second. The header should be new.
auth_handler.set_offset(base::TimeDelta::FromSeconds(24 * 60 * 60 + 1));
net::HttpRequestHeaders headers3;
// Write headers with a valid data reduction proxy.
auth_handler.MaybeAddRequestHeader(
NULL,
net::ProxyServer::FromURI(
net::HostPortPair::FromURL(GURL(params->DefaultOrigin())).ToString(),
net::ProxyServer::SCHEME_HTTP),
&headers3);
EXPECT_TRUE(headers3.HasHeader(kChromeProxyHeader));
std::string header_value3;
headers3.GetHeader(kChromeProxyHeader, &header_value3);
EXPECT_EQ(kExpectedHeader3, header_value3);
}
TEST_F(DataReductionProxyAuthRequestHandlerTest, AuthorizationBogusVersion) {
scoped_ptr<TestDataReductionProxyParams> params;
params.reset(
new TestDataReductionProxyParams(
DataReductionProxyParams::kAllowed |
DataReductionProxyParams::kFallbackAllowed |
DataReductionProxyParams::kPromoAllowed,
TestDataReductionProxyParams::HAS_EVERYTHING &
~TestDataReductionProxyParams::HAS_DEV_ORIGIN &
~TestDataReductionProxyParams::HAS_DEV_FALLBACK_ORIGIN));
TestDataReductionProxyAuthRequestHandler auth_handler(kClient,
kBogusVersion,
params.get(),
loop_proxy_);
EXPECT_TRUE(auth_handler.build_number_.empty());
EXPECT_TRUE(auth_handler.patch_number_.empty());
// Now set a key.
auth_handler.SetKeyOnUI(kTestKey2);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(kTestKey2, auth_handler.key_);
EXPECT_EQ(kExpectedCredentials2, auth_handler.credentials_);
EXPECT_EQ(kExpectedSession2, auth_handler.session_);
net::HttpRequestHeaders headers;
// Write headers with a valid data reduction proxy;
auth_handler.MaybeAddRequestHeader(
NULL,
net::ProxyServer::FromURI(
net::HostPortPair::FromURL(GURL(params->DefaultOrigin())).ToString(),
net::ProxyServer::SCHEME_HTTP),
&headers);
EXPECT_TRUE(headers.HasHeader(kChromeProxyHeader));
std::string header_value;
headers.GetHeader(kChromeProxyHeader, &header_value);
EXPECT_EQ(kExpectedHeader4, header_value);
}
TEST_F(DataReductionProxyAuthRequestHandlerTest, AuthHashForSalt) {
std::string salt = "8675309"; // Jenny's number to test the hash generator.
std::string salted_key = salt + kDataReductionProxyKey + salt;
base::string16 expected_hash = base::UTF8ToUTF16(base::MD5String(salted_key));
EXPECT_EQ(expected_hash,
DataReductionProxyAuthRequestHandler::AuthHashForSalt(
8675309, kDataReductionProxyKey));
}
} // namespace data_reduction_proxy