Home | History | Annotate | Download | only in http
      1 // Copyright (c) 2006-2008 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 "testing/gtest/include/gtest/gtest.h"
      6 
      7 #include "base/ref_counted.h"
      8 #include "net/http/http_auth.h"
      9 #include "net/http/http_auth_handler.h"
     10 #include "net/http/http_response_headers.h"
     11 #include "net/http/http_util.h"
     12 
     13 namespace net {
     14 
     15 TEST(HttpAuthTest, ChooseBestChallenge) {
     16   static const struct {
     17     const char* headers;
     18     const char* challenge_scheme;
     19     const char* challenge_realm;
     20   } tests[] = {
     21     {
     22       "Y: Digest realm=\"X\", nonce=\"aaaaaaaaaa\"\n"
     23       "www-authenticate: Basic realm=\"BasicRealm\"\n",
     24 
     25       // Basic is the only challenge type, pick it.
     26       "basic",
     27       "BasicRealm",
     28     },
     29     {
     30       "Y: Digest realm=\"FooBar\", nonce=\"aaaaaaaaaa\"\n"
     31       "www-authenticate: Fake realm=\"FooBar\"\n",
     32 
     33       // Fake is the only challenge type, but it is unsupported.
     34       "",
     35       "",
     36     },
     37     {
     38       "www-authenticate: Basic realm=\"FooBar\"\n"
     39       "www-authenticate: Fake realm=\"FooBar\"\n"
     40       "www-authenticate: nonce=\"aaaaaaaaaa\"\n"
     41       "www-authenticate: Digest realm=\"DigestRealm\", nonce=\"aaaaaaaaaa\"\n",
     42 
     43       // Pick Digset over Basic
     44       "digest",
     45       "DigestRealm",
     46     },
     47     {
     48       "Y: Digest realm=\"X\", nonce=\"aaaaaaaaaa\"\n"
     49       "www-authenticate:\n",
     50 
     51       // Handle null header value.
     52       "",
     53       "",
     54     },
     55     {
     56       "WWW-Authenticate: Negotiate\n"
     57       "WWW-Authenticate: NTLM\n",
     58 
     59       // Negotiate is not currently support on non-Windows platforms, so
     60       // the choice varies depending on platform.
     61 #if defined(OS_WIN)
     62       "negotiate",
     63       "",
     64 #else
     65       "ntlm",
     66       "",
     67 #endif
     68     }
     69   };
     70   GURL origin("http://www.example.com");
     71 
     72   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
     73     // Make a HttpResponseHeaders object.
     74     std::string headers_with_status_line("HTTP/1.1 401 Unauthorized\n");
     75     headers_with_status_line += tests[i].headers;
     76     scoped_refptr<net::HttpResponseHeaders> headers(
     77         new net::HttpResponseHeaders(
     78             net::HttpUtil::AssembleRawHeaders(
     79                 headers_with_status_line.c_str(),
     80                 headers_with_status_line.length())));
     81 
     82     scoped_refptr<HttpAuthHandler> handler;
     83     HttpAuth::ChooseBestChallenge(headers.get(),
     84                                   HttpAuth::AUTH_SERVER,
     85                                   origin,
     86                                   &handler);
     87 
     88     if (handler) {
     89       EXPECT_STREQ(tests[i].challenge_scheme, handler->scheme().c_str());
     90       EXPECT_STREQ(tests[i].challenge_realm, handler->realm().c_str());
     91     } else {
     92       EXPECT_STREQ("", tests[i].challenge_scheme);
     93       EXPECT_STREQ("", tests[i].challenge_realm);
     94     }
     95   }
     96 }
     97 
     98 TEST(HttpAuthTest, ChooseBestChallengeConnectionBased) {
     99   static const struct {
    100     const char* headers;
    101     const char* challenge_realm;
    102   } tests[] = {
    103     {
    104       "WWW-Authenticate: NTLM\r\n",
    105 
    106       "",
    107     },
    108     {
    109       "WWW-Authenticate: NTLM "
    110       "TlRMTVNTUAACAAAADAAMADgAAAAFgokCTroKF1e/DRcAAAAAAAAAALo"
    111       "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE"
    112       "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA"
    113       "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy"
    114       "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB"
    115       "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw"
    116       "BtAAAAAAA=\r\n",
    117 
    118       // Realm is empty.
    119       "",
    120     }
    121   };
    122   GURL origin("http://www.example.com");
    123 
    124   scoped_refptr<HttpAuthHandler> handler;
    125   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    126     // Make a HttpResponseHeaders object.
    127     std::string headers_with_status_line("HTTP/1.1 401 Unauthorized\n");
    128     headers_with_status_line += tests[i].headers;
    129     scoped_refptr<net::HttpResponseHeaders> headers(
    130         new net::HttpResponseHeaders(
    131             net::HttpUtil::AssembleRawHeaders(
    132                 headers_with_status_line.c_str(),
    133                 headers_with_status_line.length())));
    134 
    135     scoped_refptr<HttpAuthHandler> old_handler = handler;
    136     HttpAuth::ChooseBestChallenge(headers.get(),
    137                                   HttpAuth::AUTH_SERVER,
    138                                   origin,
    139                                   &handler);
    140 
    141     EXPECT_TRUE(handler != NULL);
    142     // Since NTLM is connection-based, we should continue to use the existing
    143     // handler rather than creating a new one.
    144     if (i != 0)
    145       EXPECT_EQ(old_handler, handler);
    146 
    147     EXPECT_STREQ(tests[i].challenge_realm, handler->realm().c_str());
    148   }
    149 }
    150 
    151 TEST(HttpAuthTest, ChallengeTokenizer) {
    152   std::string challenge_str = "Basic realm=\"foobar\"";
    153   HttpAuth::ChallengeTokenizer challenge(challenge_str.begin(),
    154                                          challenge_str.end());
    155   EXPECT_TRUE(challenge.valid());
    156   EXPECT_EQ(std::string("Basic"), challenge.scheme());
    157   EXPECT_TRUE(challenge.GetNext());
    158   EXPECT_TRUE(challenge.valid());
    159   EXPECT_EQ(std::string("realm"), challenge.name());
    160   EXPECT_EQ(std::string("foobar"), challenge.unquoted_value());
    161   EXPECT_EQ(std::string("\"foobar\""), challenge.value());
    162   EXPECT_TRUE(challenge.value_is_quoted());
    163   EXPECT_FALSE(challenge.GetNext());
    164 }
    165 
    166 // Use a name=value property with no quote marks.
    167 TEST(HttpAuthTest, ChallengeTokenizerNoQuotes) {
    168   std::string challenge_str = "Basic realm=foobar (at) baz.com";
    169   HttpAuth::ChallengeTokenizer challenge(challenge_str.begin(),
    170                                          challenge_str.end());
    171   EXPECT_TRUE(challenge.valid());
    172   EXPECT_EQ(std::string("Basic"), challenge.scheme());
    173   EXPECT_TRUE(challenge.GetNext());
    174   EXPECT_TRUE(challenge.valid());
    175   EXPECT_EQ(std::string("realm"), challenge.name());
    176   EXPECT_EQ(std::string("foobar (at) baz.com"), challenge.value());
    177   EXPECT_EQ(std::string("foobar (at) baz.com"), challenge.unquoted_value());
    178   EXPECT_FALSE(challenge.value_is_quoted());
    179   EXPECT_FALSE(challenge.GetNext());
    180 }
    181 
    182 // Use a name= property which has no value.
    183 TEST(HttpAuthTest, ChallengeTokenizerNoValue) {
    184   std::string challenge_str = "Digest qop=";
    185   HttpAuth::ChallengeTokenizer challenge(
    186       challenge_str.begin(), challenge_str.end());
    187   EXPECT_TRUE(challenge.valid());
    188   EXPECT_EQ(std::string("Digest"), challenge.scheme());
    189   EXPECT_TRUE(challenge.GetNext());
    190   EXPECT_TRUE(challenge.valid());
    191   EXPECT_EQ(std::string("qop"), challenge.name());
    192   EXPECT_EQ(std::string(""), challenge.value());
    193   EXPECT_FALSE(challenge.value_is_quoted());
    194   EXPECT_FALSE(challenge.GetNext());
    195 }
    196 
    197 // Specify multiple properties, comma separated.
    198 TEST(HttpAuthTest, ChallengeTokenizerMultiple) {
    199   std::string challenge_str =
    200       "Digest algorithm=md5, realm=\"Oblivion\", qop=auth-int";
    201   HttpAuth::ChallengeTokenizer challenge(challenge_str.begin(),
    202                                          challenge_str.end());
    203   EXPECT_TRUE(challenge.valid());
    204   EXPECT_EQ(std::string("Digest"), challenge.scheme());
    205   EXPECT_TRUE(challenge.GetNext());
    206   EXPECT_TRUE(challenge.valid());
    207   EXPECT_EQ(std::string("algorithm"), challenge.name());
    208   EXPECT_EQ(std::string("md5"), challenge.value());
    209   EXPECT_FALSE(challenge.value_is_quoted());
    210   EXPECT_TRUE(challenge.GetNext());
    211   EXPECT_TRUE(challenge.valid());
    212   EXPECT_EQ(std::string("realm"), challenge.name());
    213   EXPECT_EQ(std::string("Oblivion"), challenge.unquoted_value());
    214   EXPECT_TRUE(challenge.value_is_quoted());
    215   EXPECT_TRUE(challenge.GetNext());
    216   EXPECT_TRUE(challenge.valid());
    217   EXPECT_EQ(std::string("qop"), challenge.name());
    218   EXPECT_EQ(std::string("auth-int"), challenge.value());
    219   EXPECT_FALSE(challenge.value_is_quoted());
    220   EXPECT_FALSE(challenge.GetNext());
    221 }
    222 
    223 // Use a challenge which has no property.
    224 TEST(HttpAuthTest, ChallengeTokenizerNoProperty) {
    225   std::string challenge_str = "NTLM";
    226   HttpAuth::ChallengeTokenizer challenge(
    227       challenge_str.begin(), challenge_str.end());
    228   EXPECT_TRUE(challenge.valid());
    229   EXPECT_EQ(std::string("NTLM"), challenge.scheme());
    230   EXPECT_FALSE(challenge.GetNext());
    231 }
    232 
    233 TEST(HttpAuthTest, GetChallengeHeaderName) {
    234   std::string name;
    235 
    236   name = HttpAuth::GetChallengeHeaderName(HttpAuth::AUTH_SERVER);
    237   EXPECT_STREQ("WWW-Authenticate", name.c_str());
    238 
    239   name = HttpAuth::GetChallengeHeaderName(HttpAuth::AUTH_PROXY);
    240   EXPECT_STREQ("Proxy-Authenticate", name.c_str());
    241 }
    242 
    243 TEST(HttpAuthTest, GetAuthorizationHeaderName) {
    244   std::string name;
    245 
    246   name = HttpAuth::GetAuthorizationHeaderName(HttpAuth::AUTH_SERVER);
    247   EXPECT_STREQ("Authorization", name.c_str());
    248 
    249   name = HttpAuth::GetAuthorizationHeaderName(HttpAuth::AUTH_PROXY);
    250   EXPECT_STREQ("Proxy-Authorization", name.c_str());
    251 }
    252 
    253 TEST(HttpAuthTest, CreateAuthHandler) {
    254   GURL server_origin("http://www.example.com");
    255   GURL proxy_origin("http://cache.example.com:3128");
    256   {
    257     scoped_refptr<HttpAuthHandler> handler;
    258     HttpAuth::CreateAuthHandler("Basic realm=\"FooBar\"",
    259                                 HttpAuth::AUTH_SERVER,
    260                                 server_origin,
    261                                 &handler);
    262     EXPECT_FALSE(handler.get() == NULL);
    263     EXPECT_STREQ("basic", handler->scheme().c_str());
    264     EXPECT_STREQ("FooBar", handler->realm().c_str());
    265     EXPECT_EQ(HttpAuth::AUTH_SERVER, handler->target());
    266     EXPECT_FALSE(handler->encrypts_identity());
    267     EXPECT_FALSE(handler->is_connection_based());
    268   }
    269   {
    270     scoped_refptr<HttpAuthHandler> handler;
    271     HttpAuth::CreateAuthHandler("UNSUPPORTED realm=\"FooBar\"",
    272                                 HttpAuth::AUTH_SERVER,
    273                                 server_origin,
    274                                 &handler);
    275     EXPECT_TRUE(handler.get() == NULL);
    276   }
    277   {
    278     scoped_refptr<HttpAuthHandler> handler;
    279     HttpAuth::CreateAuthHandler("Digest realm=\"FooBar\", nonce=\"xyz\"",
    280                                 HttpAuth::AUTH_PROXY,
    281                                 proxy_origin,
    282                                 &handler);
    283     EXPECT_FALSE(handler.get() == NULL);
    284     EXPECT_STREQ("digest", handler->scheme().c_str());
    285     EXPECT_STREQ("FooBar", handler->realm().c_str());
    286     EXPECT_EQ(HttpAuth::AUTH_PROXY, handler->target());
    287     EXPECT_TRUE(handler->encrypts_identity());
    288     EXPECT_FALSE(handler->is_connection_based());
    289   }
    290   {
    291     scoped_refptr<HttpAuthHandler> handler;
    292     HttpAuth::CreateAuthHandler("NTLM",
    293                                 HttpAuth::AUTH_SERVER,
    294                                 server_origin,
    295                                 &handler);
    296     EXPECT_FALSE(handler.get() == NULL);
    297     EXPECT_STREQ("ntlm", handler->scheme().c_str());
    298     EXPECT_STREQ("", handler->realm().c_str());
    299     EXPECT_EQ(HttpAuth::AUTH_SERVER, handler->target());
    300     EXPECT_TRUE(handler->encrypts_identity());
    301     EXPECT_TRUE(handler->is_connection_based());
    302   }
    303 }
    304 
    305 }  // namespace net
    306