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 // static |
29 | 24 bool DataReductionProxyAuthRequestHandler::IsKeySetOnCommandLine() { |
30 int DataReductionProxyAuthRequestHandler::back_to_back_failure_count_ = 0; | 25 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
31 | 26 return command_line.HasSwitch( |
32 int64 | 27 data_reduction_proxy::switches::kDataReductionProxyKey); |
33 DataReductionProxyAuthRequestHandler::auth_token_invalidation_timestamp_ = 0; | 28 } |
34 | |
35 | 29 |
36 DataReductionProxyAuthRequestHandler::DataReductionProxyAuthRequestHandler( | 30 DataReductionProxyAuthRequestHandler::DataReductionProxyAuthRequestHandler( |
37 DataReductionProxySettings* settings) : settings_(settings) { | 31 DataReductionProxyParams* params) |
38 DCHECK(settings); | 32 : data_reduction_proxy_params_(params) { |
| 33 version_ = "0"; |
| 34 #if defined(OS_ANDROID) |
| 35 client_ = "android"; |
| 36 #elif defined(OS_IOS) |
| 37 client_ = "ios"; |
| 38 #endif |
| 39 Init(); |
39 } | 40 } |
40 | 41 |
| 42 void DataReductionProxyAuthRequestHandler::Init() { |
| 43 InitAuthentication(GetDefaultKey()); |
| 44 } |
| 45 |
| 46 |
41 DataReductionProxyAuthRequestHandler::~DataReductionProxyAuthRequestHandler() { | 47 DataReductionProxyAuthRequestHandler::~DataReductionProxyAuthRequestHandler() { |
42 } | 48 } |
43 | 49 |
44 DataReductionProxyAuthRequestHandler::TryHandleResult | 50 // static |
45 DataReductionProxyAuthRequestHandler::TryHandleAuthentication( | 51 base::string16 DataReductionProxyAuthRequestHandler::AuthHashForSalt( |
46 net::AuthChallengeInfo* auth_info, | 52 int64 salt, |
47 base::string16* user, | 53 const std::string& key) { |
48 base::string16* password) { | 54 std::string salted_key = |
49 if (!auth_info) { | 55 base::StringPrintf("%lld%s%lld", |
50 return TRY_HANDLE_RESULT_IGNORE; | 56 static_cast<long long>(salt), |
51 } | 57 key.c_str(), |
52 DCHECK(user); | 58 static_cast<long long>(salt)); |
53 DCHECK(password); | 59 return base::UTF8ToUTF16(base::MD5String(salted_key)); |
54 | 60 } |
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 | 61 |
66 | 62 |
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 | 63 |
95 *password = GetTokenForAuthChallenge(auth_info); | 64 base::Time DataReductionProxyAuthRequestHandler::Now() const { |
96 | 65 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 } | 66 } |
105 | 67 |
106 bool DataReductionProxyAuthRequestHandler::IsAcceptableAuthChallenge( | 68 void DataReductionProxyAuthRequestHandler::RandBytes( |
107 net::AuthChallengeInfo* auth_info) { | 69 void* output, size_t length) { |
108 return settings_->IsAcceptableAuthChallenge(auth_info); | 70 crypto::RandBytes(output, length); |
109 } | 71 } |
110 | 72 |
111 base::string16 DataReductionProxyAuthRequestHandler::GetTokenForAuthChallenge( | 73 void DataReductionProxyAuthRequestHandler::MaybeAddRequestHeader( |
112 net::AuthChallengeInfo* auth_info) { | 74 net::URLRequest* request, |
113 DCHECK(settings_); | 75 const net::ProxyServer& proxy_server, |
114 return settings_->GetTokenForAuthChallenge(auth_info); | 76 net::HttpRequestHeaders* request_headers) { |
| 77 if (!proxy_server.is_valid()) { |
| 78 LOG(WARNING) << "Invalid proxy"; |
| 79 return; |
| 80 } else { |
| 81 LOG(WARNING) << "Valid proxy"; |
| 82 } |
| 83 if (data_reduction_proxy_params_ && |
| 84 data_reduction_proxy_params_->IsDataReductionProxy( |
| 85 proxy_server.host_port_pair(), NULL)) { |
| 86 LOG(WARNING) << "DRP"; |
| 87 AddAuthorizationHeader(request_headers); |
| 88 } |
| 89 else { |
| 90 LOG(WARNING) << "Not DRP"; |
| 91 } |
115 } | 92 } |
116 | 93 |
117 base::TimeTicks DataReductionProxyAuthRequestHandler::Now() { | 94 void DataReductionProxyAuthRequestHandler::AddAuthorizationHeader( |
118 return base::TimeTicks::Now(); | 95 net::HttpRequestHeaders* headers) { |
| 96 const char kChromeProxyHeader[] = "Chrome-Proxy"; |
| 97 std::string header_value; |
| 98 if (headers->HasHeader(kChromeProxyHeader)) { |
| 99 headers->GetHeader(kChromeProxyHeader, &header_value); |
| 100 headers->RemoveHeader(kChromeProxyHeader); |
| 101 header_value += ", "; |
| 102 } |
| 103 header_value += |
| 104 "ps=" + session_ + ", sid=" + credentials_ + ", v=" + version_; |
| 105 if (!client_.empty()) |
| 106 header_value += ", c=" + client_; |
| 107 headers->SetHeader(kChromeProxyHeader, header_value); |
| 108 } |
| 109 |
| 110 void DataReductionProxyAuthRequestHandler::InitAuthentication( |
| 111 const std::string& key) { |
| 112 key_ = key; |
| 113 int64 timestamp = |
| 114 (Now() - base::Time::UnixEpoch()).InMilliseconds() / 1000; |
| 115 |
| 116 int32 rand[3]; |
| 117 RandBytes(rand, 3 * sizeof(rand[0])); |
| 118 session_ = base::StringPrintf("%lld-%u-%u-%u", |
| 119 static_cast<long long>(timestamp), |
| 120 rand[0], |
| 121 rand[1], |
| 122 rand[2]); |
| 123 credentials_ = UTF16ToUTF8(AuthHashForSalt(timestamp, key_)); |
| 124 |
| 125 DVLOG(1) << "session: [" << session_ << "] password: [" << credentials_ |
| 126 << "]"; |
| 127 } |
| 128 |
| 129 void DataReductionProxyAuthRequestHandler::SetKey(const std::string& key, |
| 130 const std::string& client, |
| 131 const std::string& version) { |
| 132 client_ = client; |
| 133 version_ = version; |
| 134 if (!key.empty()) |
| 135 InitAuthentication(key); |
| 136 } |
| 137 |
| 138 |
| 139 std::string DataReductionProxyAuthRequestHandler::GetDefaultKey() const { |
| 140 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
| 141 std::string key = |
| 142 command_line.GetSwitchValueASCII(switches::kDataReductionProxyKey); |
| 143 #if defined(SPDY_PROXY_AUTH_VALUE) |
| 144 if (key.empty()) |
| 145 key = SPDY_PROXY_AUTH_VALUE; |
| 146 #endif |
| 147 return key; |
119 } | 148 } |
120 | 149 |
121 } // namespace data_reduction_proxy | 150 } // namespace data_reduction_proxy |
OLD | NEW |