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