123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413 |
- // Copyright (c) 2011 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "net/http/http_auth_handler_factory.h"
- #include <memory>
- #include "base/bind.h"
- #include "base/callback.h"
- #include "build/build_config.h"
- #include "net/base/net_errors.h"
- #include "net/base/network_isolation_key.h"
- #include "net/dns/host_resolver.h"
- #include "net/dns/mock_host_resolver.h"
- #include "net/http/http_auth_handler.h"
- #include "net/http/http_auth_scheme.h"
- #include "net/http/mock_allow_http_auth_preferences.h"
- #include "net/http/url_security_manager.h"
- #include "net/log/net_log_values.h"
- #include "net/log/net_log_with_source.h"
- #include "net/log/test_net_log.h"
- #include "net/net_buildflags.h"
- #include "net/ssl/ssl_info.h"
- #include "net/test/gtest_util.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "url/gurl.h"
- #include "url/scheme_host_port.h"
- using net::test::IsError;
- using net::test::IsOk;
- namespace net {
- namespace {
- class MockHttpAuthHandlerFactory : public HttpAuthHandlerFactory {
- public:
- explicit MockHttpAuthHandlerFactory(int return_code) :
- return_code_(return_code) {}
- ~MockHttpAuthHandlerFactory() override = default;
- int CreateAuthHandler(HttpAuthChallengeTokenizer* challenge,
- HttpAuth::Target target,
- const SSLInfo& ssl_info,
- const NetworkIsolationKey& network_isolation_key,
- const url::SchemeHostPort& scheme_host_port,
- CreateReason reason,
- int nonce_count,
- const NetLogWithSource& net_log,
- HostResolver* host_resolver,
- std::unique_ptr<HttpAuthHandler>* handler) override {
- handler->reset();
- return return_code_;
- }
- private:
- int return_code_;
- };
- } // namespace
- TEST(HttpAuthHandlerFactoryTest, RegistryFactory) {
- SSLInfo null_ssl_info;
- HttpAuthHandlerRegistryFactory registry_factory(
- /*http_auth_preferences=*/nullptr);
- url::SchemeHostPort scheme_host_port(GURL("https://www.google.com"));
- const int kBasicReturnCode = -1;
- auto mock_factory_basic =
- std::make_unique<MockHttpAuthHandlerFactory>(kBasicReturnCode);
- const int kDigestReturnCode = -2;
- auto mock_factory_digest =
- std::make_unique<MockHttpAuthHandlerFactory>(kDigestReturnCode);
- const int kDigestReturnCodeReplace = -3;
- auto mock_factory_digest_replace =
- std::make_unique<MockHttpAuthHandlerFactory>(kDigestReturnCodeReplace);
- auto host_resovler = std::make_unique<MockHostResolver>();
- std::unique_ptr<HttpAuthHandler> handler;
- // No schemes should be supported in the beginning.
- EXPECT_EQ(
- ERR_UNSUPPORTED_AUTH_SCHEME,
- registry_factory.CreateAuthHandlerFromString(
- "Basic", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(),
- scheme_host_port, NetLogWithSource(), host_resovler.get(), &handler));
- // Test what happens with a single scheme.
- registry_factory.RegisterSchemeFactory("Basic",
- std::move(mock_factory_basic));
- EXPECT_EQ(
- kBasicReturnCode,
- registry_factory.CreateAuthHandlerFromString(
- "Basic", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(),
- scheme_host_port, NetLogWithSource(), host_resovler.get(), &handler));
- EXPECT_EQ(
- ERR_UNSUPPORTED_AUTH_SCHEME,
- registry_factory.CreateAuthHandlerFromString(
- "Digest", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(),
- scheme_host_port, NetLogWithSource(), host_resovler.get(), &handler));
- // Test multiple schemes
- registry_factory.RegisterSchemeFactory("Digest",
- std::move(mock_factory_digest));
- EXPECT_EQ(
- kBasicReturnCode,
- registry_factory.CreateAuthHandlerFromString(
- "Basic", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(),
- scheme_host_port, NetLogWithSource(), host_resovler.get(), &handler));
- EXPECT_EQ(
- kDigestReturnCode,
- registry_factory.CreateAuthHandlerFromString(
- "Digest", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(),
- scheme_host_port, NetLogWithSource(), host_resovler.get(), &handler));
- // Test case-insensitivity
- EXPECT_EQ(
- kBasicReturnCode,
- registry_factory.CreateAuthHandlerFromString(
- "basic", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(),
- scheme_host_port, NetLogWithSource(), host_resovler.get(), &handler));
- // Test replacement of existing auth scheme
- registry_factory.RegisterSchemeFactory(
- "Digest", std::move(mock_factory_digest_replace));
- EXPECT_EQ(
- kBasicReturnCode,
- registry_factory.CreateAuthHandlerFromString(
- "Basic", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(),
- scheme_host_port, NetLogWithSource(), host_resovler.get(), &handler));
- EXPECT_EQ(
- kDigestReturnCodeReplace,
- registry_factory.CreateAuthHandlerFromString(
- "Digest", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(),
- scheme_host_port, NetLogWithSource(), host_resovler.get(), &handler));
- }
- TEST(HttpAuthHandlerFactoryTest, DefaultFactory) {
- auto host_resolver = std::make_unique<MockHostResolver>();
- MockAllowHttpAuthPreferences http_auth_preferences;
- std::unique_ptr<HttpAuthHandlerRegistryFactory> http_auth_handler_factory(
- HttpAuthHandlerFactory::CreateDefault());
- http_auth_handler_factory->SetHttpAuthPreferences(kNegotiateAuthScheme,
- &http_auth_preferences);
- url::SchemeHostPort server_scheme_host_port(GURL("http://www.example.com"));
- url::SchemeHostPort proxy_scheme_host_port(
- GURL("http://cache.example.com:3128"));
- SSLInfo null_ssl_info;
- {
- std::unique_ptr<HttpAuthHandler> handler;
- int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
- "Basic realm=\"FooBar\"", HttpAuth::AUTH_SERVER, null_ssl_info,
- NetworkIsolationKey(), server_scheme_host_port, NetLogWithSource(),
- host_resolver.get(), &handler);
- EXPECT_THAT(rv, IsOk());
- ASSERT_FALSE(handler.get() == nullptr);
- EXPECT_EQ(HttpAuth::AUTH_SCHEME_BASIC, handler->auth_scheme());
- EXPECT_STREQ("FooBar", handler->realm().c_str());
- EXPECT_EQ(HttpAuth::AUTH_SERVER, handler->target());
- EXPECT_FALSE(handler->encrypts_identity());
- EXPECT_FALSE(handler->is_connection_based());
- }
- {
- std::unique_ptr<HttpAuthHandler> handler;
- int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
- "UNSUPPORTED realm=\"FooBar\"", HttpAuth::AUTH_SERVER, null_ssl_info,
- NetworkIsolationKey(), server_scheme_host_port, NetLogWithSource(),
- host_resolver.get(), &handler);
- EXPECT_THAT(rv, IsError(ERR_UNSUPPORTED_AUTH_SCHEME));
- EXPECT_TRUE(handler.get() == nullptr);
- }
- {
- std::unique_ptr<HttpAuthHandler> handler;
- int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
- "Digest realm=\"FooBar\", nonce=\"xyz\"", HttpAuth::AUTH_PROXY,
- null_ssl_info, NetworkIsolationKey(), proxy_scheme_host_port,
- NetLogWithSource(), host_resolver.get(), &handler);
- EXPECT_THAT(rv, IsOk());
- ASSERT_FALSE(handler.get() == nullptr);
- EXPECT_EQ(HttpAuth::AUTH_SCHEME_DIGEST, handler->auth_scheme());
- EXPECT_STREQ("FooBar", handler->realm().c_str());
- EXPECT_EQ(HttpAuth::AUTH_PROXY, handler->target());
- EXPECT_TRUE(handler->encrypts_identity());
- EXPECT_FALSE(handler->is_connection_based());
- }
- {
- std::unique_ptr<HttpAuthHandler> handler;
- int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
- "NTLM", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(),
- server_scheme_host_port, NetLogWithSource(), host_resolver.get(),
- &handler);
- EXPECT_THAT(rv, IsOk());
- ASSERT_FALSE(handler.get() == nullptr);
- EXPECT_EQ(HttpAuth::AUTH_SCHEME_NTLM, handler->auth_scheme());
- EXPECT_STREQ("", handler->realm().c_str());
- EXPECT_EQ(HttpAuth::AUTH_SERVER, handler->target());
- EXPECT_TRUE(handler->encrypts_identity());
- EXPECT_TRUE(handler->is_connection_based());
- }
- {
- std::unique_ptr<HttpAuthHandler> handler;
- int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
- "Negotiate", HttpAuth::AUTH_SERVER, null_ssl_info,
- NetworkIsolationKey(), server_scheme_host_port, NetLogWithSource(),
- host_resolver.get(), &handler);
- // Note the default factory doesn't support Kerberos on Android
- #if BUILDFLAG(USE_KERBEROS) && !BUILDFLAG(IS_ANDROID)
- EXPECT_THAT(rv, IsOk());
- ASSERT_FALSE(handler.get() == nullptr);
- EXPECT_EQ(HttpAuth::AUTH_SCHEME_NEGOTIATE, handler->auth_scheme());
- EXPECT_STREQ("", handler->realm().c_str());
- EXPECT_EQ(HttpAuth::AUTH_SERVER, handler->target());
- EXPECT_TRUE(handler->encrypts_identity());
- EXPECT_TRUE(handler->is_connection_based());
- #else
- EXPECT_THAT(rv, IsError(ERR_UNSUPPORTED_AUTH_SCHEME));
- EXPECT_TRUE(handler.get() == nullptr);
- #endif // BUILDFLAG(USE_KERBEROS) && !BUILDFLAG(IS_ANDROID)
- }
- }
- TEST(HttpAuthHandlerFactoryTest, HttpAuthUrlFilter) {
- auto host_resolver = std::make_unique<MockHostResolver>();
- MockAllowHttpAuthPreferences http_auth_preferences;
- // Set the Preference that blocks Basic Auth over HTTP on all of the
- // factories. It shouldn't impact any behavior except for the Basic factory.
- http_auth_preferences.set_basic_over_http_enabled(false);
- // Set the preference that only allows "https://www.example.com" to use HTTP
- // auth.
- http_auth_preferences.set_http_auth_scheme_filter(
- base::BindRepeating([](const url::SchemeHostPort& scheme_host_port) {
- return scheme_host_port ==
- url::SchemeHostPort(GURL("https://www.example.com"));
- }));
- std::unique_ptr<HttpAuthHandlerRegistryFactory> http_auth_handler_factory(
- HttpAuthHandlerFactory::CreateDefault(&http_auth_preferences));
- GURL nonsecure_origin("http://www.example.com");
- GURL secure_origin("https://www.example.com");
- SSLInfo null_ssl_info;
- const HttpAuth::Target kTargets[] = {HttpAuth::AUTH_SERVER,
- HttpAuth::AUTH_PROXY};
- struct TestCase {
- int expected_net_error;
- const GURL origin;
- const char* challenge;
- } const kTestCases[] = {
- {OK, secure_origin, "Basic realm=\"FooBar\""},
- {ERR_UNSUPPORTED_AUTH_SCHEME, nonsecure_origin, "Basic realm=\"FooBar\""},
- {OK, secure_origin, "Digest realm=\"FooBar\", nonce=\"xyz\""},
- {OK, nonsecure_origin, "Digest realm=\"FooBar\", nonce=\"xyz\""},
- {OK, secure_origin, "Ntlm"},
- {OK, nonsecure_origin, "Ntlm"},
- #if BUILDFLAG(USE_KERBEROS) && !BUILDFLAG(IS_ANDROID)
- {OK, secure_origin, "Negotiate"},
- {OK, nonsecure_origin, "Negotiate"},
- #endif
- };
- for (const auto target : kTargets) {
- for (const TestCase& test_case : kTestCases) {
- std::unique_ptr<HttpAuthHandler> handler;
- int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
- test_case.challenge, target, null_ssl_info, NetworkIsolationKey(),
- url::SchemeHostPort(test_case.origin), NetLogWithSource(),
- host_resolver.get(), &handler);
- EXPECT_THAT(rv, IsError(test_case.expected_net_error));
- }
- }
- }
- TEST(HttpAuthHandlerFactoryTest, BasicFactoryRespectsHTTPEnabledPref) {
- auto host_resolver = std::make_unique<MockHostResolver>();
- std::unique_ptr<HttpAuthHandlerRegistryFactory> http_auth_handler_factory(
- HttpAuthHandlerFactory::CreateDefault());
- // Set the Preference that blocks Basic Auth over HTTP on all of the
- // factories. It shouldn't impact any behavior except for the Basic factory.
- MockAllowHttpAuthPreferences http_auth_preferences;
- http_auth_preferences.set_basic_over_http_enabled(false);
- http_auth_handler_factory->SetHttpAuthPreferences(kBasicAuthScheme,
- &http_auth_preferences);
- http_auth_handler_factory->SetHttpAuthPreferences(kDigestAuthScheme,
- &http_auth_preferences);
- http_auth_handler_factory->SetHttpAuthPreferences(kNtlmAuthScheme,
- &http_auth_preferences);
- http_auth_handler_factory->SetHttpAuthPreferences(kNegotiateAuthScheme,
- &http_auth_preferences);
- url::SchemeHostPort nonsecure_scheme_host_port(
- GURL("http://www.example.com"));
- url::SchemeHostPort secure_scheme_host_port(GURL("https://www.example.com"));
- SSLInfo null_ssl_info;
- const HttpAuth::Target kTargets[] = {HttpAuth::AUTH_SERVER,
- HttpAuth::AUTH_PROXY};
- struct TestCase {
- int expected_net_error;
- const url::SchemeHostPort scheme_host_port;
- const char* challenge;
- } const kTestCases[] = {
- // Challenges that result in success results.
- {OK, secure_scheme_host_port, "Basic realm=\"FooBar\""},
- {OK, secure_scheme_host_port, "Digest realm=\"FooBar\", nonce=\"xyz\""},
- {OK, nonsecure_scheme_host_port, "Digest realm=\"FooBar\", nonce=\"xyz\""},
- {OK, secure_scheme_host_port, "Ntlm"},
- {OK, nonsecure_scheme_host_port, "Ntlm"},
- #if BUILDFLAG(USE_KERBEROS) && !BUILDFLAG(IS_ANDROID)
- {OK, secure_scheme_host_port, "Negotiate"},
- {OK, nonsecure_scheme_host_port, "Negotiate"},
- #endif
- // Challenges that result in error results.
- {ERR_UNSUPPORTED_AUTH_SCHEME, nonsecure_scheme_host_port,
- "Basic realm=\"FooBar\""},
- };
- for (const auto target : kTargets) {
- for (const TestCase& test_case : kTestCases) {
- std::unique_ptr<HttpAuthHandler> handler;
- int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
- test_case.challenge, target, null_ssl_info, NetworkIsolationKey(),
- test_case.scheme_host_port, NetLogWithSource(), host_resolver.get(),
- &handler);
- EXPECT_THAT(rv, IsError(test_case.expected_net_error));
- }
- }
- }
- TEST(HttpAuthHandlerFactoryTest, LogCreateAuthHandlerResults) {
- auto host_resolver = std::make_unique<MockHostResolver>();
- std::unique_ptr<HttpAuthHandlerRegistryFactory> http_auth_handler_factory(
- HttpAuthHandlerFactory::CreateDefault());
- url::SchemeHostPort scheme_host_port(GURL("http://www.example.com"));
- SSLInfo null_ssl_info;
- RecordingNetLogObserver net_log_observer;
- net::NetLogCaptureMode capture_modes[] = {
- NetLogCaptureMode::kDefault, NetLogCaptureMode::kIncludeSensitive};
- struct TestCase {
- int expected_net_error;
- const char* challenge;
- const net::HttpAuth::Target auth_target;
- const char* expected_scheme;
- } test_cases[] = {
- // Challenges that result in success results.
- {OK, "Basic realm=\"FooBar\"", HttpAuth::AUTH_SERVER, "Basic"},
- {OK, "Basic realm=\"FooBar\"", HttpAuth::AUTH_PROXY, "Basic"},
- {OK, "Digest realm=\"FooBar\", nonce=\"xyz\"", HttpAuth::AUTH_SERVER,
- "Digest"},
- // Challenges that result in error results.
- {ERR_INVALID_RESPONSE, "", HttpAuth::AUTH_SERVER, ""},
- {ERR_INVALID_RESPONSE, "Digest realm=\"no_nonce\"", HttpAuth::AUTH_SERVER,
- "Digest"},
- {ERR_UNSUPPORTED_AUTH_SCHEME, "UNSUPPORTED realm=\"FooBar\"",
- HttpAuth::AUTH_SERVER, "UNSUPPORTED"},
- {ERR_UNSUPPORTED_AUTH_SCHEME, "invalid\xff\x0a", HttpAuth::AUTH_SERVER,
- "%ESCAPED:\xE2\x80\x8B invalid%FF\n"},
- {ERR_UNSUPPORTED_AUTH_SCHEME, "UNSUPPORTED2 realm=\"FooBar\"",
- HttpAuth::AUTH_PROXY, "UNSUPPORTED2"}};
- // For each level of capture sensitivity...
- for (auto capture_mode : capture_modes) {
- net_log_observer.SetObserverCaptureMode(capture_mode);
- // ... evaluate the expected results for each test case.
- for (auto test_case : test_cases) {
- std::unique_ptr<HttpAuthHandler> handler;
- int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
- test_case.challenge, test_case.auth_target, null_ssl_info,
- NetworkIsolationKey(), scheme_host_port,
- NetLogWithSource::Make(NetLogSourceType::NONE), host_resolver.get(),
- &handler);
- EXPECT_THAT(rv, IsError(test_case.expected_net_error));
- auto entries = net_log_observer.GetEntriesWithType(
- NetLogEventType::AUTH_HANDLER_CREATE_RESULT);
- ASSERT_EQ(1u, entries.size());
- const std::string* scheme =
- entries[0].params.GetDict().FindString("scheme");
- ASSERT_NE(nullptr, scheme);
- EXPECT_STRCASEEQ(test_case.expected_scheme, scheme->data());
- absl::optional<int> net_error =
- entries[0].params.GetDict().FindInt("net_error");
- if (test_case.expected_net_error) {
- ASSERT_TRUE(net_error.has_value());
- EXPECT_EQ(test_case.expected_net_error, net_error.value());
- } else {
- ASSERT_FALSE(net_error.has_value());
- }
- // The challenge should be logged only when sensitive logging is enabled.
- const std::string* challenge =
- entries[0].params.GetDict().FindString("challenge");
- if (capture_mode == NetLogCaptureMode::kDefault) {
- ASSERT_EQ(nullptr, challenge);
- } else {
- ASSERT_NE(nullptr, challenge);
- EXPECT_EQ(net::NetLogStringValue(test_case.challenge).GetString(),
- challenge->data());
- }
- net_log_observer.Clear();
- }
- }
- }
- } // namespace net
|