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