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