OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/data_reduction_proxy/browser/data_reduction_proxy_auth_requ
est_handler.h" | 5 #include "components/data_reduction_proxy/browser/data_reduction_proxy_auth_requ
est_handler.h" |
6 | 6 |
| 7 #include "base/command_line.h" |
| 8 #include "base/strings/stringprintf.h" |
7 #include "base/strings/utf_string_conversions.h" | 9 #include "base/strings/utf_string_conversions.h" |
8 #include "base/time/time.h" | 10 #include "base/time/time.h" |
| 11 #include "components/data_reduction_proxy/browser/data_reduction_proxy_params.h" |
| 12 #include "components/data_reduction_proxy/browser/data_reduction_proxy_protocol.
h" |
9 #include "components/data_reduction_proxy/browser/data_reduction_proxy_settings.
h" | 13 #include "components/data_reduction_proxy/browser/data_reduction_proxy_settings.
h" |
10 #include "net/base/auth.h" | 14 #include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h" |
11 | 15 #include "components/data_reduction_proxy/common/data_reduction_proxy_switches.h
" |
12 namespace { | 16 #include "crypto/random.h" |
13 // The minimum interval allowed, in milliseconds, between data reduction proxy | 17 #include "net/proxy/proxy_server.h" |
14 // auth requests. | 18 #include "net/url_request/url_request.h" |
15 const int64 kMinAuthRequestIntervalMs = 500; | 19 #include "url/gurl.h" |
16 | |
17 // The minimum interval allowed, in milliseconds, between data reduction proxy | |
18 // auth token invalidation. | |
19 const int64 kMinTokenInvalidationIntervalMs = 60 * 60 * 1000; | |
20 | |
21 // The maximum number of data reduction proxy authentication failures to | |
22 // accept before giving up. | |
23 const int kMaxBackToBackFailures = 5; | |
24 } | |
25 | 20 |
26 namespace data_reduction_proxy { | 21 namespace data_reduction_proxy { |
27 | 22 |
28 int64 DataReductionProxyAuthRequestHandler::auth_request_timestamp_ = 0; | 23 // The version of the authentication protocol. |
| 24 const char kProtocolVersion[] = "0"; |
29 | 25 |
30 int DataReductionProxyAuthRequestHandler::back_to_back_failure_count_ = 0; | 26 // The clients supported by the data reduction proxy. |
| 27 const char kClientAndroidWebview[] = "webview"; |
| 28 const char kClientChromeAndroid[] = "android"; |
| 29 const char kClientChromeIOS[] = "ios"; |
31 | 30 |
32 int64 | 31 // static |
33 DataReductionProxyAuthRequestHandler::auth_token_invalidation_timestamp_ = 0; | 32 bool DataReductionProxyAuthRequestHandler::IsKeySetOnCommandLine() { |
34 | 33 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
| 34 return command_line.HasSwitch( |
| 35 data_reduction_proxy::switches::kDataReductionProxyKey); |
| 36 } |
35 | 37 |
36 DataReductionProxyAuthRequestHandler::DataReductionProxyAuthRequestHandler( | 38 DataReductionProxyAuthRequestHandler::DataReductionProxyAuthRequestHandler( |
37 DataReductionProxySettings* settings) : settings_(settings) { | 39 DataReductionProxyParams* params) |
38 DCHECK(settings); | 40 : data_reduction_proxy_params_(params) { |
| 41 version_ = kProtocolVersion; |
| 42 #if defined(OS_ANDROID) |
| 43 client_ = kClientChromeAndroid; |
| 44 #elif defined(OS_IOS) |
| 45 client_ = kClientChromeIOS; |
| 46 #endif |
| 47 Init(); |
39 } | 48 } |
40 | 49 |
| 50 void DataReductionProxyAuthRequestHandler::Init() { |
| 51 InitAuthentication(GetDefaultKey()); |
| 52 } |
| 53 |
| 54 |
41 DataReductionProxyAuthRequestHandler::~DataReductionProxyAuthRequestHandler() { | 55 DataReductionProxyAuthRequestHandler::~DataReductionProxyAuthRequestHandler() { |
42 } | 56 } |
43 | 57 |
44 DataReductionProxyAuthRequestHandler::TryHandleResult | 58 // static |
45 DataReductionProxyAuthRequestHandler::TryHandleAuthentication( | 59 base::string16 DataReductionProxyAuthRequestHandler::AuthHashForSalt( |
46 net::AuthChallengeInfo* auth_info, | 60 int64 salt, |
47 base::string16* user, | 61 const std::string& key) { |
48 base::string16* password) { | 62 std::string salted_key = |
49 if (!auth_info) { | 63 base::StringPrintf("%lld%s%lld", |
50 return TRY_HANDLE_RESULT_IGNORE; | 64 static_cast<long long>(salt), |
51 } | 65 key.c_str(), |
52 DCHECK(user); | 66 static_cast<long long>(salt)); |
53 DCHECK(password); | 67 return base::UTF8ToUTF16(base::MD5String(salted_key)); |
54 | 68 } |
55 if (!IsAcceptableAuthChallenge(auth_info)) { | |
56 *user = base::string16(); | |
57 *password = base::string16(); | |
58 return TRY_HANDLE_RESULT_IGNORE; | |
59 } | |
60 | |
61 base::TimeTicks auth_request = | |
62 base::TimeTicks::FromInternalValue(auth_request_timestamp_); | |
63 base::TimeTicks auth_token_invalidation = | |
64 base::TimeTicks::FromInternalValue(auth_token_invalidation_timestamp_); | |
65 | 69 |
66 | 70 |
67 base::TimeTicks now = Now(); | |
68 if ((now - auth_request).InMilliseconds() < kMinAuthRequestIntervalMs) { | |
69 // We've received back-to-back failures. There are two possibilities: | |
70 // 1) Our auth token has expired and we should invalidate it, or | |
71 // 2) We're receiving spurious failures from the service. | |
72 // | |
73 // If we haven't recently invalidated our token, we do that here | |
74 // and make several attempts to authenticate. Otherwise, we fail. | |
75 back_to_back_failure_count_++; | |
76 if ((now - auth_token_invalidation).InMilliseconds() < | |
77 kMinTokenInvalidationIntervalMs) { | |
78 auth_token_invalidation_timestamp_ = now.ToInternalValue(); | |
79 back_to_back_failure_count_ = 0; | |
80 } else { | |
81 if (back_to_back_failure_count_ > kMaxBackToBackFailures) { | |
82 DLOG(WARNING) << "Interpreting frequent data reduction proxy auth " | |
83 << "requests as an authorization failure."; | |
84 back_to_back_failure_count_ = 0; | |
85 *user = base::string16(); | |
86 *password = base::string16(); | |
87 return TRY_HANDLE_RESULT_CANCEL; | |
88 } | |
89 } | |
90 } else { | |
91 back_to_back_failure_count_ = 0; | |
92 } | |
93 auth_request_timestamp_ = now.ToInternalValue(); | |
94 | 71 |
95 *password = GetTokenForAuthChallenge(auth_info); | 72 base::Time DataReductionProxyAuthRequestHandler::Now() const { |
96 | 73 return base::Time::Now(); |
97 if (*password == base::string16()) { | |
98 *user = base::string16(); | |
99 DLOG(WARNING) << "Data reduction proxy auth produced null token."; | |
100 return TRY_HANDLE_RESULT_CANCEL; | |
101 } | |
102 *user = base::UTF8ToUTF16("fw-cookie"); | |
103 return TRY_HANDLE_RESULT_PROCEED; | |
104 } | 74 } |
105 | 75 |
106 bool DataReductionProxyAuthRequestHandler::IsAcceptableAuthChallenge( | 76 void DataReductionProxyAuthRequestHandler::RandBytes( |
107 net::AuthChallengeInfo* auth_info) { | 77 void* output, size_t length) { |
108 return settings_->IsAcceptableAuthChallenge(auth_info); | 78 crypto::RandBytes(output, length); |
109 } | 79 } |
110 | 80 |
111 base::string16 DataReductionProxyAuthRequestHandler::GetTokenForAuthChallenge( | 81 void DataReductionProxyAuthRequestHandler::MaybeAddRequestHeader( |
112 net::AuthChallengeInfo* auth_info) { | 82 net::URLRequest* request, |
113 DCHECK(settings_); | 83 const net::ProxyServer& proxy_server, |
114 return settings_->GetTokenForAuthChallenge(auth_info); | 84 net::HttpRequestHeaders* request_headers) { |
| 85 if (!proxy_server.is_valid()) { |
| 86 LOG(WARNING) << "Invalid proxy"; |
| 87 return; |
| 88 } else { |
| 89 LOG(WARNING) << "Valid proxy"; |
| 90 } |
| 91 if (data_reduction_proxy_params_ && |
| 92 data_reduction_proxy_params_->IsDataReductionProxy( |
| 93 proxy_server.host_port_pair(), NULL)) { |
| 94 LOG(WARNING) << "DRP"; |
| 95 AddAuthorizationHeader(request_headers); |
| 96 } |
| 97 else { |
| 98 LOG(WARNING) << "Not DRP"; |
| 99 } |
115 } | 100 } |
116 | 101 |
117 base::TimeTicks DataReductionProxyAuthRequestHandler::Now() { | 102 void DataReductionProxyAuthRequestHandler::AddAuthorizationHeader( |
118 return base::TimeTicks::Now(); | 103 net::HttpRequestHeaders* headers) { |
| 104 const char kChromeProxyHeader[] = "Chrome-Proxy"; |
| 105 std::string header_value; |
| 106 if (headers->HasHeader(kChromeProxyHeader)) { |
| 107 headers->GetHeader(kChromeProxyHeader, &header_value); |
| 108 headers->RemoveHeader(kChromeProxyHeader); |
| 109 header_value += ", "; |
| 110 } |
| 111 header_value += |
| 112 "ps=" + session_ + ", sid=" + credentials_ + ", v=" + version_; |
| 113 if (!client_.empty()) |
| 114 header_value += ", c=" + client_; |
| 115 headers->SetHeader(kChromeProxyHeader, header_value); |
| 116 } |
| 117 |
| 118 void DataReductionProxyAuthRequestHandler::InitAuthentication( |
| 119 const std::string& key) { |
| 120 key_ = key; |
| 121 int64 timestamp = |
| 122 (Now() - base::Time::UnixEpoch()).InMilliseconds() / 1000; |
| 123 |
| 124 int32 rand[3]; |
| 125 RandBytes(rand, 3 * sizeof(rand[0])); |
| 126 session_ = base::StringPrintf("%lld-%u-%u-%u", |
| 127 static_cast<long long>(timestamp), |
| 128 rand[0], |
| 129 rand[1], |
| 130 rand[2]); |
| 131 credentials_ = UTF16ToUTF8(AuthHashForSalt(timestamp, key_)); |
| 132 |
| 133 DVLOG(1) << "session: [" << session_ << "] password: [" << credentials_ |
| 134 << "]"; |
| 135 } |
| 136 |
| 137 void DataReductionProxyAuthRequestHandler::SetKey(const std::string& key, |
| 138 const std::string& client, |
| 139 const std::string& version) { |
| 140 client_ = client; |
| 141 version_ = version; |
| 142 if (!key.empty()) |
| 143 InitAuthentication(key); |
| 144 } |
| 145 |
| 146 |
| 147 std::string DataReductionProxyAuthRequestHandler::GetDefaultKey() const { |
| 148 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
| 149 std::string key = |
| 150 command_line.GetSwitchValueASCII(switches::kDataReductionProxyKey); |
| 151 #if defined(SPDY_PROXY_AUTH_VALUE) |
| 152 if (key.empty()) |
| 153 key = SPDY_PROXY_AUTH_VALUE; |
| 154 #endif |
| 155 return key; |
119 } | 156 } |
120 | 157 |
121 } // namespace data_reduction_proxy | 158 } // namespace data_reduction_proxy |
OLD | NEW |