http_auth_handler_factory_unittest.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. // Copyright (c) 2011 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. #include "net/http/http_auth_handler_factory.h"
  5. #include <memory>
  6. #include "base/bind.h"
  7. #include "base/callback.h"
  8. #include "build/build_config.h"
  9. #include "net/base/net_errors.h"
  10. #include "net/base/network_isolation_key.h"
  11. #include "net/dns/host_resolver.h"
  12. #include "net/dns/mock_host_resolver.h"
  13. #include "net/http/http_auth_handler.h"
  14. #include "net/http/http_auth_scheme.h"
  15. #include "net/http/mock_allow_http_auth_preferences.h"
  16. #include "net/http/url_security_manager.h"
  17. #include "net/log/net_log_values.h"
  18. #include "net/log/net_log_with_source.h"
  19. #include "net/log/test_net_log.h"
  20. #include "net/net_buildflags.h"
  21. #include "net/ssl/ssl_info.h"
  22. #include "net/test/gtest_util.h"
  23. #include "testing/gmock/include/gmock/gmock.h"
  24. #include "testing/gtest/include/gtest/gtest.h"
  25. #include "url/gurl.h"
  26. #include "url/scheme_host_port.h"
  27. using net::test::IsError;
  28. using net::test::IsOk;
  29. namespace net {
  30. namespace {
  31. class MockHttpAuthHandlerFactory : public HttpAuthHandlerFactory {
  32. public:
  33. explicit MockHttpAuthHandlerFactory(int return_code) :
  34. return_code_(return_code) {}
  35. ~MockHttpAuthHandlerFactory() override = default;
  36. int CreateAuthHandler(HttpAuthChallengeTokenizer* challenge,
  37. HttpAuth::Target target,
  38. const SSLInfo& ssl_info,
  39. const NetworkIsolationKey& network_isolation_key,
  40. const url::SchemeHostPort& scheme_host_port,
  41. CreateReason reason,
  42. int nonce_count,
  43. const NetLogWithSource& net_log,
  44. HostResolver* host_resolver,
  45. std::unique_ptr<HttpAuthHandler>* handler) override {
  46. handler->reset();
  47. return return_code_;
  48. }
  49. private:
  50. int return_code_;
  51. };
  52. } // namespace
  53. TEST(HttpAuthHandlerFactoryTest, RegistryFactory) {
  54. SSLInfo null_ssl_info;
  55. HttpAuthHandlerRegistryFactory registry_factory(
  56. /*http_auth_preferences=*/nullptr);
  57. url::SchemeHostPort scheme_host_port(GURL("https://www.google.com"));
  58. const int kBasicReturnCode = -1;
  59. auto mock_factory_basic =
  60. std::make_unique<MockHttpAuthHandlerFactory>(kBasicReturnCode);
  61. const int kDigestReturnCode = -2;
  62. auto mock_factory_digest =
  63. std::make_unique<MockHttpAuthHandlerFactory>(kDigestReturnCode);
  64. const int kDigestReturnCodeReplace = -3;
  65. auto mock_factory_digest_replace =
  66. std::make_unique<MockHttpAuthHandlerFactory>(kDigestReturnCodeReplace);
  67. auto host_resovler = std::make_unique<MockHostResolver>();
  68. std::unique_ptr<HttpAuthHandler> handler;
  69. // No schemes should be supported in the beginning.
  70. EXPECT_EQ(
  71. ERR_UNSUPPORTED_AUTH_SCHEME,
  72. registry_factory.CreateAuthHandlerFromString(
  73. "Basic", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(),
  74. scheme_host_port, NetLogWithSource(), host_resovler.get(), &handler));
  75. // Test what happens with a single scheme.
  76. registry_factory.RegisterSchemeFactory("Basic",
  77. std::move(mock_factory_basic));
  78. EXPECT_EQ(
  79. kBasicReturnCode,
  80. registry_factory.CreateAuthHandlerFromString(
  81. "Basic", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(),
  82. scheme_host_port, NetLogWithSource(), host_resovler.get(), &handler));
  83. EXPECT_EQ(
  84. ERR_UNSUPPORTED_AUTH_SCHEME,
  85. registry_factory.CreateAuthHandlerFromString(
  86. "Digest", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(),
  87. scheme_host_port, NetLogWithSource(), host_resovler.get(), &handler));
  88. // Test multiple schemes
  89. registry_factory.RegisterSchemeFactory("Digest",
  90. std::move(mock_factory_digest));
  91. EXPECT_EQ(
  92. kBasicReturnCode,
  93. registry_factory.CreateAuthHandlerFromString(
  94. "Basic", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(),
  95. scheme_host_port, NetLogWithSource(), host_resovler.get(), &handler));
  96. EXPECT_EQ(
  97. kDigestReturnCode,
  98. registry_factory.CreateAuthHandlerFromString(
  99. "Digest", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(),
  100. scheme_host_port, NetLogWithSource(), host_resovler.get(), &handler));
  101. // Test case-insensitivity
  102. EXPECT_EQ(
  103. kBasicReturnCode,
  104. registry_factory.CreateAuthHandlerFromString(
  105. "basic", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(),
  106. scheme_host_port, NetLogWithSource(), host_resovler.get(), &handler));
  107. // Test replacement of existing auth scheme
  108. registry_factory.RegisterSchemeFactory(
  109. "Digest", std::move(mock_factory_digest_replace));
  110. EXPECT_EQ(
  111. kBasicReturnCode,
  112. registry_factory.CreateAuthHandlerFromString(
  113. "Basic", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(),
  114. scheme_host_port, NetLogWithSource(), host_resovler.get(), &handler));
  115. EXPECT_EQ(
  116. kDigestReturnCodeReplace,
  117. registry_factory.CreateAuthHandlerFromString(
  118. "Digest", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(),
  119. scheme_host_port, NetLogWithSource(), host_resovler.get(), &handler));
  120. }
  121. TEST(HttpAuthHandlerFactoryTest, DefaultFactory) {
  122. auto host_resolver = std::make_unique<MockHostResolver>();
  123. MockAllowHttpAuthPreferences http_auth_preferences;
  124. std::unique_ptr<HttpAuthHandlerRegistryFactory> http_auth_handler_factory(
  125. HttpAuthHandlerFactory::CreateDefault());
  126. http_auth_handler_factory->SetHttpAuthPreferences(kNegotiateAuthScheme,
  127. &http_auth_preferences);
  128. url::SchemeHostPort server_scheme_host_port(GURL("http://www.example.com"));
  129. url::SchemeHostPort proxy_scheme_host_port(
  130. GURL("http://cache.example.com:3128"));
  131. SSLInfo null_ssl_info;
  132. {
  133. std::unique_ptr<HttpAuthHandler> handler;
  134. int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
  135. "Basic realm=\"FooBar\"", HttpAuth::AUTH_SERVER, null_ssl_info,
  136. NetworkIsolationKey(), server_scheme_host_port, NetLogWithSource(),
  137. host_resolver.get(), &handler);
  138. EXPECT_THAT(rv, IsOk());
  139. ASSERT_FALSE(handler.get() == nullptr);
  140. EXPECT_EQ(HttpAuth::AUTH_SCHEME_BASIC, handler->auth_scheme());
  141. EXPECT_STREQ("FooBar", handler->realm().c_str());
  142. EXPECT_EQ(HttpAuth::AUTH_SERVER, handler->target());
  143. EXPECT_FALSE(handler->encrypts_identity());
  144. EXPECT_FALSE(handler->is_connection_based());
  145. }
  146. {
  147. std::unique_ptr<HttpAuthHandler> handler;
  148. int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
  149. "UNSUPPORTED realm=\"FooBar\"", HttpAuth::AUTH_SERVER, null_ssl_info,
  150. NetworkIsolationKey(), server_scheme_host_port, NetLogWithSource(),
  151. host_resolver.get(), &handler);
  152. EXPECT_THAT(rv, IsError(ERR_UNSUPPORTED_AUTH_SCHEME));
  153. EXPECT_TRUE(handler.get() == nullptr);
  154. }
  155. {
  156. std::unique_ptr<HttpAuthHandler> handler;
  157. int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
  158. "Digest realm=\"FooBar\", nonce=\"xyz\"", HttpAuth::AUTH_PROXY,
  159. null_ssl_info, NetworkIsolationKey(), proxy_scheme_host_port,
  160. NetLogWithSource(), host_resolver.get(), &handler);
  161. EXPECT_THAT(rv, IsOk());
  162. ASSERT_FALSE(handler.get() == nullptr);
  163. EXPECT_EQ(HttpAuth::AUTH_SCHEME_DIGEST, handler->auth_scheme());
  164. EXPECT_STREQ("FooBar", handler->realm().c_str());
  165. EXPECT_EQ(HttpAuth::AUTH_PROXY, handler->target());
  166. EXPECT_TRUE(handler->encrypts_identity());
  167. EXPECT_FALSE(handler->is_connection_based());
  168. }
  169. {
  170. std::unique_ptr<HttpAuthHandler> handler;
  171. int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
  172. "NTLM", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(),
  173. server_scheme_host_port, NetLogWithSource(), host_resolver.get(),
  174. &handler);
  175. EXPECT_THAT(rv, IsOk());
  176. ASSERT_FALSE(handler.get() == nullptr);
  177. EXPECT_EQ(HttpAuth::AUTH_SCHEME_NTLM, handler->auth_scheme());
  178. EXPECT_STREQ("", handler->realm().c_str());
  179. EXPECT_EQ(HttpAuth::AUTH_SERVER, handler->target());
  180. EXPECT_TRUE(handler->encrypts_identity());
  181. EXPECT_TRUE(handler->is_connection_based());
  182. }
  183. {
  184. std::unique_ptr<HttpAuthHandler> handler;
  185. int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
  186. "Negotiate", HttpAuth::AUTH_SERVER, null_ssl_info,
  187. NetworkIsolationKey(), server_scheme_host_port, NetLogWithSource(),
  188. host_resolver.get(), &handler);
  189. // Note the default factory doesn't support Kerberos on Android
  190. #if BUILDFLAG(USE_KERBEROS) && !BUILDFLAG(IS_ANDROID)
  191. EXPECT_THAT(rv, IsOk());
  192. ASSERT_FALSE(handler.get() == nullptr);
  193. EXPECT_EQ(HttpAuth::AUTH_SCHEME_NEGOTIATE, handler->auth_scheme());
  194. EXPECT_STREQ("", handler->realm().c_str());
  195. EXPECT_EQ(HttpAuth::AUTH_SERVER, handler->target());
  196. EXPECT_TRUE(handler->encrypts_identity());
  197. EXPECT_TRUE(handler->is_connection_based());
  198. #else
  199. EXPECT_THAT(rv, IsError(ERR_UNSUPPORTED_AUTH_SCHEME));
  200. EXPECT_TRUE(handler.get() == nullptr);
  201. #endif // BUILDFLAG(USE_KERBEROS) && !BUILDFLAG(IS_ANDROID)
  202. }
  203. }
  204. TEST(HttpAuthHandlerFactoryTest, HttpAuthUrlFilter) {
  205. auto host_resolver = std::make_unique<MockHostResolver>();
  206. MockAllowHttpAuthPreferences http_auth_preferences;
  207. // Set the Preference that blocks Basic Auth over HTTP on all of the
  208. // factories. It shouldn't impact any behavior except for the Basic factory.
  209. http_auth_preferences.set_basic_over_http_enabled(false);
  210. // Set the preference that only allows "https://www.example.com" to use HTTP
  211. // auth.
  212. http_auth_preferences.set_http_auth_scheme_filter(
  213. base::BindRepeating([](const url::SchemeHostPort& scheme_host_port) {
  214. return scheme_host_port ==
  215. url::SchemeHostPort(GURL("https://www.example.com"));
  216. }));
  217. std::unique_ptr<HttpAuthHandlerRegistryFactory> http_auth_handler_factory(
  218. HttpAuthHandlerFactory::CreateDefault(&http_auth_preferences));
  219. GURL nonsecure_origin("http://www.example.com");
  220. GURL secure_origin("https://www.example.com");
  221. SSLInfo null_ssl_info;
  222. const HttpAuth::Target kTargets[] = {HttpAuth::AUTH_SERVER,
  223. HttpAuth::AUTH_PROXY};
  224. struct TestCase {
  225. int expected_net_error;
  226. const GURL origin;
  227. const char* challenge;
  228. } const kTestCases[] = {
  229. {OK, secure_origin, "Basic realm=\"FooBar\""},
  230. {ERR_UNSUPPORTED_AUTH_SCHEME, nonsecure_origin, "Basic realm=\"FooBar\""},
  231. {OK, secure_origin, "Digest realm=\"FooBar\", nonce=\"xyz\""},
  232. {OK, nonsecure_origin, "Digest realm=\"FooBar\", nonce=\"xyz\""},
  233. {OK, secure_origin, "Ntlm"},
  234. {OK, nonsecure_origin, "Ntlm"},
  235. #if BUILDFLAG(USE_KERBEROS) && !BUILDFLAG(IS_ANDROID)
  236. {OK, secure_origin, "Negotiate"},
  237. {OK, nonsecure_origin, "Negotiate"},
  238. #endif
  239. };
  240. for (const auto target : kTargets) {
  241. for (const TestCase& test_case : kTestCases) {
  242. std::unique_ptr<HttpAuthHandler> handler;
  243. int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
  244. test_case.challenge, target, null_ssl_info, NetworkIsolationKey(),
  245. url::SchemeHostPort(test_case.origin), NetLogWithSource(),
  246. host_resolver.get(), &handler);
  247. EXPECT_THAT(rv, IsError(test_case.expected_net_error));
  248. }
  249. }
  250. }
  251. TEST(HttpAuthHandlerFactoryTest, BasicFactoryRespectsHTTPEnabledPref) {
  252. auto host_resolver = std::make_unique<MockHostResolver>();
  253. std::unique_ptr<HttpAuthHandlerRegistryFactory> http_auth_handler_factory(
  254. HttpAuthHandlerFactory::CreateDefault());
  255. // Set the Preference that blocks Basic Auth over HTTP on all of the
  256. // factories. It shouldn't impact any behavior except for the Basic factory.
  257. MockAllowHttpAuthPreferences http_auth_preferences;
  258. http_auth_preferences.set_basic_over_http_enabled(false);
  259. http_auth_handler_factory->SetHttpAuthPreferences(kBasicAuthScheme,
  260. &http_auth_preferences);
  261. http_auth_handler_factory->SetHttpAuthPreferences(kDigestAuthScheme,
  262. &http_auth_preferences);
  263. http_auth_handler_factory->SetHttpAuthPreferences(kNtlmAuthScheme,
  264. &http_auth_preferences);
  265. http_auth_handler_factory->SetHttpAuthPreferences(kNegotiateAuthScheme,
  266. &http_auth_preferences);
  267. url::SchemeHostPort nonsecure_scheme_host_port(
  268. GURL("http://www.example.com"));
  269. url::SchemeHostPort secure_scheme_host_port(GURL("https://www.example.com"));
  270. SSLInfo null_ssl_info;
  271. const HttpAuth::Target kTargets[] = {HttpAuth::AUTH_SERVER,
  272. HttpAuth::AUTH_PROXY};
  273. struct TestCase {
  274. int expected_net_error;
  275. const url::SchemeHostPort scheme_host_port;
  276. const char* challenge;
  277. } const kTestCases[] = {
  278. // Challenges that result in success results.
  279. {OK, secure_scheme_host_port, "Basic realm=\"FooBar\""},
  280. {OK, secure_scheme_host_port, "Digest realm=\"FooBar\", nonce=\"xyz\""},
  281. {OK, nonsecure_scheme_host_port, "Digest realm=\"FooBar\", nonce=\"xyz\""},
  282. {OK, secure_scheme_host_port, "Ntlm"},
  283. {OK, nonsecure_scheme_host_port, "Ntlm"},
  284. #if BUILDFLAG(USE_KERBEROS) && !BUILDFLAG(IS_ANDROID)
  285. {OK, secure_scheme_host_port, "Negotiate"},
  286. {OK, nonsecure_scheme_host_port, "Negotiate"},
  287. #endif
  288. // Challenges that result in error results.
  289. {ERR_UNSUPPORTED_AUTH_SCHEME, nonsecure_scheme_host_port,
  290. "Basic realm=\"FooBar\""},
  291. };
  292. for (const auto target : kTargets) {
  293. for (const TestCase& test_case : kTestCases) {
  294. std::unique_ptr<HttpAuthHandler> handler;
  295. int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
  296. test_case.challenge, target, null_ssl_info, NetworkIsolationKey(),
  297. test_case.scheme_host_port, NetLogWithSource(), host_resolver.get(),
  298. &handler);
  299. EXPECT_THAT(rv, IsError(test_case.expected_net_error));
  300. }
  301. }
  302. }
  303. TEST(HttpAuthHandlerFactoryTest, LogCreateAuthHandlerResults) {
  304. auto host_resolver = std::make_unique<MockHostResolver>();
  305. std::unique_ptr<HttpAuthHandlerRegistryFactory> http_auth_handler_factory(
  306. HttpAuthHandlerFactory::CreateDefault());
  307. url::SchemeHostPort scheme_host_port(GURL("http://www.example.com"));
  308. SSLInfo null_ssl_info;
  309. RecordingNetLogObserver net_log_observer;
  310. net::NetLogCaptureMode capture_modes[] = {
  311. NetLogCaptureMode::kDefault, NetLogCaptureMode::kIncludeSensitive};
  312. struct TestCase {
  313. int expected_net_error;
  314. const char* challenge;
  315. const net::HttpAuth::Target auth_target;
  316. const char* expected_scheme;
  317. } test_cases[] = {
  318. // Challenges that result in success results.
  319. {OK, "Basic realm=\"FooBar\"", HttpAuth::AUTH_SERVER, "Basic"},
  320. {OK, "Basic realm=\"FooBar\"", HttpAuth::AUTH_PROXY, "Basic"},
  321. {OK, "Digest realm=\"FooBar\", nonce=\"xyz\"", HttpAuth::AUTH_SERVER,
  322. "Digest"},
  323. // Challenges that result in error results.
  324. {ERR_INVALID_RESPONSE, "", HttpAuth::AUTH_SERVER, ""},
  325. {ERR_INVALID_RESPONSE, "Digest realm=\"no_nonce\"", HttpAuth::AUTH_SERVER,
  326. "Digest"},
  327. {ERR_UNSUPPORTED_AUTH_SCHEME, "UNSUPPORTED realm=\"FooBar\"",
  328. HttpAuth::AUTH_SERVER, "UNSUPPORTED"},
  329. {ERR_UNSUPPORTED_AUTH_SCHEME, "invalid\xff\x0a", HttpAuth::AUTH_SERVER,
  330. "%ESCAPED:\xE2\x80\x8B invalid%FF\n"},
  331. {ERR_UNSUPPORTED_AUTH_SCHEME, "UNSUPPORTED2 realm=\"FooBar\"",
  332. HttpAuth::AUTH_PROXY, "UNSUPPORTED2"}};
  333. // For each level of capture sensitivity...
  334. for (auto capture_mode : capture_modes) {
  335. net_log_observer.SetObserverCaptureMode(capture_mode);
  336. // ... evaluate the expected results for each test case.
  337. for (auto test_case : test_cases) {
  338. std::unique_ptr<HttpAuthHandler> handler;
  339. int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
  340. test_case.challenge, test_case.auth_target, null_ssl_info,
  341. NetworkIsolationKey(), scheme_host_port,
  342. NetLogWithSource::Make(NetLogSourceType::NONE), host_resolver.get(),
  343. &handler);
  344. EXPECT_THAT(rv, IsError(test_case.expected_net_error));
  345. auto entries = net_log_observer.GetEntriesWithType(
  346. NetLogEventType::AUTH_HANDLER_CREATE_RESULT);
  347. ASSERT_EQ(1u, entries.size());
  348. const std::string* scheme =
  349. entries[0].params.GetDict().FindString("scheme");
  350. ASSERT_NE(nullptr, scheme);
  351. EXPECT_STRCASEEQ(test_case.expected_scheme, scheme->data());
  352. absl::optional<int> net_error =
  353. entries[0].params.GetDict().FindInt("net_error");
  354. if (test_case.expected_net_error) {
  355. ASSERT_TRUE(net_error.has_value());
  356. EXPECT_EQ(test_case.expected_net_error, net_error.value());
  357. } else {
  358. ASSERT_FALSE(net_error.has_value());
  359. }
  360. // The challenge should be logged only when sensitive logging is enabled.
  361. const std::string* challenge =
  362. entries[0].params.GetDict().FindString("challenge");
  363. if (capture_mode == NetLogCaptureMode::kDefault) {
  364. ASSERT_EQ(nullptr, challenge);
  365. } else {
  366. ASSERT_NE(nullptr, challenge);
  367. EXPECT_EQ(net::NetLogStringValue(test_case.challenge).GetString(),
  368. challenge->data());
  369. }
  370. net_log_observer.Clear();
  371. }
  372. }
  373. }
  374. } // namespace net