| // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include <string> | 
 |  | 
 | #include "base/basictypes.h" | 
 | #include "base/strings/string_util.h" | 
 | #include "base/strings/utf_string_conversions.h" | 
 | #include "net/base/net_errors.h" | 
 | #include "net/base/test_completion_callback.h" | 
 | #include "net/http/http_auth_challenge_tokenizer.h" | 
 | #include "net/http/http_auth_handler_digest.h" | 
 | #include "net/http/http_request_info.h" | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 |  | 
 | namespace net { | 
 |  | 
 | namespace { | 
 |  | 
 | const char* const kSimpleChallenge = | 
 |   "Digest realm=\"Oblivion\", nonce=\"nonce-value\""; | 
 |  | 
 | // RespondToChallenge creates an HttpAuthHandlerDigest for the specified | 
 | // |challenge|, and generates a response to the challenge which is returned in | 
 | // |token|. | 
 | // | 
 | // The return value indicates whether the |token| was successfully created. | 
 | // | 
 | // If |target| is HttpAuth::AUTH_PROXY, then |proxy_name| specifies the source | 
 | // of the |challenge|. Otherwise, the scheme and host and port of |request_url| | 
 | // indicates the origin of the challenge. | 
 | bool RespondToChallenge(HttpAuth::Target target, | 
 |                         const std::string& proxy_name, | 
 |                         const std::string& request_url, | 
 |                         const std::string& challenge, | 
 |                         std::string* token) { | 
 |   // Input validation. | 
 |   if (token == NULL) { | 
 |     ADD_FAILURE() << "|token| must be non-NULL"; | 
 |     return false; | 
 |   } | 
 |   EXPECT_TRUE(target != HttpAuth::AUTH_PROXY || !proxy_name.empty()); | 
 |   EXPECT_FALSE(request_url.empty()); | 
 |   EXPECT_FALSE(challenge.empty()); | 
 |  | 
 |   token->clear(); | 
 |   scoped_ptr<HttpAuthHandlerDigest::Factory> factory( | 
 |       new HttpAuthHandlerDigest::Factory()); | 
 |   HttpAuthHandlerDigest::NonceGenerator* nonce_generator = | 
 |       new HttpAuthHandlerDigest::FixedNonceGenerator("client_nonce"); | 
 |   factory->set_nonce_generator(nonce_generator); | 
 |   scoped_ptr<HttpAuthHandler> handler; | 
 |  | 
 |   // Create a handler for a particular challenge. | 
 |   GURL url_origin(target == HttpAuth::AUTH_SERVER ? request_url : proxy_name); | 
 |   int rv_create = factory->CreateAuthHandlerFromString( | 
 |     challenge, target, url_origin.GetOrigin(), BoundNetLog(), &handler); | 
 |   if (rv_create != OK || handler.get() == NULL) { | 
 |     ADD_FAILURE() << "Unable to create auth handler."; | 
 |     return false; | 
 |   } | 
 |  | 
 |   // Create a token in response to the challenge. | 
 |   // NOTE: HttpAuthHandlerDigest's implementation of GenerateAuthToken always | 
 |   // completes synchronously. That's why this test can get away with a | 
 |   // TestCompletionCallback without an IO thread. | 
 |   TestCompletionCallback callback; | 
 |   scoped_ptr<HttpRequestInfo> request(new HttpRequestInfo()); | 
 |   request->url = GURL(request_url); | 
 |   AuthCredentials credentials(base::ASCIIToUTF16("foo"), | 
 |                               base::ASCIIToUTF16("bar")); | 
 |   int rv_generate = handler->GenerateAuthToken( | 
 |       &credentials, request.get(), callback.callback(), token); | 
 |   if (rv_generate != OK) { | 
 |     ADD_FAILURE() << "Problems generating auth token"; | 
 |     return false; | 
 |   } | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 |  | 
 | TEST(HttpAuthHandlerDigestTest, ParseChallenge) { | 
 |   static const struct { | 
 |     // The challenge string. | 
 |     const char* challenge; | 
 |     // Expected return value of ParseChallenge. | 
 |     bool parsed_success; | 
 |     // The expected values that were parsed. | 
 |     const char* parsed_realm; | 
 |     const char* parsed_nonce; | 
 |     const char* parsed_domain; | 
 |     const char* parsed_opaque; | 
 |     bool parsed_stale; | 
 |     int parsed_algorithm; | 
 |     int parsed_qop; | 
 |   } tests[] = { | 
 |     { // Check that a minimal challenge works correctly. | 
 |       "Digest nonce=\"xyz\", realm=\"Thunder Bluff\"", | 
 |       true, | 
 |       "Thunder Bluff", | 
 |       "xyz", | 
 |       "", | 
 |       "", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED, | 
 |       HttpAuthHandlerDigest::QOP_UNSPECIFIED | 
 |     }, | 
 |  | 
 |     { // Realm does not need to be quoted, even though RFC2617 requires it. | 
 |       "Digest nonce=\"xyz\", realm=ThunderBluff", | 
 |       true, | 
 |       "ThunderBluff", | 
 |       "xyz", | 
 |       "", | 
 |       "", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED, | 
 |       HttpAuthHandlerDigest::QOP_UNSPECIFIED | 
 |     }, | 
 |  | 
 |     { // We allow the realm to be omitted, and will default it to empty string. | 
 |       // See http://crbug.com/20984. | 
 |       "Digest nonce=\"xyz\"", | 
 |       true, | 
 |       "", | 
 |       "xyz", | 
 |       "", | 
 |       "", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED, | 
 |       HttpAuthHandlerDigest::QOP_UNSPECIFIED | 
 |     }, | 
 |  | 
 |     { // Try with realm set to empty string. | 
 |       "Digest realm=\"\", nonce=\"xyz\"", | 
 |       true, | 
 |       "", | 
 |       "xyz", | 
 |       "", | 
 |       "", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED, | 
 |       HttpAuthHandlerDigest::QOP_UNSPECIFIED | 
 |     }, | 
 |  | 
 |     // Handle ISO-8859-1 character as part of the realm. The realm is converted | 
 |     // to UTF-8. However, the credentials will still use the original encoding. | 
 |     { | 
 |       "Digest nonce=\"xyz\", realm=\"foo-\xE5\"", | 
 |       true, | 
 |       "foo-\xC3\xA5", | 
 |       "xyz", | 
 |       "", | 
 |       "", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED, | 
 |       HttpAuthHandlerDigest::QOP_UNSPECIFIED, | 
 |     }, | 
 |  | 
 |     { // At a minimum, a nonce must be provided. | 
 |       "Digest realm=\"Thunder Bluff\"", | 
 |       false, | 
 |       "", | 
 |       "", | 
 |       "", | 
 |       "", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED, | 
 |       HttpAuthHandlerDigest::QOP_UNSPECIFIED | 
 |     }, | 
 |  | 
 |     { // The nonce does not need to be quoted, even though RFC2617 | 
 |       // requires it. | 
 |       "Digest nonce=xyz, realm=\"Thunder Bluff\"", | 
 |       true, | 
 |       "Thunder Bluff", | 
 |       "xyz", | 
 |       "", | 
 |       "", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED, | 
 |       HttpAuthHandlerDigest::QOP_UNSPECIFIED | 
 |     }, | 
 |  | 
 |     { // Unknown authentication parameters are ignored. | 
 |       "Digest nonce=\"xyz\", realm=\"Thunder Bluff\", foo=\"bar\"", | 
 |       true, | 
 |       "Thunder Bluff", | 
 |       "xyz", | 
 |       "", | 
 |       "", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED, | 
 |       HttpAuthHandlerDigest::QOP_UNSPECIFIED | 
 |     }, | 
 |  | 
 |     { // Check that when algorithm has an unsupported value, parsing fails. | 
 |       "Digest nonce=\"xyz\", algorithm=\"awezum\", realm=\"Thunder\"", | 
 |       false, | 
 |       // The remaining values don't matter (but some have been set already). | 
 |       "", | 
 |       "xyz", | 
 |       "", | 
 |       "", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED, | 
 |       HttpAuthHandlerDigest::QOP_UNSPECIFIED | 
 |     }, | 
 |  | 
 |     { // Check that algorithm's value is case insensitive, and that MD5 is | 
 |       // a supported algorithm. | 
 |       "Digest nonce=\"xyz\", algorithm=\"mD5\", realm=\"Oblivion\"", | 
 |       true, | 
 |       "Oblivion", | 
 |       "xyz", | 
 |       "", | 
 |       "", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_MD5, | 
 |       HttpAuthHandlerDigest::QOP_UNSPECIFIED | 
 |     }, | 
 |  | 
 |     { // Check that md5-sess is a supported algorithm. | 
 |       "Digest nonce=\"xyz\", algorithm=\"md5-sess\", realm=\"Oblivion\"", | 
 |       true, | 
 |       "Oblivion", | 
 |       "xyz", | 
 |       "", | 
 |       "", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_MD5_SESS, | 
 |       HttpAuthHandlerDigest::QOP_UNSPECIFIED, | 
 |     }, | 
 |  | 
 |     { // Check that qop's value is case insensitive, and that auth is known. | 
 |       "Digest nonce=\"xyz\", realm=\"Oblivion\", qop=\"aUth\"", | 
 |       true, | 
 |       "Oblivion", | 
 |       "xyz", | 
 |       "", | 
 |       "", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED, | 
 |       HttpAuthHandlerDigest::QOP_AUTH | 
 |     }, | 
 |  | 
 |     { // auth-int is not handled, but will fall back to default qop. | 
 |       "Digest nonce=\"xyz\", realm=\"Oblivion\", qop=\"auth-int\"", | 
 |       true, | 
 |       "Oblivion", | 
 |       "xyz", | 
 |       "", | 
 |       "", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED, | 
 |       HttpAuthHandlerDigest::QOP_UNSPECIFIED | 
 |     }, | 
 |  | 
 |     { // Unknown qop values are ignored. | 
 |       "Digest nonce=\"xyz\", realm=\"Oblivion\", qop=\"auth,foo\"", | 
 |       true, | 
 |       "Oblivion", | 
 |       "xyz", | 
 |       "", | 
 |       "", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED, | 
 |       HttpAuthHandlerDigest::QOP_AUTH | 
 |     }, | 
 |  | 
 |     { // If auth-int is included with auth, then use auth. | 
 |       "Digest nonce=\"xyz\", realm=\"Oblivion\", qop=\"auth,auth-int\"", | 
 |       true, | 
 |       "Oblivion", | 
 |       "xyz", | 
 |       "", | 
 |       "", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED, | 
 |       HttpAuthHandlerDigest::QOP_AUTH | 
 |     }, | 
 |  | 
 |     { // Opaque parameter parsing should work correctly. | 
 |       "Digest nonce=\"xyz\", realm=\"Thunder Bluff\", opaque=\"foobar\"", | 
 |       true, | 
 |       "Thunder Bluff", | 
 |       "xyz", | 
 |       "", | 
 |       "foobar", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED, | 
 |       HttpAuthHandlerDigest::QOP_UNSPECIFIED | 
 |     }, | 
 |  | 
 |     { // Opaque parameters do not need to be quoted, even though RFC2617 | 
 |       // seems to require it. | 
 |       "Digest nonce=\"xyz\", realm=\"Thunder Bluff\", opaque=foobar", | 
 |       true, | 
 |       "Thunder Bluff", | 
 |       "xyz", | 
 |       "", | 
 |       "foobar", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED, | 
 |       HttpAuthHandlerDigest::QOP_UNSPECIFIED | 
 |     }, | 
 |  | 
 |     { // Domain can be parsed. | 
 |       "Digest nonce=\"xyz\", realm=\"Thunder Bluff\", " | 
 |       "domain=\"http://intranet.example.com/protection\"", | 
 |       true, | 
 |       "Thunder Bluff", | 
 |       "xyz", | 
 |       "http://intranet.example.com/protection", | 
 |       "", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED, | 
 |       HttpAuthHandlerDigest::QOP_UNSPECIFIED | 
 |     }, | 
 |  | 
 |     { // Multiple domains can be parsed. | 
 |       "Digest nonce=\"xyz\", realm=\"Thunder Bluff\", " | 
 |       "domain=\"http://intranet.example.com/protection http://www.google.com\"", | 
 |       true, | 
 |       "Thunder Bluff", | 
 |       "xyz", | 
 |       "http://intranet.example.com/protection http://www.google.com", | 
 |       "", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED, | 
 |       HttpAuthHandlerDigest::QOP_UNSPECIFIED | 
 |     }, | 
 |  | 
 |     { // If a non-Digest scheme is somehow passed in, it should be rejected. | 
 |       "Basic realm=\"foo\"", | 
 |       false, | 
 |       "", | 
 |       "", | 
 |       "", | 
 |       "", | 
 |       false, | 
 |       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED, | 
 |       HttpAuthHandlerDigest::QOP_UNSPECIFIED | 
 |     }, | 
 |   }; | 
 |  | 
 |   GURL origin("http://www.example.com"); | 
 |   scoped_ptr<HttpAuthHandlerDigest::Factory> factory( | 
 |       new HttpAuthHandlerDigest::Factory()); | 
 |   for (size_t i = 0; i < arraysize(tests); ++i) { | 
 |     scoped_ptr<HttpAuthHandler> handler; | 
 |     int rv = factory->CreateAuthHandlerFromString(tests[i].challenge, | 
 |                                                   HttpAuth::AUTH_SERVER, | 
 |                                                   origin, | 
 |                                                   BoundNetLog(), | 
 |                                                   &handler); | 
 |     if (tests[i].parsed_success) { | 
 |       EXPECT_EQ(OK, rv); | 
 |     } else { | 
 |       EXPECT_NE(OK, rv); | 
 |       EXPECT_TRUE(handler.get() == NULL); | 
 |       continue; | 
 |     } | 
 |     ASSERT_TRUE(handler.get() != NULL); | 
 |     HttpAuthHandlerDigest* digest = | 
 |         static_cast<HttpAuthHandlerDigest*>(handler.get()); | 
 |     EXPECT_STREQ(tests[i].parsed_realm, digest->realm_.c_str()); | 
 |     EXPECT_STREQ(tests[i].parsed_nonce, digest->nonce_.c_str()); | 
 |     EXPECT_STREQ(tests[i].parsed_domain, digest->domain_.c_str()); | 
 |     EXPECT_STREQ(tests[i].parsed_opaque, digest->opaque_.c_str()); | 
 |     EXPECT_EQ(tests[i].parsed_stale, digest->stale_); | 
 |     EXPECT_EQ(tests[i].parsed_algorithm, digest->algorithm_); | 
 |     EXPECT_EQ(tests[i].parsed_qop, digest->qop_); | 
 |     EXPECT_TRUE(handler->encrypts_identity()); | 
 |     EXPECT_FALSE(handler->is_connection_based()); | 
 |     EXPECT_TRUE(handler->NeedsIdentity()); | 
 |     EXPECT_FALSE(handler->AllowsDefaultCredentials()); | 
 |   } | 
 | } | 
 |  | 
 | TEST(HttpAuthHandlerDigestTest, AssembleCredentials) { | 
 |   static const struct { | 
 |     const char* req_method; | 
 |     const char* req_path; | 
 |     const char* challenge; | 
 |     const char* username; | 
 |     const char* password; | 
 |     const char* cnonce; | 
 |     int nonce_count; | 
 |     const char* expected_creds; | 
 |   } tests[] = { | 
 |     { // MD5 with username/password | 
 |       "GET", | 
 |       "/test/drealm1", | 
 |  | 
 |       // Challenge | 
 |       "Digest realm=\"DRealm1\", " | 
 |       "nonce=\"claGgoRXBAA=7583377687842fdb7b56ba0555d175baa0b800e3\", " | 
 |       "algorithm=MD5, qop=\"auth\"", | 
 |  | 
 |       "foo", "bar", // username/password | 
 |       "082c875dcb2ca740", // cnonce | 
 |       1, // nc | 
 |  | 
 |       // Authorization | 
 |       "Digest username=\"foo\", realm=\"DRealm1\", " | 
 |       "nonce=\"claGgoRXBAA=7583377687842fdb7b56ba0555d175baa0b800e3\", " | 
 |       "uri=\"/test/drealm1\", algorithm=MD5, " | 
 |       "response=\"bcfaa62f1186a31ff1b474a19a17cf57\", " | 
 |       "qop=auth, nc=00000001, cnonce=\"082c875dcb2ca740\"" | 
 |     }, | 
 |  | 
 |     { // MD5 with username but empty password. username has space in it. | 
 |       "GET", | 
 |       "/test/drealm1/", | 
 |  | 
 |       // Challenge | 
 |       "Digest realm=\"DRealm1\", " | 
 |       "nonce=\"Ure30oRXBAA=7eca98bbf521ac6642820b11b86bd2d9ed7edc70\", " | 
 |       "algorithm=MD5, qop=\"auth\"", | 
 |  | 
 |       "foo bar", "", // Username/password | 
 |       "082c875dcb2ca740", // cnonce | 
 |       1, // nc | 
 |  | 
 |       // Authorization | 
 |       "Digest username=\"foo bar\", realm=\"DRealm1\", " | 
 |       "nonce=\"Ure30oRXBAA=7eca98bbf521ac6642820b11b86bd2d9ed7edc70\", " | 
 |       "uri=\"/test/drealm1/\", algorithm=MD5, " | 
 |       "response=\"93c9c6d5930af3b0eb26c745e02b04a0\", " | 
 |       "qop=auth, nc=00000001, cnonce=\"082c875dcb2ca740\"" | 
 |     }, | 
 |  | 
 |     { // MD5 with no username. | 
 |       "GET", | 
 |       "/test/drealm1/", | 
 |  | 
 |       // Challenge | 
 |       "Digest realm=\"DRealm1\", " | 
 |       "nonce=\"7thGplhaBAA=41fb92453c49799cf353c8cd0aabee02d61a98a8\", " | 
 |       "algorithm=MD5, qop=\"auth\"", | 
 |  | 
 |       "", "pass", // Username/password | 
 |       "6509bc74daed8263", // cnonce | 
 |       1, // nc | 
 |  | 
 |       // Authorization | 
 |       "Digest username=\"\", realm=\"DRealm1\", " | 
 |       "nonce=\"7thGplhaBAA=41fb92453c49799cf353c8cd0aabee02d61a98a8\", " | 
 |       "uri=\"/test/drealm1/\", algorithm=MD5, " | 
 |       "response=\"bc597110f41a62d07f8b70b6977fcb61\", " | 
 |       "qop=auth, nc=00000001, cnonce=\"6509bc74daed8263\"" | 
 |     }, | 
 |  | 
 |     { // MD5 with no username and no password. | 
 |       "GET", | 
 |       "/test/drealm1/", | 
 |  | 
 |       // Challenge | 
 |       "Digest realm=\"DRealm1\", " | 
 |       "nonce=\"s3MzvFhaBAA=4c520af5acd9d8d7ae26947529d18c8eae1e98f4\", " | 
 |       "algorithm=MD5, qop=\"auth\"", | 
 |  | 
 |       "", "", // Username/password | 
 |       "1522e61005789929", // cnonce | 
 |       1, // nc | 
 |  | 
 |       // Authorization | 
 |       "Digest username=\"\", realm=\"DRealm1\", " | 
 |       "nonce=\"s3MzvFhaBAA=4c520af5acd9d8d7ae26947529d18c8eae1e98f4\", " | 
 |       "uri=\"/test/drealm1/\", algorithm=MD5, " | 
 |       "response=\"22cfa2b30cb500a9591c6d55ec5590a8\", " | 
 |       "qop=auth, nc=00000001, cnonce=\"1522e61005789929\"" | 
 |     }, | 
 |  | 
 |     { // No algorithm, and no qop. | 
 |       "GET", | 
 |       "/", | 
 |  | 
 |       // Challenge | 
 |       "Digest realm=\"Oblivion\", nonce=\"nonce-value\"", | 
 |  | 
 |       "FooBar", "pass", // Username/password | 
 |       "", // cnonce | 
 |       1, // nc | 
 |  | 
 |       // Authorization | 
 |       "Digest username=\"FooBar\", realm=\"Oblivion\", " | 
 |       "nonce=\"nonce-value\", uri=\"/\", " | 
 |       "response=\"f72ff54ebde2f928860f806ec04acd1b\"" | 
 |     }, | 
 |  | 
 |     { // MD5-sess | 
 |       "GET", | 
 |       "/", | 
 |  | 
 |       // Challenge | 
 |       "Digest realm=\"Baztastic\", nonce=\"AAAAAAAA\", " | 
 |       "algorithm=\"md5-sess\", qop=auth", | 
 |  | 
 |       "USER", "123", // Username/password | 
 |       "15c07961ed8575c4", // cnonce | 
 |       1, // nc | 
 |  | 
 |       // Authorization | 
 |       "Digest username=\"USER\", realm=\"Baztastic\", " | 
 |       "nonce=\"AAAAAAAA\", uri=\"/\", algorithm=MD5-sess, " | 
 |       "response=\"cbc1139821ee7192069580570c541a03\", " | 
 |       "qop=auth, nc=00000001, cnonce=\"15c07961ed8575c4\"" | 
 |     } | 
 |   }; | 
 |   GURL origin("http://www.example.com"); | 
 |   scoped_ptr<HttpAuthHandlerDigest::Factory> factory( | 
 |       new HttpAuthHandlerDigest::Factory()); | 
 |   for (size_t i = 0; i < arraysize(tests); ++i) { | 
 |     scoped_ptr<HttpAuthHandler> handler; | 
 |     int rv = factory->CreateAuthHandlerFromString(tests[i].challenge, | 
 |                                                   HttpAuth::AUTH_SERVER, | 
 |                                                   origin, | 
 |                                                   BoundNetLog(), | 
 |                                                   &handler); | 
 |     EXPECT_EQ(OK, rv); | 
 |     ASSERT_TRUE(handler != NULL); | 
 |  | 
 |     HttpAuthHandlerDigest* digest = | 
 |         static_cast<HttpAuthHandlerDigest*>(handler.get()); | 
 |     std::string creds = | 
 |         digest->AssembleCredentials(tests[i].req_method, | 
 |                                     tests[i].req_path, | 
 |                                     AuthCredentials( | 
 |                                         base::ASCIIToUTF16(tests[i].username), | 
 |                                         base::ASCIIToUTF16(tests[i].password)), | 
 |                                     tests[i].cnonce, | 
 |                                     tests[i].nonce_count); | 
 |  | 
 |     EXPECT_STREQ(tests[i].expected_creds, creds.c_str()); | 
 |   } | 
 | } | 
 |  | 
 | TEST(HttpAuthHandlerDigest, HandleAnotherChallenge) { | 
 |   scoped_ptr<HttpAuthHandlerDigest::Factory> factory( | 
 |       new HttpAuthHandlerDigest::Factory()); | 
 |   scoped_ptr<HttpAuthHandler> handler; | 
 |   std::string default_challenge = | 
 |       "Digest realm=\"Oblivion\", nonce=\"nonce-value\""; | 
 |   GURL origin("intranet.google.com"); | 
 |   int rv = factory->CreateAuthHandlerFromString( | 
 |       default_challenge, HttpAuth::AUTH_SERVER, origin, BoundNetLog(), | 
 |       &handler); | 
 |   EXPECT_EQ(OK, rv); | 
 |   ASSERT_TRUE(handler.get() != NULL); | 
 |   HttpAuthChallengeTokenizer tok_default(default_challenge.begin(), | 
 |                                          default_challenge.end()); | 
 |   EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT, | 
 |             handler->HandleAnotherChallenge(&tok_default)); | 
 |  | 
 |   std::string stale_challenge = default_challenge + ", stale=true"; | 
 |   HttpAuthChallengeTokenizer tok_stale(stale_challenge.begin(), | 
 |                                        stale_challenge.end()); | 
 |   EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_STALE, | 
 |             handler->HandleAnotherChallenge(&tok_stale)); | 
 |  | 
 |   std::string stale_false_challenge = default_challenge + ", stale=false"; | 
 |   HttpAuthChallengeTokenizer tok_stale_false(stale_false_challenge.begin(), | 
 |                                              stale_false_challenge.end()); | 
 |   EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT, | 
 |             handler->HandleAnotherChallenge(&tok_stale_false)); | 
 |  | 
 |   std::string realm_change_challenge = | 
 |       "Digest realm=\"SomethingElse\", nonce=\"nonce-value2\""; | 
 |   HttpAuthChallengeTokenizer tok_realm_change(realm_change_challenge.begin(), | 
 |                                               realm_change_challenge.end()); | 
 |   EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_DIFFERENT_REALM, | 
 |             handler->HandleAnotherChallenge(&tok_realm_change)); | 
 | } | 
 |  | 
 | TEST(HttpAuthHandlerDigest, RespondToServerChallenge) { | 
 |   std::string auth_token; | 
 |   EXPECT_TRUE(RespondToChallenge( | 
 |       HttpAuth::AUTH_SERVER, | 
 |       std::string(), | 
 |       "http://www.example.com/path/to/resource", | 
 |       kSimpleChallenge, | 
 |       &auth_token)); | 
 |   EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", " | 
 |             "nonce=\"nonce-value\", uri=\"/path/to/resource\", " | 
 |             "response=\"6779f90bd0d658f937c1af967614fe84\"", | 
 |             auth_token); | 
 | } | 
 |  | 
 | TEST(HttpAuthHandlerDigest, RespondToHttpsServerChallenge) { | 
 |   std::string auth_token; | 
 |   EXPECT_TRUE(RespondToChallenge( | 
 |       HttpAuth::AUTH_SERVER, | 
 |       std::string(), | 
 |       "https://www.example.com/path/to/resource", | 
 |       kSimpleChallenge, | 
 |       &auth_token)); | 
 |   EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", " | 
 |             "nonce=\"nonce-value\", uri=\"/path/to/resource\", " | 
 |             "response=\"6779f90bd0d658f937c1af967614fe84\"", | 
 |             auth_token); | 
 | } | 
 |  | 
 | TEST(HttpAuthHandlerDigest, RespondToProxyChallenge) { | 
 |   std::string auth_token; | 
 |   EXPECT_TRUE(RespondToChallenge( | 
 |       HttpAuth::AUTH_PROXY, | 
 |       "http://proxy.intranet.corp.com:3128", | 
 |       "http://www.example.com/path/to/resource", | 
 |       kSimpleChallenge, | 
 |       &auth_token)); | 
 |   EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", " | 
 |             "nonce=\"nonce-value\", uri=\"/path/to/resource\", " | 
 |             "response=\"6779f90bd0d658f937c1af967614fe84\"", | 
 |             auth_token); | 
 | } | 
 |  | 
 | TEST(HttpAuthHandlerDigest, RespondToProxyChallengeHttps) { | 
 |   std::string auth_token; | 
 |   EXPECT_TRUE(RespondToChallenge( | 
 |       HttpAuth::AUTH_PROXY, | 
 |       "http://proxy.intranet.corp.com:3128", | 
 |       "https://www.example.com/path/to/resource", | 
 |       kSimpleChallenge, | 
 |       &auth_token)); | 
 |   EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", " | 
 |             "nonce=\"nonce-value\", uri=\"www.example.com:443\", " | 
 |             "response=\"3270da8467afbe9ddf2334a48d46e9b9\"", | 
 |             auth_token); | 
 | } | 
 |  | 
 | TEST(HttpAuthHandlerDigest, RespondToProxyChallengeWs) { | 
 |   std::string auth_token; | 
 |   EXPECT_TRUE(RespondToChallenge( | 
 |       HttpAuth::AUTH_PROXY, | 
 |       "http://proxy.intranet.corp.com:3128", | 
 |       "ws://www.example.com/echo", | 
 |       kSimpleChallenge, | 
 |       &auth_token)); | 
 |   EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", " | 
 |             "nonce=\"nonce-value\", uri=\"www.example.com:80\", " | 
 |             "response=\"aa1df184f68d5b6ab9d9aa4f88e41b4c\"", | 
 |             auth_token); | 
 | } | 
 |  | 
 | TEST(HttpAuthHandlerDigest, RespondToProxyChallengeWss) { | 
 |   std::string auth_token; | 
 |   EXPECT_TRUE(RespondToChallenge( | 
 |       HttpAuth::AUTH_PROXY, | 
 |       "http://proxy.intranet.corp.com:3128", | 
 |       "wss://www.example.com/echo", | 
 |       kSimpleChallenge, | 
 |       &auth_token)); | 
 |   EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", " | 
 |             "nonce=\"nonce-value\", uri=\"www.example.com:443\", " | 
 |             "response=\"3270da8467afbe9ddf2334a48d46e9b9\"", | 
 |             auth_token); | 
 | } | 
 |  | 
 | TEST(HttpAuthHandlerDigest, RespondToChallengeAuthQop) { | 
 |   std::string auth_token; | 
 |   EXPECT_TRUE(RespondToChallenge( | 
 |       HttpAuth::AUTH_SERVER, | 
 |       std::string(), | 
 |       "http://www.example.com/path/to/resource", | 
 |       "Digest realm=\"Oblivion\", nonce=\"nonce-value\", qop=\"auth\"", | 
 |       &auth_token)); | 
 |   EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", " | 
 |             "nonce=\"nonce-value\", uri=\"/path/to/resource\", " | 
 |             "response=\"5b1459beda5cee30d6ff9e970a69c0ea\", " | 
 |             "qop=auth, nc=00000001, cnonce=\"client_nonce\"", | 
 |             auth_token); | 
 | } | 
 |  | 
 | TEST(HttpAuthHandlerDigest, RespondToChallengeOpaque) { | 
 |   std::string auth_token; | 
 |   EXPECT_TRUE(RespondToChallenge( | 
 |       HttpAuth::AUTH_SERVER, | 
 |       std::string(), | 
 |       "http://www.example.com/path/to/resource", | 
 |       "Digest realm=\"Oblivion\", nonce=\"nonce-value\", " | 
 |       "qop=\"auth\", opaque=\"opaque text\"", | 
 |       &auth_token)); | 
 |   EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", " | 
 |             "nonce=\"nonce-value\", uri=\"/path/to/resource\", " | 
 |             "response=\"5b1459beda5cee30d6ff9e970a69c0ea\", " | 
 |             "opaque=\"opaque text\", " | 
 |             "qop=auth, nc=00000001, cnonce=\"client_nonce\"", | 
 |             auth_token); | 
 | } | 
 |  | 
 |  | 
 | } // namespace net |