1 // Copyright (c) 2010 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 "net/http/http_auth_handler_negotiate.h" 6 7 #include "base/string_util.h" 8 #include "base/utf_string_conversions.h" 9 #include "net/base/mock_host_resolver.h" 10 #include "net/base/net_errors.h" 11 #include "net/base/test_completion_callback.h" 12 #include "net/http/http_request_info.h" 13 #include "net/http/mock_allow_url_security_manager.h" 14 #if defined(OS_WIN) 15 #include "net/http/mock_sspi_library_win.h" 16 #elif defined(OS_POSIX) 17 #include "net/http/mock_gssapi_library_posix.h" 18 #include "net/third_party/gssapi/gssapi.h" 19 #endif 20 #include "testing/gtest/include/gtest/gtest.h" 21 #include "testing/platform_test.h" 22 23 #if defined(OS_WIN) 24 typedef net::MockSSPILibrary MockAuthLibrary; 25 #elif defined(OS_POSIX) 26 typedef net::test::MockGSSAPILibrary MockAuthLibrary; 27 #endif 28 29 30 namespace net { 31 32 class HttpAuthHandlerNegotiateTest : public PlatformTest { 33 public: 34 virtual void SetUp() { 35 auth_library_ = new MockAuthLibrary(); 36 resolver_.reset(new MockHostResolver()); 37 resolver_->rules()->AddIPLiteralRule("alias", "10.0.0.2", 38 "canonical.example.com"); 39 40 url_security_manager_.reset(new MockAllowURLSecurityManager()); 41 factory_.reset(new HttpAuthHandlerNegotiate::Factory()); 42 factory_->set_url_security_manager(url_security_manager_.get()); 43 factory_->set_library(auth_library_); 44 factory_->set_host_resolver(resolver_.get()); 45 } 46 47 void SetupMocks(MockAuthLibrary* mock_library) { 48 #if defined(OS_WIN) 49 security_package_.reset(new SecPkgInfoW); 50 memset(security_package_.get(), 0x0, sizeof(SecPkgInfoW)); 51 security_package_->cbMaxToken = 1337; 52 mock_library->ExpectQuerySecurityPackageInfo( 53 L"Negotiate", SEC_E_OK, security_package_.get()); 54 #elif defined(OS_POSIX) 55 // Copied from an actual transaction! 56 static const char kAuthResponse[] = 57 "\x60\x82\x02\xCA\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x01" 58 "\x00\x6E\x82\x02\xB9\x30\x82\x02\xB5\xA0\x03\x02\x01\x05\xA1\x03" 59 "\x02\x01\x0E\xA2\x07\x03\x05\x00\x00\x00\x00\x00\xA3\x82\x01\xC1" 60 "\x61\x82\x01\xBD\x30\x82\x01\xB9\xA0\x03\x02\x01\x05\xA1\x16\x1B" 61 "\x14\x55\x4E\x49\x58\x2E\x43\x4F\x52\x50\x2E\x47\x4F\x4F\x47\x4C" 62 "\x45\x2E\x43\x4F\x4D\xA2\x2C\x30\x2A\xA0\x03\x02\x01\x01\xA1\x23" 63 "\x30\x21\x1B\x04\x68\x6F\x73\x74\x1B\x19\x6E\x69\x6E\x6A\x61\x2E" 64 "\x63\x61\x6D\x2E\x63\x6F\x72\x70\x2E\x67\x6F\x6F\x67\x6C\x65\x2E" 65 "\x63\x6F\x6D\xA3\x82\x01\x6A\x30\x82\x01\x66\xA0\x03\x02\x01\x10" 66 "\xA1\x03\x02\x01\x01\xA2\x82\x01\x58\x04\x82\x01\x54\x2C\xB1\x2B" 67 "\x0A\xA5\xFF\x6F\xEC\xDE\xB0\x19\x6E\x15\x20\x18\x0C\x42\xB3\x2C" 68 "\x4B\xB0\x37\x02\xDE\xD3\x2F\xB4\xBF\xCA\xEC\x0E\xF9\xF3\x45\x6A" 69 "\x43\xF3\x8D\x79\xBD\xCB\xCD\xB2\x2B\xB8\xFC\xD6\xB4\x7F\x09\x48" 70 "\x14\xA7\x4F\xD2\xEE\xBC\x1B\x2F\x18\x3B\x81\x97\x7B\x28\xA4\xAF" 71 "\xA8\xA3\x7A\x31\x1B\xFC\x97\xB6\xBA\x8A\x50\x50\xD7\x44\xB8\x30" 72 "\xA4\x51\x4C\x3A\x95\x6C\xA1\xED\xE2\xEF\x17\xFE\xAB\xD2\xE4\x70" 73 "\xDE\xEB\x7E\x86\x48\xC5\x3E\x19\x5B\x83\x17\xBB\x52\x26\xC0\xF3" 74 "\x38\x0F\xB0\x8C\x72\xC9\xB0\x8B\x99\x96\x18\xE1\x9E\x67\x9D\xDC" 75 "\xF5\x39\x80\x70\x35\x3F\x98\x72\x16\x44\xA2\xC0\x10\xAA\x70\xBD" 76 "\x06\x6F\x83\xB1\xF4\x67\xA4\xBD\xDA\xF7\x79\x1D\x96\xB5\x7E\xF8" 77 "\xC6\xCF\xB4\xD9\x51\xC9\xBB\xB4\x20\x3C\xDD\xB9\x2C\x38\xEA\x40" 78 "\xFB\x02\x6C\xCB\x48\x71\xE8\xF4\x34\x5B\x63\x5D\x13\x57\xBD\xD1" 79 "\x3D\xDE\xE8\x4A\x51\x6E\xBE\x4C\xF5\xA3\x84\xF7\x4C\x4E\x58\x04" 80 "\xBE\xD1\xCC\x22\xA0\x43\xB0\x65\x99\x6A\xE0\x78\x0D\xFC\xE1\x42" 81 "\xA9\x18\xCF\x55\x4D\x23\xBD\x5C\x0D\xB5\x48\x25\x47\xCC\x01\x54" 82 "\x36\x4D\x0C\x6F\xAC\xCD\x33\x21\xC5\x63\x18\x91\x68\x96\xE9\xD1" 83 "\xD8\x23\x1F\x21\xAE\x96\xA3\xBD\x27\xF7\x4B\xEF\x4C\x43\xFF\xF8" 84 "\x22\x57\xCF\x68\x6C\x35\xD5\x21\x48\x5B\x5F\x8F\xA5\xB9\x6F\x99" 85 "\xA6\xE0\x6E\xF0\xC5\x7C\x91\xC8\x0B\x8A\x4B\x4E\x80\x59\x02\xE9" 86 "\xE8\x3F\x87\x04\xA6\xD1\xCA\x26\x3C\xF0\xDA\x57\xFA\xE6\xAF\x25" 87 "\x43\x34\xE1\xA4\x06\x1A\x1C\xF4\xF5\x21\x9C\x00\x98\xDD\xF0\xB4" 88 "\x8E\xA4\x81\xDA\x30\x81\xD7\xA0\x03\x02\x01\x10\xA2\x81\xCF\x04" 89 "\x81\xCC\x20\x39\x34\x60\x19\xF9\x4C\x26\x36\x46\x99\x7A\xFD\x2B" 90 "\x50\x8B\x2D\x47\x72\x38\x20\x43\x0E\x6E\x28\xB3\xA7\x4F\x26\xF1" 91 "\xF1\x7B\x02\x63\x58\x5A\x7F\xC8\xD0\x6E\xF5\xD1\xDA\x28\x43\x1B" 92 "\x6D\x9F\x59\x64\xDE\x90\xEA\x6C\x8C\xA9\x1B\x1E\x92\x29\x24\x23" 93 "\x2C\xE3\xEA\x64\xEF\x91\xA5\x4E\x94\xE1\xDC\x56\x3A\xAF\xD5\xBC" 94 "\xC9\xD3\x9B\x6B\x1F\xBE\x40\xE5\x40\xFF\x5E\x21\xEA\xCE\xFC\xD5" 95 "\xB0\xE5\xBA\x10\x94\xAE\x16\x54\xFC\xEB\xAB\xF1\xD4\x20\x31\xCC" 96 "\x26\xFE\xBE\xFE\x22\xB6\x9B\x1A\xE5\x55\x2C\x93\xB7\x3B\xD6\x4C" 97 "\x35\x35\xC1\x59\x61\xD4\x1F\x2E\x4C\xE1\x72\x8F\x71\x4B\x0C\x39" 98 "\x80\x79\xFA\xCD\xEA\x71\x1B\xAE\x35\x41\xED\xF9\x65\x0C\x59\xF8" 99 "\xE1\x27\xDA\xD6\xD1\x20\x32\xCD\xBF\xD1\xEF\xE2\xED\xAD\x5D\xA7" 100 "\x69\xE3\x55\xF9\x30\xD3\xD4\x08\xC8\xCA\x62\xF8\x64\xEC\x9B\x92" 101 "\x1A\xF1\x03\x2E\xCC\xDC\xEB\x17\xDE\x09\xAC\xA9\x58\x86"; 102 test::GssContextMockImpl context1( 103 "localhost", // Source name 104 "example.com", // Target name 105 23, // Lifetime 106 *GSS_C_NT_HOSTBASED_SERVICE, // Mechanism 107 0, // Context flags 108 1, // Locally initiated 109 0); // Open 110 test::GssContextMockImpl context2( 111 "localhost", // Source name 112 "example.com", // Target name 113 23, // Lifetime 114 *GSS_C_NT_HOSTBASED_SERVICE, // Mechanism 115 0, // Context flags 116 1, // Locally initiated 117 1); // Open 118 test::MockGSSAPILibrary::SecurityContextQuery queries[] = { 119 test::MockGSSAPILibrary::SecurityContextQuery( 120 "Negotiate", // Package name 121 GSS_S_CONTINUE_NEEDED, // Major response code 122 0, // Minor response code 123 context1, // Context 124 NULL, // Expected input token 125 kAuthResponse), // Output token 126 test::MockGSSAPILibrary::SecurityContextQuery( 127 "Negotiate", // Package name 128 GSS_S_COMPLETE, // Major response code 129 0, // Minor response code 130 context2, // Context 131 kAuthResponse, // Expected input token 132 kAuthResponse) // Output token 133 }; 134 135 for (size_t i = 0; i < arraysize(queries); ++i) { 136 mock_library->ExpectSecurityContext(queries[i].expected_package, 137 queries[i].response_code, 138 queries[i].minor_response_code, 139 queries[i].context_info, 140 queries[i].expected_input_token, 141 queries[i].output_token); 142 } 143 #endif // defined(OS_POSIX) 144 } 145 146 #if defined(OS_POSIX) 147 void SetupErrorMocks(MockAuthLibrary* mock_library, 148 int major_status, 149 int minor_status) { 150 const gss_OID_desc kDefaultMech = { 0, NULL }; 151 test::GssContextMockImpl context( 152 "localhost", // Source name 153 "example.com", // Target name 154 0, // Lifetime 155 kDefaultMech, // Mechanism 156 0, // Context flags 157 1, // Locally initiated 158 0); // Open 159 test::MockGSSAPILibrary::SecurityContextQuery query( 160 "Negotiate", // Package name 161 major_status, // Major response code 162 minor_status, // Minor response code 163 context, // Context 164 NULL, // Expected input token 165 NULL); // Output token 166 167 mock_library->ExpectSecurityContext(query.expected_package, 168 query.response_code, 169 query.minor_response_code, 170 query.context_info, 171 query.expected_input_token, 172 query.output_token); 173 } 174 175 #endif // defined(OS_POSIX) 176 177 int CreateHandler(bool disable_cname_lookup, bool use_port, 178 bool synchronous_resolve_mode, 179 const std::string& url_string, 180 scoped_ptr<HttpAuthHandlerNegotiate>* handler) { 181 factory_->set_disable_cname_lookup(disable_cname_lookup); 182 factory_->set_use_port(use_port); 183 resolver_->set_synchronous_mode(synchronous_resolve_mode); 184 GURL gurl(url_string); 185 186 // Note: This is a little tricky because CreateAuthHandlerFromString 187 // expects a scoped_ptr<HttpAuthHandler>* rather than a 188 // scoped_ptr<HttpAuthHandlerNegotiate>*. This needs to do the cast 189 // after creating the handler, and make sure that generic_handler 190 // no longer holds on to the HttpAuthHandlerNegotiate object. 191 scoped_ptr<HttpAuthHandler> generic_handler; 192 int rv = factory_->CreateAuthHandlerFromString("Negotiate", 193 HttpAuth::AUTH_SERVER, 194 gurl, 195 BoundNetLog(), 196 &generic_handler); 197 if (rv != OK) 198 return rv; 199 HttpAuthHandlerNegotiate* negotiate_handler = 200 static_cast<HttpAuthHandlerNegotiate*>(generic_handler.release()); 201 handler->reset(negotiate_handler); 202 return rv; 203 } 204 205 MockAuthLibrary* AuthLibrary() { return auth_library_; } 206 207 private: 208 #if defined(OS_WIN) 209 scoped_ptr<SecPkgInfoW> security_package_; 210 #endif 211 // |auth_library_| is passed to |factory_|, which assumes ownership of it. 212 MockAuthLibrary* auth_library_; 213 scoped_ptr<MockHostResolver> resolver_; 214 scoped_ptr<URLSecurityManager> url_security_manager_; 215 scoped_ptr<HttpAuthHandlerNegotiate::Factory> factory_; 216 }; 217 218 TEST_F(HttpAuthHandlerNegotiateTest, DisableCname) { 219 SetupMocks(AuthLibrary()); 220 scoped_ptr<HttpAuthHandlerNegotiate> auth_handler; 221 EXPECT_EQ(OK, CreateHandler( 222 true, false, true, "http://alias:500", &auth_handler)); 223 224 ASSERT_TRUE(auth_handler.get() != NULL); 225 TestCompletionCallback callback; 226 HttpRequestInfo request_info; 227 std::string token; 228 EXPECT_EQ(OK, auth_handler->GenerateAuthToken(NULL, NULL, 229 &request_info, 230 &callback, &token)); 231 #if defined(OS_WIN) 232 EXPECT_EQ(L"HTTP/alias", auth_handler->spn()); 233 #elif defined(OS_POSIX) 234 EXPECT_EQ(L"HTTP@alias", auth_handler->spn()); 235 #endif 236 } 237 238 TEST_F(HttpAuthHandlerNegotiateTest, DisableCnameStandardPort) { 239 SetupMocks(AuthLibrary()); 240 scoped_ptr<HttpAuthHandlerNegotiate> auth_handler; 241 EXPECT_EQ(OK, CreateHandler( 242 true, true, true, "http://alias:80", &auth_handler)); 243 ASSERT_TRUE(auth_handler.get() != NULL); 244 TestCompletionCallback callback; 245 HttpRequestInfo request_info; 246 std::string token; 247 EXPECT_EQ(OK, auth_handler->GenerateAuthToken(NULL, NULL, 248 &request_info, 249 &callback, &token)); 250 #if defined(OS_WIN) 251 EXPECT_EQ(L"HTTP/alias", auth_handler->spn()); 252 #elif defined(OS_POSIX) 253 EXPECT_EQ(L"HTTP@alias", auth_handler->spn()); 254 #endif 255 } 256 257 TEST_F(HttpAuthHandlerNegotiateTest, DisableCnameNonstandardPort) { 258 SetupMocks(AuthLibrary()); 259 scoped_ptr<HttpAuthHandlerNegotiate> auth_handler; 260 EXPECT_EQ(OK, CreateHandler( 261 true, true, true, "http://alias:500", &auth_handler)); 262 ASSERT_TRUE(auth_handler.get() != NULL); 263 TestCompletionCallback callback; 264 HttpRequestInfo request_info; 265 std::string token; 266 EXPECT_EQ(OK, auth_handler->GenerateAuthToken(NULL, NULL, 267 &request_info, 268 &callback, &token)); 269 #if defined(OS_WIN) 270 EXPECT_EQ(L"HTTP/alias:500", auth_handler->spn()); 271 #elif defined(OS_POSIX) 272 EXPECT_EQ(L"HTTP@alias:500", auth_handler->spn()); 273 #endif 274 } 275 276 TEST_F(HttpAuthHandlerNegotiateTest, CnameSync) { 277 SetupMocks(AuthLibrary()); 278 scoped_ptr<HttpAuthHandlerNegotiate> auth_handler; 279 EXPECT_EQ(OK, CreateHandler( 280 false, false, true, "http://alias:500", &auth_handler)); 281 ASSERT_TRUE(auth_handler.get() != NULL); 282 TestCompletionCallback callback; 283 HttpRequestInfo request_info; 284 std::string token; 285 EXPECT_EQ(OK, auth_handler->GenerateAuthToken(NULL, NULL, 286 &request_info, 287 &callback, &token)); 288 #if defined(OS_WIN) 289 EXPECT_EQ(L"HTTP/canonical.example.com", auth_handler->spn()); 290 #elif defined(OS_POSIX) 291 EXPECT_EQ(L"HTTP (at) canonical.example.com", auth_handler->spn()); 292 #endif 293 } 294 295 TEST_F(HttpAuthHandlerNegotiateTest, CnameAsync) { 296 SetupMocks(AuthLibrary()); 297 scoped_ptr<HttpAuthHandlerNegotiate> auth_handler; 298 EXPECT_EQ(OK, CreateHandler( 299 false, false, false, "http://alias:500", &auth_handler)); 300 ASSERT_TRUE(auth_handler.get() != NULL); 301 TestCompletionCallback callback; 302 HttpRequestInfo request_info; 303 std::string token; 304 EXPECT_EQ(ERR_IO_PENDING, auth_handler->GenerateAuthToken( 305 NULL, NULL, &request_info, &callback, &token)); 306 EXPECT_EQ(OK, callback.WaitForResult()); 307 #if defined(OS_WIN) 308 EXPECT_EQ(L"HTTP/canonical.example.com", auth_handler->spn()); 309 #elif defined(OS_POSIX) 310 EXPECT_EQ(L"HTTP (at) canonical.example.com", auth_handler->spn()); 311 #endif 312 } 313 314 #if defined(OS_POSIX) 315 316 // These tests are only for GSSAPI, as we can't use explicit credentials with 317 // that library. 318 319 TEST_F(HttpAuthHandlerNegotiateTest, ServerNotInKerberosDatabase) { 320 SetupErrorMocks(AuthLibrary(), GSS_S_FAILURE, 0x96C73A07); // No server 321 scoped_ptr<HttpAuthHandlerNegotiate> auth_handler; 322 EXPECT_EQ(OK, CreateHandler( 323 false, false, false, "http://alias:500", &auth_handler)); 324 ASSERT_TRUE(auth_handler.get() != NULL); 325 TestCompletionCallback callback; 326 HttpRequestInfo request_info; 327 std::string token; 328 EXPECT_EQ(ERR_IO_PENDING, auth_handler->GenerateAuthToken( 329 NULL, NULL, &request_info, &callback, &token)); 330 EXPECT_EQ(ERR_MISSING_AUTH_CREDENTIALS, callback.WaitForResult()); 331 } 332 333 TEST_F(HttpAuthHandlerNegotiateTest, NoKerberosCredentials) { 334 SetupErrorMocks(AuthLibrary(), GSS_S_FAILURE, 0x96C73AC3); // No credentials 335 scoped_ptr<HttpAuthHandlerNegotiate> auth_handler; 336 EXPECT_EQ(OK, CreateHandler( 337 false, false, false, "http://alias:500", &auth_handler)); 338 ASSERT_TRUE(auth_handler.get() != NULL); 339 TestCompletionCallback callback; 340 HttpRequestInfo request_info; 341 std::string token; 342 EXPECT_EQ(ERR_IO_PENDING, auth_handler->GenerateAuthToken( 343 NULL, NULL, &request_info, &callback, &token)); 344 EXPECT_EQ(ERR_MISSING_AUTH_CREDENTIALS, callback.WaitForResult()); 345 } 346 347 #endif // defined(OS_POSIX) 348 349 } // namespace net 350