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