• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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