xref: /aosp_15_r20/external/cronet/net/http/http_auth_handler_negotiate_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 The Chromium Authors
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 <memory>
8 #include <string>
9 
10 #include "base/functional/bind.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/memory/raw_ptr.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/test/scoped_feature_list.h"
16 #include "build/build_config.h"
17 #include "build/chromeos_buildflags.h"
18 #include "net/base/features.h"
19 #include "net/base/net_errors.h"
20 #include "net/base/test_completion_callback.h"
21 #include "net/dns/mock_host_resolver.h"
22 #include "net/http/http_auth_mechanism.h"
23 #include "net/http/http_request_info.h"
24 #include "net/http/mock_allow_http_auth_preferences.h"
25 #include "net/log/net_log_with_source.h"
26 #include "net/net_buildflags.h"
27 #include "net/ssl/ssl_info.h"
28 #include "net/test/gtest_util.h"
29 #include "net/test/test_with_task_environment.h"
30 #include "testing/gmock/include/gmock/gmock.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32 #include "testing/platform_test.h"
33 #include "url/gurl.h"
34 #include "url/scheme_host_port.h"
35 
36 #if !BUILDFLAG(USE_KERBEROS)
37 #error "use_kerberos should be true to use Negotiate authentication scheme."
38 #endif
39 
40 #if BUILDFLAG(IS_ANDROID)
41 #include "net/android/dummy_spnego_authenticator.h"
42 #elif BUILDFLAG(IS_WIN)
43 #include "net/http/mock_sspi_library_win.h"
44 #elif BUILDFLAG(USE_EXTERNAL_GSSAPI)
45 #include "net/http/mock_gssapi_library_posix.h"
46 #else
47 #error "use_kerberos is true, but no Kerberos implementation available."
48 #endif
49 
50 using net::test::IsError;
51 using net::test::IsOk;
52 
53 namespace net {
54 
55 constexpr char kFakeToken[] = "FakeToken";
56 
57 class HttpAuthHandlerNegotiateTest : public PlatformTest,
58                                      public WithTaskEnvironment {
59  public:
SetUp()60   void SetUp() override {
61     scoped_feature_list_.InitAndEnableFeature(
62         features::kSplitHostCacheByNetworkIsolationKey);
63     network_anoymization_key_ = NetworkAnonymizationKey::CreateTransient();
64 #if BUILDFLAG(IS_WIN)
65     auto auth_library =
66         std::make_unique<MockAuthLibrary>(const_cast<wchar_t*>(NEGOSSP_NAME));
67 #else
68     auto auth_library = std::make_unique<MockAuthLibrary>();
69 #endif
70     auth_library_ = auth_library.get();
71     resolver_ = std::make_unique<MockCachingHostResolver>(
72         /*cache_invalidation_num=*/0,
73         /*default_result=*/MockHostResolverBase::RuleResolver::
74             GetLocalhostResult());
75     resolver_->rules()->AddIPLiteralRule("alias", "10.0.0.2",
76                                          "canonical.example.com");
77 
78     http_auth_preferences_ = std::make_unique<MockAllowHttpAuthPreferences>();
79     factory_ = std::make_unique<HttpAuthHandlerNegotiate::Factory>(
80         HttpAuthMechanismFactory());
81     factory_->set_http_auth_preferences(http_auth_preferences_.get());
82 #if BUILDFLAG(IS_ANDROID)
83     auth_library_for_android_ = std::move(auth_library);
84     http_auth_preferences_->set_auth_android_negotiate_account_type(
85         "org.chromium.test.DummySpnegoAuthenticator");
86     MockAuthLibrary::EnsureTestAccountExists();
87 #else
88     factory_->set_library(std::move(auth_library));
89 #endif  // BUILDFLAG(IS_ANDROID)
90   }
91 
92 #if BUILDFLAG(IS_ANDROID)
TearDown()93   void TearDown() override { MockAuthLibrary::RemoveTestAccounts(); }
94 #endif
95 
SetupMocks(MockAuthLibrary * mock_library)96   void SetupMocks(MockAuthLibrary* mock_library) {
97 #if BUILDFLAG(IS_WIN)
98     security_package_ = std::make_unique<SecPkgInfoW>();
99     memset(security_package_.get(), 0x0, sizeof(SecPkgInfoW));
100     security_package_->cbMaxToken = 1337;
101     mock_library->ExpectQuerySecurityPackageInfo(SEC_E_OK,
102                                                  security_package_.get());
103 #else
104     // Copied from an actual transaction!
105     static const char kAuthResponse[] =
106         "\x60\x82\x02\xCA\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x01"
107         "\x00\x6E\x82\x02\xB9\x30\x82\x02\xB5\xA0\x03\x02\x01\x05\xA1\x03"
108         "\x02\x01\x0E\xA2\x07\x03\x05\x00\x00\x00\x00\x00\xA3\x82\x01\xC1"
109         "\x61\x82\x01\xBD\x30\x82\x01\xB9\xA0\x03\x02\x01\x05\xA1\x16\x1B"
110         "\x14\x55\x4E\x49\x58\x2E\x43\x4F\x52\x50\x2E\x47\x4F\x4F\x47\x4C"
111         "\x45\x2E\x43\x4F\x4D\xA2\x2C\x30\x2A\xA0\x03\x02\x01\x01\xA1\x23"
112         "\x30\x21\x1B\x04\x68\x6F\x73\x74\x1B\x19\x6E\x69\x6E\x6A\x61\x2E"
113         "\x63\x61\x6D\x2E\x63\x6F\x72\x70\x2E\x67\x6F\x6F\x67\x6C\x65\x2E"
114         "\x63\x6F\x6D\xA3\x82\x01\x6A\x30\x82\x01\x66\xA0\x03\x02\x01\x10"
115         "\xA1\x03\x02\x01\x01\xA2\x82\x01\x58\x04\x82\x01\x54\x2C\xB1\x2B"
116         "\x0A\xA5\xFF\x6F\xEC\xDE\xB0\x19\x6E\x15\x20\x18\x0C\x42\xB3\x2C"
117         "\x4B\xB0\x37\x02\xDE\xD3\x2F\xB4\xBF\xCA\xEC\x0E\xF9\xF3\x45\x6A"
118         "\x43\xF3\x8D\x79\xBD\xCB\xCD\xB2\x2B\xB8\xFC\xD6\xB4\x7F\x09\x48"
119         "\x14\xA7\x4F\xD2\xEE\xBC\x1B\x2F\x18\x3B\x81\x97\x7B\x28\xA4\xAF"
120         "\xA8\xA3\x7A\x31\x1B\xFC\x97\xB6\xBA\x8A\x50\x50\xD7\x44\xB8\x30"
121         "\xA4\x51\x4C\x3A\x95\x6C\xA1\xED\xE2\xEF\x17\xFE\xAB\xD2\xE4\x70"
122         "\xDE\xEB\x7E\x86\x48\xC5\x3E\x19\x5B\x83\x17\xBB\x52\x26\xC0\xF3"
123         "\x38\x0F\xB0\x8C\x72\xC9\xB0\x8B\x99\x96\x18\xE1\x9E\x67\x9D\xDC"
124         "\xF5\x39\x80\x70\x35\x3F\x98\x72\x16\x44\xA2\xC0\x10\xAA\x70\xBD"
125         "\x06\x6F\x83\xB1\xF4\x67\xA4\xBD\xDA\xF7\x79\x1D\x96\xB5\x7E\xF8"
126         "\xC6\xCF\xB4\xD9\x51\xC9\xBB\xB4\x20\x3C\xDD\xB9\x2C\x38\xEA\x40"
127         "\xFB\x02\x6C\xCB\x48\x71\xE8\xF4\x34\x5B\x63\x5D\x13\x57\xBD\xD1"
128         "\x3D\xDE\xE8\x4A\x51\x6E\xBE\x4C\xF5\xA3\x84\xF7\x4C\x4E\x58\x04"
129         "\xBE\xD1\xCC\x22\xA0\x43\xB0\x65\x99\x6A\xE0\x78\x0D\xFC\xE1\x42"
130         "\xA9\x18\xCF\x55\x4D\x23\xBD\x5C\x0D\xB5\x48\x25\x47\xCC\x01\x54"
131         "\x36\x4D\x0C\x6F\xAC\xCD\x33\x21\xC5\x63\x18\x91\x68\x96\xE9\xD1"
132         "\xD8\x23\x1F\x21\xAE\x96\xA3\xBD\x27\xF7\x4B\xEF\x4C\x43\xFF\xF8"
133         "\x22\x57\xCF\x68\x6C\x35\xD5\x21\x48\x5B\x5F\x8F\xA5\xB9\x6F\x99"
134         "\xA6\xE0\x6E\xF0\xC5\x7C\x91\xC8\x0B\x8A\x4B\x4E\x80\x59\x02\xE9"
135         "\xE8\x3F\x87\x04\xA6\xD1\xCA\x26\x3C\xF0\xDA\x57\xFA\xE6\xAF\x25"
136         "\x43\x34\xE1\xA4\x06\x1A\x1C\xF4\xF5\x21\x9C\x00\x98\xDD\xF0\xB4"
137         "\x8E\xA4\x81\xDA\x30\x81\xD7\xA0\x03\x02\x01\x10\xA2\x81\xCF\x04"
138         "\x81\xCC\x20\x39\x34\x60\x19\xF9\x4C\x26\x36\x46\x99\x7A\xFD\x2B"
139         "\x50\x8B\x2D\x47\x72\x38\x20\x43\x0E\x6E\x28\xB3\xA7\x4F\x26\xF1"
140         "\xF1\x7B\x02\x63\x58\x5A\x7F\xC8\xD0\x6E\xF5\xD1\xDA\x28\x43\x1B"
141         "\x6D\x9F\x59\x64\xDE\x90\xEA\x6C\x8C\xA9\x1B\x1E\x92\x29\x24\x23"
142         "\x2C\xE3\xEA\x64\xEF\x91\xA5\x4E\x94\xE1\xDC\x56\x3A\xAF\xD5\xBC"
143         "\xC9\xD3\x9B\x6B\x1F\xBE\x40\xE5\x40\xFF\x5E\x21\xEA\xCE\xFC\xD5"
144         "\xB0\xE5\xBA\x10\x94\xAE\x16\x54\xFC\xEB\xAB\xF1\xD4\x20\x31\xCC"
145         "\x26\xFE\xBE\xFE\x22\xB6\x9B\x1A\xE5\x55\x2C\x93\xB7\x3B\xD6\x4C"
146         "\x35\x35\xC1\x59\x61\xD4\x1F\x2E\x4C\xE1\x72\x8F\x71\x4B\x0C\x39"
147         "\x80\x79\xFA\xCD\xEA\x71\x1B\xAE\x35\x41\xED\xF9\x65\x0C\x59\xF8"
148         "\xE1\x27\xDA\xD6\xD1\x20\x32\xCD\xBF\xD1\xEF\xE2\xED\xAD\x5D\xA7"
149         "\x69\xE3\x55\xF9\x30\xD3\xD4\x08\xC8\xCA\x62\xF8\x64\xEC\x9B\x92"
150         "\x1A\xF1\x03\x2E\xCC\xDC\xEB\x17\xDE\x09\xAC\xA9\x58\x86";
151     test::GssContextMockImpl context1(
152         "localhost",                         // Source name
153         "example.com",                       // Target name
154         23,                                  // Lifetime
155         *CHROME_GSS_SPNEGO_MECH_OID_DESC,    // Mechanism
156         0,                                   // Context flags
157         1,                                   // Locally initiated
158         0);                                  // Open
159     test::GssContextMockImpl context2(
160         "localhost",                         // Source name
161         "example.com",                       // Target name
162         23,                                  // Lifetime
163         *CHROME_GSS_SPNEGO_MECH_OID_DESC,    // Mechanism
164         0,                                   // Context flags
165         1,                                   // Locally initiated
166         1);                                  // Open
167     MockAuthLibrary::SecurityContextQuery queries[] = {
168         MockAuthLibrary::SecurityContextQuery(
169             "Negotiate",            // Package name
170             GSS_S_CONTINUE_NEEDED,  // Major response code
171             0,                      // Minor response code
172             context1,               // Context
173             nullptr,                // Expected input token
174             kAuthResponse),         // Output token
175         MockAuthLibrary::SecurityContextQuery(
176             "Negotiate",     // Package name
177             GSS_S_COMPLETE,  // Major response code
178             0,               // Minor response code
179             context2,        // Context
180             kAuthResponse,   // Expected input token
181             kAuthResponse)   // Output token
182     };
183 
184     for (const auto& query : queries) {
185       mock_library->ExpectSecurityContext(
186           query.expected_package, query.response_code,
187           query.minor_response_code, query.context_info,
188           query.expected_input_token, query.output_token);
189     }
190 #endif  // BUILDFLAG(IS_WIN)
191   }
192 
193 #if BUILDFLAG(IS_POSIX)
SetupErrorMocks(MockAuthLibrary * mock_library,int major_status,int minor_status)194   void SetupErrorMocks(MockAuthLibrary* mock_library,
195                        int major_status,
196                        int minor_status) {
197     const gss_OID_desc kDefaultMech = {0, nullptr};
198     test::GssContextMockImpl context(
199         "localhost",                    // Source name
200         "example.com",                  // Target name
201         0,                              // Lifetime
202         kDefaultMech,                   // Mechanism
203         0,                              // Context flags
204         1,                              // Locally initiated
205         0);                             // Open
206     MockAuthLibrary::SecurityContextQuery query(
207         "Negotiate",   // Package name
208         major_status,  // Major response code
209         minor_status,  // Minor response code
210         context,       // Context
211         nullptr,       // Expected input token
212         nullptr);      // Output token
213 
214     mock_library->ExpectSecurityContext(query.expected_package,
215                                         query.response_code,
216                                         query.minor_response_code,
217                                         query.context_info,
218                                         query.expected_input_token,
219                                         query.output_token);
220   }
221 #endif  // BUILDFLAG(IS_POSIX)
222 
CreateHandler(bool disable_cname_lookup,bool use_port,bool synchronous_resolve_mode,const std::string & url_string,std::unique_ptr<HttpAuthHandlerNegotiate> * handler)223   int CreateHandler(bool disable_cname_lookup,
224                     bool use_port,
225                     bool synchronous_resolve_mode,
226                     const std::string& url_string,
227                     std::unique_ptr<HttpAuthHandlerNegotiate>* handler) {
228     http_auth_preferences_->set_negotiate_disable_cname_lookup(
229         disable_cname_lookup);
230     http_auth_preferences_->set_negotiate_enable_port(use_port);
231     resolver_->set_synchronous_mode(synchronous_resolve_mode);
232     url::SchemeHostPort scheme_host_port{GURL(url_string)};
233 
234     // Note: This is a little tricky because CreateAuthHandlerFromString
235     // expects a std::unique_ptr<HttpAuthHandler>* rather than a
236     // std::unique_ptr<HttpAuthHandlerNegotiate>*. This needs to do the cast
237     // after creating the handler, and make sure that generic_handler
238     // no longer holds on to the HttpAuthHandlerNegotiate object.
239     std::unique_ptr<HttpAuthHandler> generic_handler;
240     SSLInfo null_ssl_info;
241     int rv = factory_->CreateAuthHandlerFromString(
242         "Negotiate", HttpAuth::AUTH_SERVER, null_ssl_info,
243         network_anonymization_key(), scheme_host_port, NetLogWithSource(),
244         resolver_.get(), &generic_handler);
245     if (rv != OK)
246       return rv;
247     HttpAuthHandlerNegotiate* negotiate_handler =
248         static_cast<HttpAuthHandlerNegotiate*>(generic_handler.release());
249     handler->reset(negotiate_handler);
250     return rv;
251   }
252 
AuthLibrary()253   MockAuthLibrary* AuthLibrary() { return auth_library_; }
resolver()254   MockCachingHostResolver* resolver() { return resolver_.get(); }
http_auth_preferences()255   MockAllowHttpAuthPreferences* http_auth_preferences() {
256     return http_auth_preferences_.get();
257   }
258 
network_anonymization_key() const259   const NetworkAnonymizationKey& network_anonymization_key() const {
260     return network_anoymization_key_;
261   }
262 
263  private:
264   base::test::ScopedFeatureList scoped_feature_list_;
265 
266   NetworkAnonymizationKey network_anoymization_key_;
267 
268 #if BUILDFLAG(IS_WIN)
269   std::unique_ptr<SecPkgInfoW> security_package_;
270 #elif BUILDFLAG(IS_ANDROID)
271   std::unique_ptr<MockAuthLibrary> auth_library_for_android_;
272 #endif
273   std::unique_ptr<MockCachingHostResolver> resolver_;
274   std::unique_ptr<MockAllowHttpAuthPreferences> http_auth_preferences_;
275   std::unique_ptr<HttpAuthHandlerNegotiate::Factory> factory_;
276 
277   // |auth_library_| is passed to |factory_|, which assumes ownership of it, but
278   // can't be a scoped pointer to it since the tests need access when they set
279   // up the mocks after passing ownership.
280   raw_ptr<MockAuthLibrary> auth_library_;
281 };
282 
TEST_F(HttpAuthHandlerNegotiateTest,DisableCname)283 TEST_F(HttpAuthHandlerNegotiateTest, DisableCname) {
284   SetupMocks(AuthLibrary());
285   std::unique_ptr<HttpAuthHandlerNegotiate> auth_handler;
286   EXPECT_EQ(OK, CreateHandler(
287       true, false, true, "http://alias:500", &auth_handler));
288 
289   ASSERT_TRUE(auth_handler.get() != nullptr);
290   TestCompletionCallback callback;
291   HttpRequestInfo request_info;
292   std::string token;
293   EXPECT_EQ(OK, callback.GetResult(auth_handler->GenerateAuthToken(
294                     nullptr, &request_info, callback.callback(), &token)));
295 #if BUILDFLAG(IS_WIN)
296   EXPECT_EQ("HTTP/alias", auth_handler->spn_for_testing());
297 #else
298   EXPECT_EQ("HTTP@alias", auth_handler->spn_for_testing());
299 #endif
300 }
301 
TEST_F(HttpAuthHandlerNegotiateTest,DisableCnameStandardPort)302 TEST_F(HttpAuthHandlerNegotiateTest, DisableCnameStandardPort) {
303   SetupMocks(AuthLibrary());
304   std::unique_ptr<HttpAuthHandlerNegotiate> auth_handler;
305   EXPECT_EQ(OK, CreateHandler(
306       true, true, true, "http://alias:80", &auth_handler));
307   ASSERT_TRUE(auth_handler.get() != nullptr);
308   TestCompletionCallback callback;
309   HttpRequestInfo request_info;
310   std::string token;
311   EXPECT_EQ(OK, callback.GetResult(auth_handler->GenerateAuthToken(
312                     nullptr, &request_info, callback.callback(), &token)));
313 #if BUILDFLAG(IS_WIN)
314   EXPECT_EQ("HTTP/alias", auth_handler->spn_for_testing());
315 #else
316   EXPECT_EQ("HTTP@alias", auth_handler->spn_for_testing());
317 #endif
318 }
319 
TEST_F(HttpAuthHandlerNegotiateTest,DisableCnameNonstandardPort)320 TEST_F(HttpAuthHandlerNegotiateTest, DisableCnameNonstandardPort) {
321   SetupMocks(AuthLibrary());
322   std::unique_ptr<HttpAuthHandlerNegotiate> auth_handler;
323   EXPECT_EQ(OK, CreateHandler(
324       true, true, true, "http://alias:500", &auth_handler));
325   ASSERT_TRUE(auth_handler.get() != nullptr);
326   TestCompletionCallback callback;
327   HttpRequestInfo request_info;
328   std::string token;
329   EXPECT_EQ(OK, callback.GetResult(auth_handler->GenerateAuthToken(
330                     nullptr, &request_info, callback.callback(), &token)));
331 #if BUILDFLAG(IS_WIN)
332   EXPECT_EQ("HTTP/alias:500", auth_handler->spn_for_testing());
333 #else
334   EXPECT_EQ("HTTP@alias:500", auth_handler->spn_for_testing());
335 #endif
336 }
337 
TEST_F(HttpAuthHandlerNegotiateTest,CnameSync)338 TEST_F(HttpAuthHandlerNegotiateTest, CnameSync) {
339   SetupMocks(AuthLibrary());
340   std::unique_ptr<HttpAuthHandlerNegotiate> auth_handler;
341   const std::string url_string = "http://alias:500";
342   EXPECT_EQ(OK, CreateHandler(false, false, true, url_string, &auth_handler));
343   ASSERT_TRUE(auth_handler.get() != nullptr);
344   TestCompletionCallback callback;
345   HttpRequestInfo request_info;
346   std::string token;
347   EXPECT_EQ(OK, callback.GetResult(auth_handler->GenerateAuthToken(
348                     nullptr, &request_info, callback.callback(), &token)));
349 #if BUILDFLAG(IS_WIN)
350   EXPECT_EQ("HTTP/canonical.example.com", auth_handler->spn_for_testing());
351 #else
352   EXPECT_EQ("[email protected]", auth_handler->spn_for_testing());
353 #endif
354 
355   // Make sure a cache-only lookup with the wrong NetworkAnonymizationKey (an
356   // empty one) fails, to make sure the right NetworkAnonymizationKey was used.
357   url::SchemeHostPort scheme_host_port{GURL(url_string)};
358   HostResolver::ResolveHostParameters resolve_params;
359   resolve_params.include_canonical_name = true;
360   resolve_params.source = HostResolverSource::LOCAL_ONLY;
361   std::unique_ptr<HostResolver::ResolveHostRequest> host_request1 =
362       resolver()->CreateRequest(scheme_host_port, NetworkAnonymizationKey(),
363                                 NetLogWithSource(), resolve_params);
364   TestCompletionCallback callback2;
365   int result = host_request1->Start(callback2.callback());
366   EXPECT_EQ(ERR_NAME_NOT_RESOLVED, callback2.GetResult(result));
367 
368   // Make sure a cache-only lookup with the same NetworkAnonymizationKey
369   // succeeds, to make sure the right NetworkAnonymizationKey was used.
370   std::unique_ptr<HostResolver::ResolveHostRequest> host_request2 =
371       resolver()->CreateRequest(scheme_host_port, network_anonymization_key(),
372                                 NetLogWithSource(), resolve_params);
373   TestCompletionCallback callback3;
374   result = host_request2->Start(callback3.callback());
375   EXPECT_EQ(OK, callback3.GetResult(result));
376 }
377 
TEST_F(HttpAuthHandlerNegotiateTest,CnameAsync)378 TEST_F(HttpAuthHandlerNegotiateTest, CnameAsync) {
379   SetupMocks(AuthLibrary());
380   std::unique_ptr<HttpAuthHandlerNegotiate> auth_handler;
381   const std::string url_string = "http://alias:500";
382   EXPECT_EQ(OK, CreateHandler(false, false, false, url_string, &auth_handler));
383   ASSERT_TRUE(auth_handler.get() != nullptr);
384   TestCompletionCallback callback;
385   HttpRequestInfo request_info;
386   std::string token;
387   EXPECT_EQ(ERR_IO_PENDING,
388             auth_handler->GenerateAuthToken(nullptr, &request_info,
389                                             callback.callback(), &token));
390   EXPECT_THAT(callback.WaitForResult(), IsOk());
391 #if BUILDFLAG(IS_WIN)
392   EXPECT_EQ("HTTP/canonical.example.com", auth_handler->spn_for_testing());
393 #else
394   EXPECT_EQ("[email protected]", auth_handler->spn_for_testing());
395 #endif
396 
397   // Make sure a cache-only lookup with the wrong NetworkAnonymizationKey (an
398   // empty one) fails, to make sure the right NetworkAnonymizationKey was used.
399   url::SchemeHostPort scheme_host_port{GURL(url_string)};
400   HostResolver::ResolveHostParameters resolve_params;
401   resolve_params.include_canonical_name = true;
402   resolve_params.source = HostResolverSource::LOCAL_ONLY;
403   std::unique_ptr<HostResolver::ResolveHostRequest> host_request1 =
404       resolver()->CreateRequest(scheme_host_port, NetworkAnonymizationKey(),
405                                 NetLogWithSource(), resolve_params);
406   TestCompletionCallback callback2;
407   int result = host_request1->Start(callback2.callback());
408   EXPECT_EQ(ERR_NAME_NOT_RESOLVED, callback2.GetResult(result));
409 
410   // Make sure a cache-only lookup with the same NetworkAnonymizationKey
411   // succeeds, to make sure the right NetworkAnonymizationKey was used.
412   std::unique_ptr<HostResolver::ResolveHostRequest> host_request2 =
413       resolver()->CreateRequest(scheme_host_port, network_anonymization_key(),
414                                 NetLogWithSource(), resolve_params);
415   TestCompletionCallback callback3;
416   result = host_request2->Start(callback3.callback());
417   EXPECT_EQ(OK, callback3.GetResult(result));
418 }
419 
420 #if BUILDFLAG(IS_POSIX)
421 
422 // This test is only for GSSAPI, as we can't use explicit credentials with
423 // that library.
TEST_F(HttpAuthHandlerNegotiateTest,ServerNotInKerberosDatabase)424 TEST_F(HttpAuthHandlerNegotiateTest, ServerNotInKerberosDatabase) {
425   SetupErrorMocks(AuthLibrary(), GSS_S_FAILURE, 0x96C73A07);  // No server
426   std::unique_ptr<HttpAuthHandlerNegotiate> auth_handler;
427   EXPECT_EQ(OK, CreateHandler(
428       false, false, false, "http://alias:500", &auth_handler));
429   ASSERT_TRUE(auth_handler.get() != nullptr);
430   TestCompletionCallback callback;
431   HttpRequestInfo request_info;
432   std::string token;
433   EXPECT_EQ(ERR_IO_PENDING,
434             auth_handler->GenerateAuthToken(nullptr, &request_info,
435                                             callback.callback(), &token));
436   EXPECT_THAT(callback.WaitForResult(), IsError(ERR_MISSING_AUTH_CREDENTIALS));
437 }
438 
439 // This test is only for GSSAPI, as we can't use explicit credentials with
440 // that library.
TEST_F(HttpAuthHandlerNegotiateTest,NoKerberosCredentials)441 TEST_F(HttpAuthHandlerNegotiateTest, NoKerberosCredentials) {
442   SetupErrorMocks(AuthLibrary(), GSS_S_FAILURE, 0x96C73AC3);  // No credentials
443   std::unique_ptr<HttpAuthHandlerNegotiate> auth_handler;
444   EXPECT_EQ(OK, CreateHandler(
445       false, false, false, "http://alias:500", &auth_handler));
446   ASSERT_TRUE(auth_handler.get() != nullptr);
447   TestCompletionCallback callback;
448   HttpRequestInfo request_info;
449   std::string token;
450   EXPECT_EQ(ERR_IO_PENDING,
451             auth_handler->GenerateAuthToken(nullptr, &request_info,
452                                             callback.callback(), &token));
453   EXPECT_THAT(callback.WaitForResult(), IsError(ERR_MISSING_AUTH_CREDENTIALS));
454 }
455 
456 #if BUILDFLAG(USE_EXTERNAL_GSSAPI)
TEST_F(HttpAuthHandlerNegotiateTest,MissingGSSAPI)457 TEST_F(HttpAuthHandlerNegotiateTest, MissingGSSAPI) {
458   MockAllowHttpAuthPreferences http_auth_preferences;
459   auto negotiate_factory = std::make_unique<HttpAuthHandlerNegotiate::Factory>(
460       HttpAuthMechanismFactory());
461   negotiate_factory->set_http_auth_preferences(&http_auth_preferences);
462   negotiate_factory->set_library(
463       std::make_unique<GSSAPISharedLibrary>("/this/library/does/not/exist"));
464 
465   url::SchemeHostPort scheme_host_port(GURL("http://www.example.com"));
466   std::unique_ptr<HttpAuthHandler> generic_handler;
467   int rv = negotiate_factory->CreateAuthHandlerFromString(
468       "Negotiate", HttpAuth::AUTH_SERVER, SSLInfo(), NetworkAnonymizationKey(),
469       scheme_host_port, NetLogWithSource(), resolver(), &generic_handler);
470   EXPECT_THAT(rv, IsError(ERR_UNSUPPORTED_AUTH_SCHEME));
471   EXPECT_TRUE(generic_handler.get() == nullptr);
472 }
473 #endif  // BUILDFLAG(USE_EXTERNAL_GSSAPI)
474 
475 // AllowGssapiLibraryLoad() is only supported on ChromeOS and Linux.
476 #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
TEST_F(HttpAuthHandlerNegotiateTest,AllowGssapiLibraryLoad)477 TEST_F(HttpAuthHandlerNegotiateTest, AllowGssapiLibraryLoad) {
478   // Disabling allow_gssapi_library_load should prevent handler creation.
479   SetupMocks(AuthLibrary());
480   http_auth_preferences()->set_allow_gssapi_library_load(false);
481   std::unique_ptr<HttpAuthHandlerNegotiate> auth_handler;
482   int rv = CreateHandler(true, false, true, "http://alias:500", &auth_handler);
483   EXPECT_THAT(rv, IsError(ERR_UNSUPPORTED_AUTH_SCHEME));
484   EXPECT_FALSE(auth_handler);
485 
486   // Handler creation can be dynamically re-enabled.
487   http_auth_preferences()->set_allow_gssapi_library_load(true);
488   rv = CreateHandler(true, false, true, "http://alias:500", &auth_handler);
489   EXPECT_EQ(OK, rv);
490   EXPECT_TRUE(auth_handler);
491 }
492 #endif  // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
493 
494 #endif  // BUILDFLAG(IS_POSIX)
495 
496 class TestAuthSystem : public HttpAuthMechanism {
497  public:
498   TestAuthSystem() = default;
499   ~TestAuthSystem() override = default;
500 
501   // HttpAuthMechanism implementation:
Init(const NetLogWithSource &)502   bool Init(const NetLogWithSource&) override { return true; }
NeedsIdentity() const503   bool NeedsIdentity() const override { return true; }
AllowsExplicitCredentials() const504   bool AllowsExplicitCredentials() const override { return true; }
505 
ParseChallenge(net::HttpAuthChallengeTokenizer * tok)506   net::HttpAuth::AuthorizationResult ParseChallenge(
507       net::HttpAuthChallengeTokenizer* tok) override {
508     return net::HttpAuth::AUTHORIZATION_RESULT_ACCEPT;
509   }
510 
GenerateAuthToken(const net::AuthCredentials * credentials,const std::string & spn,const std::string & channel_bindings,std::string * auth_token,const NetLogWithSource & net_log,net::CompletionOnceCallback callback)511   int GenerateAuthToken(const net::AuthCredentials* credentials,
512                         const std::string& spn,
513                         const std::string& channel_bindings,
514                         std::string* auth_token,
515                         const NetLogWithSource& net_log,
516                         net::CompletionOnceCallback callback) override {
517     *auth_token = kFakeToken;
518     return net::OK;
519   }
520 
SetDelegation(HttpAuth::DelegationType delegation_type)521   void SetDelegation(HttpAuth::DelegationType delegation_type) override {}
522 };
523 
TEST_F(HttpAuthHandlerNegotiateTest,OverrideAuthSystem)524 TEST_F(HttpAuthHandlerNegotiateTest, OverrideAuthSystem) {
525   auto negotiate_factory =
526       std::make_unique<HttpAuthHandlerNegotiate::Factory>(base::BindRepeating(
527           [](const HttpAuthPreferences*) -> std::unique_ptr<HttpAuthMechanism> {
528             return std::make_unique<TestAuthSystem>();
529           }));
530   negotiate_factory->set_http_auth_preferences(http_auth_preferences());
531 #if BUILDFLAG(IS_WIN)
532   negotiate_factory->set_library(
533       std::make_unique<MockAuthLibrary>(NEGOSSP_NAME));
534 #elif !BUILDFLAG(IS_ANDROID)
535   negotiate_factory->set_library(std::make_unique<MockAuthLibrary>());
536 #endif
537 
538   url::SchemeHostPort scheme_host_port{GURL("http://www.example.com")};
539   std::unique_ptr<HttpAuthHandler> handler;
540   EXPECT_EQ(OK, negotiate_factory->CreateAuthHandlerFromString(
541                     "Negotiate", HttpAuth::AUTH_SERVER, SSLInfo(),
542                     NetworkAnonymizationKey(), scheme_host_port,
543                     NetLogWithSource(), resolver(), &handler));
544   EXPECT_TRUE(handler);
545 
546   TestCompletionCallback callback;
547   std::string auth_token;
548   HttpRequestInfo request_info;
549   EXPECT_EQ(OK, callback.GetResult(handler->GenerateAuthToken(
550                     nullptr, &request_info, callback.callback(), &auth_token)));
551   EXPECT_EQ(kFakeToken, auth_token);
552 }
553 
554 }  // namespace net
555