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 { |
marq (ping after 24h)
2014/06/25 16:39:26
Why wrap base::Time::Now() like this?
bengr
2014/06/25 17:15:19
This facilitates testing. There's a comment in the
| |
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( |
marq (ping after 24h)
2014/06/25 16:39:27
Why wrap RandBytes like this?
bengr
2014/06/25 17:15:19
This facilitates testing also.
| |
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"; | |
marq (ping after 24h)
2014/06/25 16:39:26
Clean up the logging -- this looks like debugging
bengr
2014/06/25 17:15:18
Aargh. Sorry. Done.
| |
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 { | |
marq (ping after 24h)
2014/06/25 16:39:27
} else {
bengr
2014/06/25 17:15:19
Done.
| |
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 << "]"; | |
marq (ping after 24h)
2014/06/25 16:39:27
Align << for continued log lines.
bengr
2014/06/25 17:15:19
Done.
| |
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(); | |
marq (ping after 24h)
2014/06/25 16:39:26
Why doesn't this get the key from a data_reduction
bengr
2014/06/25 17:15:19
Key has been pulled out of params, bucause it is m
| |
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 |