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
3 // found in the LICENSE file.
4
5 #include <string>
6
7 #include "base/basictypes.h"
8 #include "base/string_util.h"
9 #include "base/utf_string_conversions.h"
10 #include "net/base/net_errors.h"
11 #include "net/base/test_completion_callback.h"
12 #include "net/http/http_auth_handler_digest.h"
13 #include "net/http/http_request_info.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace net {
17
18 namespace {
19
20 const char* const kSimpleChallenge =
21 "Digest realm=\"Oblivion\", nonce=\"nonce-value\"";
22
23 // RespondToChallenge creates an HttpAuthHandlerDigest for the specified
24 // |challenge|, and generates a response to the challenge which is returned in
25 // |token|.
26 //
27 // The return value indicates whether the |token| was successfully created.
28 //
29 // If |target| is HttpAuth::AUTH_PROXY, then |proxy_name| specifies the source
30 // of the |challenge|. Otherwise, the scheme and host and port of |request_url|
31 // indicates the origin of the challenge.
RespondToChallenge(HttpAuth::Target target,const std::string & proxy_name,const std::string & request_url,const std::string & challenge,std::string * token)32 bool RespondToChallenge(HttpAuth::Target target,
33 const std::string& proxy_name,
34 const std::string& request_url,
35 const std::string& challenge,
36 std::string* token) {
37 // Input validation.
38 if (token == NULL) {
39 ADD_FAILURE() << "|token| must be non-NULL";
40 return false;
41 }
42 EXPECT_TRUE(target != HttpAuth::AUTH_PROXY || !proxy_name.empty());
43 EXPECT_FALSE(request_url.empty());
44 EXPECT_FALSE(challenge.empty());
45
46 token->clear();
47 scoped_ptr<HttpAuthHandlerDigest::Factory> factory(
48 new HttpAuthHandlerDigest::Factory());
49 HttpAuthHandlerDigest::NonceGenerator* nonce_generator =
50 new HttpAuthHandlerDigest::FixedNonceGenerator("client_nonce");
51 factory->set_nonce_generator(nonce_generator);
52 scoped_ptr<HttpAuthHandler> handler;
53
54 // Create a handler for a particular challenge.
55 GURL url_origin(target == HttpAuth::AUTH_SERVER ? request_url : proxy_name);
56 int rv_create = factory->CreateAuthHandlerFromString(
57 challenge, target, url_origin.GetOrigin(), BoundNetLog(), &handler);
58 if (rv_create != OK || handler.get() == NULL) {
59 ADD_FAILURE() << "Unable to create auth handler.";
60 return false;
61 }
62
63 // Create a token in response to the challenge.
64 // NOTE: HttpAuthHandlerDigest's implementation of GenerateAuthToken always
65 // completes synchronously. That's why this test can get away with a
66 // TestCompletionCallback without an IO thread.
67 TestCompletionCallback callback;
68 scoped_ptr<HttpRequestInfo> request(new HttpRequestInfo());
69 request->url = GURL(request_url);
70 const string16 kFoo = ASCIIToUTF16("foo");
71 const string16 kBar = ASCIIToUTF16("bar");
72 int rv_generate = handler->GenerateAuthToken(
73 &kFoo, &kBar, request.get(), &callback, token);
74 if (rv_generate != OK) {
75 ADD_FAILURE() << "Problems generating auth token";
76 return false;
77 }
78
79 return true;
80 }
81
82 } // namespace
83
84
TEST(HttpAuthHandlerDigestTest,ParseChallenge)85 TEST(HttpAuthHandlerDigestTest, ParseChallenge) {
86 static const struct {
87 // The challenge string.
88 const char* challenge;
89 // Expected return value of ParseChallenge.
90 bool parsed_success;
91 // The expected values that were parsed.
92 const char* parsed_realm;
93 const char* parsed_nonce;
94 const char* parsed_domain;
95 const char* parsed_opaque;
96 bool parsed_stale;
97 int parsed_algorithm;
98 int parsed_qop;
99 } tests[] = {
100 { // Check that a minimal challenge works correctly.
101 "Digest nonce=\"xyz\", realm=\"Thunder Bluff\"",
102 true,
103 "Thunder Bluff",
104 "xyz",
105 "",
106 "",
107 false,
108 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
109 HttpAuthHandlerDigest::QOP_UNSPECIFIED
110 },
111
112 { // Realm does not need to be quoted, even though RFC2617 requires it.
113 "Digest nonce=\"xyz\", realm=ThunderBluff",
114 true,
115 "ThunderBluff",
116 "xyz",
117 "",
118 "",
119 false,
120 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
121 HttpAuthHandlerDigest::QOP_UNSPECIFIED
122 },
123
124 { // We allow the realm to be omitted, and will default it to empty string.
125 // See http://crbug.com/20984.
126 "Digest nonce=\"xyz\"",
127 true,
128 "",
129 "xyz",
130 "",
131 "",
132 false,
133 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
134 HttpAuthHandlerDigest::QOP_UNSPECIFIED
135 },
136
137 { // Try with realm set to empty string.
138 "Digest realm=\"\", nonce=\"xyz\"",
139 true,
140 "",
141 "xyz",
142 "",
143 "",
144 false,
145 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
146 HttpAuthHandlerDigest::QOP_UNSPECIFIED
147 },
148
149 { // At a minimum, a nonce must be provided.
150 "Digest realm=\"Thunder Bluff\"",
151 false,
152 "",
153 "",
154 "",
155 "",
156 false,
157 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
158 HttpAuthHandlerDigest::QOP_UNSPECIFIED
159 },
160
161 { // The nonce does not need to be quoted, even though RFC2617
162 // requires it.
163 "Digest nonce=xyz, realm=\"Thunder Bluff\"",
164 true,
165 "Thunder Bluff",
166 "xyz",
167 "",
168 "",
169 false,
170 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
171 HttpAuthHandlerDigest::QOP_UNSPECIFIED
172 },
173
174 { // Unknown authentication parameters are ignored.
175 "Digest nonce=\"xyz\", realm=\"Thunder Bluff\", foo=\"bar\"",
176 true,
177 "Thunder Bluff",
178 "xyz",
179 "",
180 "",
181 false,
182 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
183 HttpAuthHandlerDigest::QOP_UNSPECIFIED
184 },
185
186 { // Check that when algorithm has an unsupported value, parsing fails.
187 "Digest nonce=\"xyz\", algorithm=\"awezum\", realm=\"Thunder\"",
188 false,
189 // The remaining values don't matter (but some have been set already).
190 "",
191 "xyz",
192 "",
193 "",
194 false,
195 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
196 HttpAuthHandlerDigest::QOP_UNSPECIFIED
197 },
198
199 { // Check that algorithm's value is case insensitive, and that MD5 is
200 // a supported algorithm.
201 "Digest nonce=\"xyz\", algorithm=\"mD5\", realm=\"Oblivion\"",
202 true,
203 "Oblivion",
204 "xyz",
205 "",
206 "",
207 false,
208 HttpAuthHandlerDigest::ALGORITHM_MD5,
209 HttpAuthHandlerDigest::QOP_UNSPECIFIED
210 },
211
212 { // Check that md5-sess is a supported algorithm.
213 "Digest nonce=\"xyz\", algorithm=\"md5-sess\", realm=\"Oblivion\"",
214 true,
215 "Oblivion",
216 "xyz",
217 "",
218 "",
219 false,
220 HttpAuthHandlerDigest::ALGORITHM_MD5_SESS,
221 HttpAuthHandlerDigest::QOP_UNSPECIFIED,
222 },
223
224 { // Check that qop's value is case insensitive, and that auth is known.
225 "Digest nonce=\"xyz\", realm=\"Oblivion\", qop=\"aUth\"",
226 true,
227 "Oblivion",
228 "xyz",
229 "",
230 "",
231 false,
232 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
233 HttpAuthHandlerDigest::QOP_AUTH
234 },
235
236 { // auth-int is not handled, but will fall back to default qop.
237 "Digest nonce=\"xyz\", realm=\"Oblivion\", qop=\"auth-int\"",
238 true,
239 "Oblivion",
240 "xyz",
241 "",
242 "",
243 false,
244 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
245 HttpAuthHandlerDigest::QOP_UNSPECIFIED
246 },
247
248 { // Unknown qop values are ignored.
249 "Digest nonce=\"xyz\", realm=\"Oblivion\", qop=\"auth,foo\"",
250 true,
251 "Oblivion",
252 "xyz",
253 "",
254 "",
255 false,
256 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
257 HttpAuthHandlerDigest::QOP_AUTH
258 },
259
260 { // If auth-int is included with auth, then use auth.
261 "Digest nonce=\"xyz\", realm=\"Oblivion\", qop=\"auth,auth-int\"",
262 true,
263 "Oblivion",
264 "xyz",
265 "",
266 "",
267 false,
268 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
269 HttpAuthHandlerDigest::QOP_AUTH
270 },
271
272 { // Opaque parameter parsing should work correctly.
273 "Digest nonce=\"xyz\", realm=\"Thunder Bluff\", opaque=\"foobar\"",
274 true,
275 "Thunder Bluff",
276 "xyz",
277 "",
278 "foobar",
279 false,
280 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
281 HttpAuthHandlerDigest::QOP_UNSPECIFIED
282 },
283
284 { // Opaque parameters do not need to be quoted, even though RFC2617
285 // seems to require it.
286 "Digest nonce=\"xyz\", realm=\"Thunder Bluff\", opaque=foobar",
287 true,
288 "Thunder Bluff",
289 "xyz",
290 "",
291 "foobar",
292 false,
293 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
294 HttpAuthHandlerDigest::QOP_UNSPECIFIED
295 },
296
297 { // Domain can be parsed.
298 "Digest nonce=\"xyz\", realm=\"Thunder Bluff\", "
299 "domain=\"http://intranet.example.com/protection\"",
300 true,
301 "Thunder Bluff",
302 "xyz",
303 "http://intranet.example.com/protection",
304 "",
305 false,
306 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
307 HttpAuthHandlerDigest::QOP_UNSPECIFIED
308 },
309
310 { // Multiple domains can be parsed.
311 "Digest nonce=\"xyz\", realm=\"Thunder Bluff\", "
312 "domain=\"http://intranet.example.com/protection http://www.google.com\"",
313 true,
314 "Thunder Bluff",
315 "xyz",
316 "http://intranet.example.com/protection http://www.google.com",
317 "",
318 false,
319 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
320 HttpAuthHandlerDigest::QOP_UNSPECIFIED
321 },
322
323 { // If a non-Digest scheme is somehow passed in, it should be rejected.
324 "Basic realm=\"foo\"",
325 false,
326 "",
327 "",
328 "",
329 "",
330 false,
331 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
332 HttpAuthHandlerDigest::QOP_UNSPECIFIED
333 },
334 };
335
336 GURL origin("http://www.example.com");
337 scoped_ptr<HttpAuthHandlerDigest::Factory> factory(
338 new HttpAuthHandlerDigest::Factory());
339 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
340 scoped_ptr<HttpAuthHandler> handler;
341 int rv = factory->CreateAuthHandlerFromString(tests[i].challenge,
342 HttpAuth::AUTH_SERVER,
343 origin,
344 BoundNetLog(),
345 &handler);
346 if (tests[i].parsed_success) {
347 EXPECT_EQ(OK, rv);
348 } else {
349 EXPECT_NE(OK, rv);
350 EXPECT_TRUE(handler.get() == NULL);
351 continue;
352 }
353 ASSERT_TRUE(handler.get() != NULL);
354 HttpAuthHandlerDigest* digest =
355 static_cast<HttpAuthHandlerDigest*>(handler.get());
356 EXPECT_STREQ(tests[i].parsed_realm, digest->realm_.c_str());
357 EXPECT_STREQ(tests[i].parsed_nonce, digest->nonce_.c_str());
358 EXPECT_STREQ(tests[i].parsed_domain, digest->domain_.c_str());
359 EXPECT_STREQ(tests[i].parsed_opaque, digest->opaque_.c_str());
360 EXPECT_EQ(tests[i].parsed_stale, digest->stale_);
361 EXPECT_EQ(tests[i].parsed_algorithm, digest->algorithm_);
362 EXPECT_EQ(tests[i].parsed_qop, digest->qop_);
363 EXPECT_TRUE(handler->encrypts_identity());
364 EXPECT_FALSE(handler->is_connection_based());
365 EXPECT_TRUE(handler->NeedsIdentity());
366 EXPECT_FALSE(handler->AllowsDefaultCredentials());
367 }
368 }
369
TEST(HttpAuthHandlerDigestTest,AssembleCredentials)370 TEST(HttpAuthHandlerDigestTest, AssembleCredentials) {
371 static const struct {
372 const char* req_method;
373 const char* req_path;
374 const char* challenge;
375 const char* username;
376 const char* password;
377 const char* cnonce;
378 int nonce_count;
379 const char* expected_creds;
380 } tests[] = {
381 { // MD5 with username/password
382 "GET",
383 "/test/drealm1",
384
385 // Challenge
386 "Digest realm=\"DRealm1\", "
387 "nonce=\"claGgoRXBAA=7583377687842fdb7b56ba0555d175baa0b800e3\", "
388 "algorithm=MD5, qop=\"auth\"",
389
390 "foo", "bar", // username/password
391 "082c875dcb2ca740", // cnonce
392 1, // nc
393
394 // Authorization
395 "Digest username=\"foo\", realm=\"DRealm1\", "
396 "nonce=\"claGgoRXBAA=7583377687842fdb7b56ba0555d175baa0b800e3\", "
397 "uri=\"/test/drealm1\", algorithm=MD5, "
398 "response=\"bcfaa62f1186a31ff1b474a19a17cf57\", "
399 "qop=auth, nc=00000001, cnonce=\"082c875dcb2ca740\""
400 },
401
402 { // MD5 with username but empty password. username has space in it.
403 "GET",
404 "/test/drealm1/",
405
406 // Challenge
407 "Digest realm=\"DRealm1\", "
408 "nonce=\"Ure30oRXBAA=7eca98bbf521ac6642820b11b86bd2d9ed7edc70\", "
409 "algorithm=MD5, qop=\"auth\"",
410
411 "foo bar", "", // Username/password
412 "082c875dcb2ca740", // cnonce
413 1, // nc
414
415 // Authorization
416 "Digest username=\"foo bar\", realm=\"DRealm1\", "
417 "nonce=\"Ure30oRXBAA=7eca98bbf521ac6642820b11b86bd2d9ed7edc70\", "
418 "uri=\"/test/drealm1/\", algorithm=MD5, "
419 "response=\"93c9c6d5930af3b0eb26c745e02b04a0\", "
420 "qop=auth, nc=00000001, cnonce=\"082c875dcb2ca740\""
421 },
422
423 { // MD5 with no username.
424 "GET",
425 "/test/drealm1/",
426
427 // Challenge
428 "Digest realm=\"DRealm1\", "
429 "nonce=\"7thGplhaBAA=41fb92453c49799cf353c8cd0aabee02d61a98a8\", "
430 "algorithm=MD5, qop=\"auth\"",
431
432 "", "pass", // Username/password
433 "6509bc74daed8263", // cnonce
434 1, // nc
435
436 // Authorization
437 "Digest username=\"\", realm=\"DRealm1\", "
438 "nonce=\"7thGplhaBAA=41fb92453c49799cf353c8cd0aabee02d61a98a8\", "
439 "uri=\"/test/drealm1/\", algorithm=MD5, "
440 "response=\"bc597110f41a62d07f8b70b6977fcb61\", "
441 "qop=auth, nc=00000001, cnonce=\"6509bc74daed8263\""
442 },
443
444 { // MD5 with no username and no password.
445 "GET",
446 "/test/drealm1/",
447
448 // Challenge
449 "Digest realm=\"DRealm1\", "
450 "nonce=\"s3MzvFhaBAA=4c520af5acd9d8d7ae26947529d18c8eae1e98f4\", "
451 "algorithm=MD5, qop=\"auth\"",
452
453 "", "", // Username/password
454 "1522e61005789929", // cnonce
455 1, // nc
456
457 // Authorization
458 "Digest username=\"\", realm=\"DRealm1\", "
459 "nonce=\"s3MzvFhaBAA=4c520af5acd9d8d7ae26947529d18c8eae1e98f4\", "
460 "uri=\"/test/drealm1/\", algorithm=MD5, "
461 "response=\"22cfa2b30cb500a9591c6d55ec5590a8\", "
462 "qop=auth, nc=00000001, cnonce=\"1522e61005789929\""
463 },
464
465 { // No algorithm, and no qop.
466 "GET",
467 "/",
468
469 // Challenge
470 "Digest realm=\"Oblivion\", nonce=\"nonce-value\"",
471
472 "FooBar", "pass", // Username/password
473 "", // cnonce
474 1, // nc
475
476 // Authorization
477 "Digest username=\"FooBar\", realm=\"Oblivion\", "
478 "nonce=\"nonce-value\", uri=\"/\", "
479 "response=\"f72ff54ebde2f928860f806ec04acd1b\""
480 },
481
482 { // MD5-sess
483 "GET",
484 "/",
485
486 // Challenge
487 "Digest realm=\"Baztastic\", nonce=\"AAAAAAAA\", "
488 "algorithm=\"md5-sess\", qop=auth",
489
490 "USER", "123", // Username/password
491 "15c07961ed8575c4", // cnonce
492 1, // nc
493
494 // Authorization
495 "Digest username=\"USER\", realm=\"Baztastic\", "
496 "nonce=\"AAAAAAAA\", uri=\"/\", algorithm=MD5-sess, "
497 "response=\"cbc1139821ee7192069580570c541a03\", "
498 "qop=auth, nc=00000001, cnonce=\"15c07961ed8575c4\""
499 }
500 };
501 GURL origin("http://www.example.com");
502 scoped_ptr<HttpAuthHandlerDigest::Factory> factory(
503 new HttpAuthHandlerDigest::Factory());
504 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
505 scoped_ptr<HttpAuthHandler> handler;
506 int rv = factory->CreateAuthHandlerFromString(tests[i].challenge,
507 HttpAuth::AUTH_SERVER,
508 origin,
509 BoundNetLog(),
510 &handler);
511 EXPECT_EQ(OK, rv);
512 ASSERT_TRUE(handler != NULL);
513
514 HttpAuthHandlerDigest* digest =
515 static_cast<HttpAuthHandlerDigest*>(handler.get());
516 std::string creds =
517 digest->AssembleCredentials(tests[i].req_method,
518 tests[i].req_path,
519 ASCIIToUTF16(tests[i].username),
520 ASCIIToUTF16(tests[i].password),
521 tests[i].cnonce,
522 tests[i].nonce_count);
523
524 EXPECT_STREQ(tests[i].expected_creds, creds.c_str());
525 }
526 }
527
TEST(HttpAuthHandlerDigest,HandleAnotherChallenge)528 TEST(HttpAuthHandlerDigest, HandleAnotherChallenge) {
529 scoped_ptr<HttpAuthHandlerDigest::Factory> factory(
530 new HttpAuthHandlerDigest::Factory());
531 scoped_ptr<HttpAuthHandler> handler;
532 std::string default_challenge =
533 "Digest realm=\"Oblivion\", nonce=\"nonce-value\"";
534 GURL origin("intranet.google.com");
535 int rv = factory->CreateAuthHandlerFromString(
536 default_challenge, HttpAuth::AUTH_SERVER, origin, BoundNetLog(),
537 &handler);
538 EXPECT_EQ(OK, rv);
539 ASSERT_TRUE(handler.get() != NULL);
540 HttpAuth::ChallengeTokenizer tok_default(default_challenge.begin(),
541 default_challenge.end());
542 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT,
543 handler->HandleAnotherChallenge(&tok_default));
544
545 std::string stale_challenge = default_challenge + ", stale=true";
546 HttpAuth::ChallengeTokenizer tok_stale(stale_challenge.begin(),
547 stale_challenge.end());
548 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_STALE,
549 handler->HandleAnotherChallenge(&tok_stale));
550
551 std::string stale_false_challenge = default_challenge + ", stale=false";
552 HttpAuth::ChallengeTokenizer tok_stale_false(stale_false_challenge.begin(),
553 stale_false_challenge.end());
554 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT,
555 handler->HandleAnotherChallenge(&tok_stale_false));
556
557 std::string realm_change_challenge =
558 "Digest realm=\"SomethingElse\", nonce=\"nonce-value2\"";
559 HttpAuth::ChallengeTokenizer tok_realm_change(realm_change_challenge.begin(),
560 realm_change_challenge.end());
561 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_DIFFERENT_REALM,
562 handler->HandleAnotherChallenge(&tok_realm_change));
563 }
564
TEST(HttpAuthHandlerDigest,RespondToServerChallenge)565 TEST(HttpAuthHandlerDigest, RespondToServerChallenge) {
566 std::string auth_token;
567 EXPECT_TRUE(RespondToChallenge(
568 HttpAuth::AUTH_SERVER,
569 std::string(),
570 "http://www.example.com/path/to/resource",
571 kSimpleChallenge,
572 &auth_token));
573 EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
574 "nonce=\"nonce-value\", uri=\"/path/to/resource\", "
575 "response=\"6779f90bd0d658f937c1af967614fe84\"",
576 auth_token);
577 }
578
TEST(HttpAuthHandlerDigest,RespondToHttpsServerChallenge)579 TEST(HttpAuthHandlerDigest, RespondToHttpsServerChallenge) {
580 std::string auth_token;
581 EXPECT_TRUE(RespondToChallenge(
582 HttpAuth::AUTH_SERVER,
583 std::string(),
584 "https://www.example.com/path/to/resource",
585 kSimpleChallenge,
586 &auth_token));
587 EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
588 "nonce=\"nonce-value\", uri=\"/path/to/resource\", "
589 "response=\"6779f90bd0d658f937c1af967614fe84\"",
590 auth_token);
591 }
592
TEST(HttpAuthHandlerDigest,RespondToProxyChallenge)593 TEST(HttpAuthHandlerDigest, RespondToProxyChallenge) {
594 std::string auth_token;
595 EXPECT_TRUE(RespondToChallenge(
596 HttpAuth::AUTH_PROXY,
597 "http://proxy.intranet.corp.com:3128",
598 "http://www.example.com/path/to/resource",
599 kSimpleChallenge,
600 &auth_token));
601 EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
602 "nonce=\"nonce-value\", uri=\"/path/to/resource\", "
603 "response=\"6779f90bd0d658f937c1af967614fe84\"",
604 auth_token);
605 }
606
TEST(HttpAuthHandlerDigest,RespondToProxyChallengeHttps)607 TEST(HttpAuthHandlerDigest, RespondToProxyChallengeHttps) {
608 std::string auth_token;
609 EXPECT_TRUE(RespondToChallenge(
610 HttpAuth::AUTH_PROXY,
611 "http://proxy.intranet.corp.com:3128",
612 "https://www.example.com/path/to/resource",
613 kSimpleChallenge,
614 &auth_token));
615 EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
616 "nonce=\"nonce-value\", uri=\"www.example.com:443\", "
617 "response=\"3270da8467afbe9ddf2334a48d46e9b9\"",
618 auth_token);
619 }
620
TEST(HttpAuthHandlerDigest,RespondToChallengeAuthQop)621 TEST(HttpAuthHandlerDigest, RespondToChallengeAuthQop) {
622 std::string auth_token;
623 EXPECT_TRUE(RespondToChallenge(
624 HttpAuth::AUTH_SERVER,
625 std::string(),
626 "http://www.example.com/path/to/resource",
627 "Digest realm=\"Oblivion\", nonce=\"nonce-value\", qop=\"auth\"",
628 &auth_token));
629 EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
630 "nonce=\"nonce-value\", uri=\"/path/to/resource\", "
631 "response=\"5b1459beda5cee30d6ff9e970a69c0ea\", "
632 "qop=auth, nc=00000001, cnonce=\"client_nonce\"",
633 auth_token);
634 }
635
TEST(HttpAuthHandlerDigest,RespondToChallengeOpaque)636 TEST(HttpAuthHandlerDigest, RespondToChallengeOpaque) {
637 std::string auth_token;
638 EXPECT_TRUE(RespondToChallenge(
639 HttpAuth::AUTH_SERVER,
640 std::string(),
641 "http://www.example.com/path/to/resource",
642 "Digest realm=\"Oblivion\", nonce=\"nonce-value\", "
643 "qop=\"auth\", opaque=\"opaque text\"",
644 &auth_token));
645 EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
646 "nonce=\"nonce-value\", uri=\"/path/to/resource\", "
647 "response=\"5b1459beda5cee30d6ff9e970a69c0ea\", "
648 "opaque=\"opaque text\", "
649 "qop=auth, nc=00000001, cnonce=\"client_nonce\"",
650 auth_token);
651 }
652
653
654 } // namespace net
655