OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "net/http/http_auth_handler_digest.h" | 5 #include "net/http/http_auth_handler_digest.h" |
6 | 6 |
| 7 #include <string> |
| 8 |
7 #include "base/logging.h" | 9 #include "base/logging.h" |
8 #include "base/md5.h" | 10 #include "base/md5.h" |
9 #include "base/rand_util.h" | 11 #include "base/rand_util.h" |
10 #include "base/string_util.h" | 12 #include "base/string_util.h" |
11 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" |
12 #include "net/base/net_errors.h" | 14 #include "net/base/net_errors.h" |
13 #include "net/base/net_util.h" | 15 #include "net/base/net_util.h" |
14 #include "net/http/http_auth.h" | 16 #include "net/http/http_auth.h" |
15 #include "net/http/http_request_info.h" | 17 #include "net/http/http_request_info.h" |
16 #include "net/http/http_util.h" | 18 #include "net/http/http_util.h" |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
79 case ALGORITHM_MD5: | 81 case ALGORITHM_MD5: |
80 return "MD5"; | 82 return "MD5"; |
81 case ALGORITHM_MD5_SESS: | 83 case ALGORITHM_MD5_SESS: |
82 return "MD5-sess"; | 84 return "MD5-sess"; |
83 default: | 85 default: |
84 return ""; | 86 return ""; |
85 } | 87 } |
86 } | 88 } |
87 | 89 |
88 int HttpAuthHandlerDigest::GenerateAuthTokenImpl( | 90 int HttpAuthHandlerDigest::GenerateAuthTokenImpl( |
89 const std::wstring* username, | 91 const string16* username, |
90 const std::wstring* password, | 92 const string16* password, |
91 const HttpRequestInfo* request, | 93 const HttpRequestInfo* request, |
92 CompletionCallback* callback, | 94 CompletionCallback* callback, |
93 std::string* auth_token) { | 95 std::string* auth_token) { |
94 // Generate a random client nonce. | 96 // Generate a random client nonce. |
95 std::string cnonce = GenerateNonce(); | 97 std::string cnonce = GenerateNonce(); |
96 | 98 |
97 // Extract the request method and path -- the meaning of 'path' is overloaded | 99 // Extract the request method and path -- the meaning of 'path' is overloaded |
98 // in certain cases, to be a hostname. | 100 // in certain cases, to be a hostname. |
99 std::string method; | 101 std::string method; |
100 std::string path; | 102 std::string path; |
101 GetRequestMethodAndPath(request, &method, &path); | 103 GetRequestMethodAndPath(request, &method, &path); |
102 | 104 |
103 *auth_token = AssembleCredentials(method, path, | 105 *auth_token = AssembleCredentials(method, path, |
104 // TODO(eroman): is this the right encoding? | 106 *username, |
105 WideToUTF8(*username), | 107 *password, |
106 WideToUTF8(*password), | |
107 cnonce, nonce_count_); | 108 cnonce, nonce_count_); |
108 return OK; | 109 return OK; |
109 } | 110 } |
110 | 111 |
111 void HttpAuthHandlerDigest::GetRequestMethodAndPath( | 112 void HttpAuthHandlerDigest::GetRequestMethodAndPath( |
112 const HttpRequestInfo* request, | 113 const HttpRequestInfo* request, |
113 std::string* method, | 114 std::string* method, |
114 std::string* path) const { | 115 std::string* path) const { |
115 DCHECK(request); | 116 DCHECK(request); |
116 | 117 |
117 const GURL& url = request->url; | 118 const GURL& url = request->url; |
118 | 119 |
119 if (target_ == HttpAuth::AUTH_PROXY && url.SchemeIs("https")) { | 120 if (target_ == HttpAuth::AUTH_PROXY && url.SchemeIs("https")) { |
120 *method = "CONNECT"; | 121 *method = "CONNECT"; |
121 *path = GetHostAndPort(url); | 122 *path = GetHostAndPort(url); |
122 } else { | 123 } else { |
123 *method = request->method; | 124 *method = request->method; |
124 *path = HttpUtil::PathForRequest(url); | 125 *path = HttpUtil::PathForRequest(url); |
125 } | 126 } |
126 } | 127 } |
127 | 128 |
128 std::string HttpAuthHandlerDigest::AssembleResponseDigest( | 129 std::string HttpAuthHandlerDigest::AssembleResponseDigest( |
129 const std::string& method, | 130 const std::string& method, |
130 const std::string& path, | 131 const std::string& path, |
131 const std::string& username, | 132 const string16& username, |
132 const std::string& password, | 133 const string16& password, |
133 const std::string& cnonce, | 134 const std::string& cnonce, |
134 const std::string& nc) const { | 135 const std::string& nc) const { |
135 // ha1 = MD5(A1) | 136 // ha1 = MD5(A1) |
136 std::string ha1 = MD5String(username + ":" + realm_ + ":" + password); | 137 // TODO(eroman): is this the right encoding? |
| 138 std::string ha1 = MD5String(UTF16ToUTF8(username) + ":" + realm_ + ":" + |
| 139 UTF16ToUTF8(password)); |
137 if (algorithm_ == HttpAuthHandlerDigest::ALGORITHM_MD5_SESS) | 140 if (algorithm_ == HttpAuthHandlerDigest::ALGORITHM_MD5_SESS) |
138 ha1 = MD5String(ha1 + ":" + nonce_ + ":" + cnonce); | 141 ha1 = MD5String(ha1 + ":" + nonce_ + ":" + cnonce); |
139 | 142 |
140 // ha2 = MD5(A2) | 143 // ha2 = MD5(A2) |
141 // TODO(eroman): need to add MD5(req-entity-body) for qop=auth-int. | 144 // TODO(eroman): need to add MD5(req-entity-body) for qop=auth-int. |
142 std::string ha2 = MD5String(method + ":" + path); | 145 std::string ha2 = MD5String(method + ":" + path); |
143 | 146 |
144 std::string nc_part; | 147 std::string nc_part; |
145 if (qop_ != HttpAuthHandlerDigest::QOP_UNSPECIFIED) { | 148 if (qop_ != HttpAuthHandlerDigest::QOP_UNSPECIFIED) { |
146 nc_part = nc + ":" + cnonce + ":" + QopToString(qop_) + ":"; | 149 nc_part = nc + ":" + cnonce + ":" + QopToString(qop_) + ":"; |
147 } | 150 } |
148 | 151 |
149 return MD5String(ha1 + ":" + nonce_ + ":" + nc_part + ha2); | 152 return MD5String(ha1 + ":" + nonce_ + ":" + nc_part + ha2); |
150 } | 153 } |
151 | 154 |
152 std::string HttpAuthHandlerDigest::AssembleCredentials( | 155 std::string HttpAuthHandlerDigest::AssembleCredentials( |
153 const std::string& method, | 156 const std::string& method, |
154 const std::string& path, | 157 const std::string& path, |
155 const std::string& username, | 158 const string16& username, |
156 const std::string& password, | 159 const string16& password, |
157 const std::string& cnonce, | 160 const std::string& cnonce, |
158 int nonce_count) const { | 161 int nonce_count) const { |
159 // the nonce-count is an 8 digit hex string. | 162 // the nonce-count is an 8 digit hex string. |
160 std::string nc = StringPrintf("%08x", nonce_count); | 163 std::string nc = StringPrintf("%08x", nonce_count); |
161 | 164 |
| 165 // TODO(eroman): is this the right encoding? |
162 std::string authorization = std::string("Digest username=") + | 166 std::string authorization = std::string("Digest username=") + |
163 HttpUtil::Quote(username); | 167 HttpUtil::Quote(UTF16ToUTF8(username)); |
164 authorization += ", realm=" + HttpUtil::Quote(realm_); | 168 authorization += ", realm=" + HttpUtil::Quote(realm_); |
165 authorization += ", nonce=" + HttpUtil::Quote(nonce_); | 169 authorization += ", nonce=" + HttpUtil::Quote(nonce_); |
166 authorization += ", uri=" + HttpUtil::Quote(path); | 170 authorization += ", uri=" + HttpUtil::Quote(path); |
167 | 171 |
168 if (algorithm_ != ALGORITHM_UNSPECIFIED) { | 172 if (algorithm_ != ALGORITHM_UNSPECIFIED) { |
169 authorization += ", algorithm=" + AlgorithmToString(algorithm_); | 173 authorization += ", algorithm=" + AlgorithmToString(algorithm_); |
170 } | 174 } |
171 std::string response = AssembleResponseDigest(method, path, username, | 175 std::string response = AssembleResponseDigest(method, path, username, |
172 password, cnonce, nc); | 176 password, cnonce, nc); |
173 // No need to call HttpUtil::Quote() as the response digest cannot contain | 177 // No need to call HttpUtil::Quote() as the response digest cannot contain |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
212 properties_ = ENCRYPTS_IDENTITY; | 216 properties_ = ENCRYPTS_IDENTITY; |
213 | 217 |
214 // Initialize to defaults. | 218 // Initialize to defaults. |
215 stale_ = false; | 219 stale_ = false; |
216 algorithm_ = ALGORITHM_UNSPECIFIED; | 220 algorithm_ = ALGORITHM_UNSPECIFIED; |
217 qop_ = QOP_UNSPECIFIED; | 221 qop_ = QOP_UNSPECIFIED; |
218 realm_ = nonce_ = domain_ = opaque_ = std::string(); | 222 realm_ = nonce_ = domain_ = opaque_ = std::string(); |
219 | 223 |
220 if (!challenge->valid() || | 224 if (!challenge->valid() || |
221 !LowerCaseEqualsASCII(challenge->scheme(), "digest")) | 225 !LowerCaseEqualsASCII(challenge->scheme(), "digest")) |
222 return false; // FAIL -- Couldn't match auth-scheme. | 226 return false; // FAIL -- Couldn't match auth-scheme. |
223 | 227 |
224 // Loop through all the properties. | 228 // Loop through all the properties. |
225 while (challenge->GetNext()) { | 229 while (challenge->GetNext()) { |
226 if (challenge->value().empty()) { | 230 if (challenge->value().empty()) { |
227 DLOG(INFO) << "Invalid digest property"; | 231 DLOG(INFO) << "Invalid digest property"; |
228 return false; | 232 return false; |
229 } | 233 } |
230 | 234 |
231 if (!ParseChallengeProperty(challenge->name(), challenge->unquoted_value())) | 235 if (!ParseChallengeProperty(challenge->name(), challenge->unquoted_value())) |
232 return false; // FAIL -- couldn't parse a property. | 236 return false; // FAIL -- couldn't parse a property. |
233 } | 237 } |
234 | 238 |
235 // Check if tokenizer failed. | 239 // Check if tokenizer failed. |
236 if (!challenge->valid()) | 240 if (!challenge->valid()) |
237 return false; // FAIL | 241 return false; // FAIL |
238 | 242 |
239 // Check that a minimum set of properties were provided. | 243 // Check that a minimum set of properties were provided. |
240 if (nonce_.empty()) | 244 if (nonce_.empty()) |
241 return false; // FAIL | 245 return false; // FAIL |
242 | 246 |
243 return true; | 247 return true; |
244 } | 248 } |
245 | 249 |
246 bool HttpAuthHandlerDigest::ParseChallengeProperty(const std::string& name, | 250 bool HttpAuthHandlerDigest::ParseChallengeProperty(const std::string& name, |
247 const std::string& value) { | 251 const std::string& value) { |
248 if (LowerCaseEqualsASCII(name, "realm")) { | 252 if (LowerCaseEqualsASCII(name, "realm")) { |
249 realm_ = value; | 253 realm_ = value; |
250 } else if (LowerCaseEqualsASCII(name, "nonce")) { | 254 } else if (LowerCaseEqualsASCII(name, "nonce")) { |
251 nonce_ = value; | 255 nonce_ = value; |
252 } else if (LowerCaseEqualsASCII(name, "domain")) { | 256 } else if (LowerCaseEqualsASCII(name, "domain")) { |
253 domain_ = value; | 257 domain_ = value; |
254 } else if (LowerCaseEqualsASCII(name, "opaque")) { | 258 } else if (LowerCaseEqualsASCII(name, "opaque")) { |
255 opaque_ = value; | 259 opaque_ = value; |
256 } else if (LowerCaseEqualsASCII(name, "stale")) { | 260 } else if (LowerCaseEqualsASCII(name, "stale")) { |
257 // Parse the stale boolean. | 261 // Parse the stale boolean. |
258 stale_ = LowerCaseEqualsASCII(value, "true"); | 262 stale_ = LowerCaseEqualsASCII(value, "true"); |
259 } else if (LowerCaseEqualsASCII(name, "algorithm")) { | 263 } else if (LowerCaseEqualsASCII(name, "algorithm")) { |
260 // Parse the algorithm. | 264 // Parse the algorithm. |
261 if (LowerCaseEqualsASCII(value, "md5")) { | 265 if (LowerCaseEqualsASCII(value, "md5")) { |
262 algorithm_ = ALGORITHM_MD5; | 266 algorithm_ = ALGORITHM_MD5; |
263 } else if (LowerCaseEqualsASCII(value, "md5-sess")) { | 267 } else if (LowerCaseEqualsASCII(value, "md5-sess")) { |
264 algorithm_ = ALGORITHM_MD5_SESS; | 268 algorithm_ = ALGORITHM_MD5_SESS; |
265 } else { | 269 } else { |
266 DLOG(INFO) << "Unknown value of algorithm"; | 270 DLOG(INFO) << "Unknown value of algorithm"; |
267 return false; // FAIL -- unsupported value of algorithm. | 271 return false; // FAIL -- unsupported value of algorithm. |
268 } | 272 } |
269 } else if (LowerCaseEqualsASCII(name, "qop")) { | 273 } else if (LowerCaseEqualsASCII(name, "qop")) { |
270 // Parse the comma separated list of qops. | 274 // Parse the comma separated list of qops. |
271 HttpUtil::ValuesIterator qop_values(value.begin(), value.end(), ','); | 275 HttpUtil::ValuesIterator qop_values(value.begin(), value.end(), ','); |
272 while (qop_values.GetNext()) { | 276 while (qop_values.GetNext()) { |
273 if (LowerCaseEqualsASCII(qop_values.value(), "auth")) { | 277 if (LowerCaseEqualsASCII(qop_values.value(), "auth")) { |
274 qop_ |= QOP_AUTH; | 278 qop_ |= QOP_AUTH; |
275 } else if (LowerCaseEqualsASCII(qop_values.value(), "auth-int")) { | 279 } else if (LowerCaseEqualsASCII(qop_values.value(), "auth-int")) { |
276 qop_ |= QOP_AUTH_INT; | 280 qop_ |= QOP_AUTH_INT; |
277 } | 281 } |
(...skipping 23 matching lines...) Expand all Loading... |
301 // method and only constructing when valid. | 305 // method and only constructing when valid. |
302 scoped_ptr<HttpAuthHandler> tmp_handler( | 306 scoped_ptr<HttpAuthHandler> tmp_handler( |
303 new HttpAuthHandlerDigest(digest_nonce_count)); | 307 new HttpAuthHandlerDigest(digest_nonce_count)); |
304 if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log)) | 308 if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log)) |
305 return ERR_INVALID_RESPONSE; | 309 return ERR_INVALID_RESPONSE; |
306 handler->swap(tmp_handler); | 310 handler->swap(tmp_handler); |
307 return OK; | 311 return OK; |
308 } | 312 } |
309 | 313 |
310 } // namespace net | 314 } // namespace net |
OLD | NEW |