1 // Copyright 2010 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_factory.h"
6
7 #include <optional>
8 #include <set>
9
10 #include "base/containers/contains.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/strings/string_util.h"
13 #include "build/build_config.h"
14 #include "net/base/net_errors.h"
15 #include "net/dns/host_resolver.h"
16 #include "net/http/http_auth_challenge_tokenizer.h"
17 #include "net/http/http_auth_filter.h"
18 #include "net/http/http_auth_handler_basic.h"
19 #include "net/http/http_auth_handler_digest.h"
20 #include "net/http/http_auth_handler_ntlm.h"
21 #include "net/http/http_auth_preferences.h"
22 #include "net/http/http_auth_scheme.h"
23 #include "net/log/net_log_values.h"
24 #include "net/net_buildflags.h"
25 #include "net/ssl/ssl_info.h"
26 #include "url/scheme_host_port.h"
27
28 #if BUILDFLAG(USE_KERBEROS)
29 #include "net/http/http_auth_handler_negotiate.h"
30 #endif
31
32 namespace {
33
NetLogParamsForCreateAuth(const std::string & scheme,const std::string & challenge,const int net_error,const url::SchemeHostPort & scheme_host_port,const std::optional<bool> & allows_default_credentials,net::NetLogCaptureMode capture_mode)34 base::Value::Dict NetLogParamsForCreateAuth(
35 const std::string& scheme,
36 const std::string& challenge,
37 const int net_error,
38 const url::SchemeHostPort& scheme_host_port,
39 const std::optional<bool>& allows_default_credentials,
40 net::NetLogCaptureMode capture_mode) {
41 base::Value::Dict dict;
42 dict.Set("scheme", net::NetLogStringValue(scheme));
43 if (net::NetLogCaptureIncludesSensitive(capture_mode))
44 dict.Set("challenge", net::NetLogStringValue(challenge));
45 dict.Set("origin", scheme_host_port.Serialize());
46 if (allows_default_credentials)
47 dict.Set("allows_default_credentials", *allows_default_credentials);
48 if (net_error < 0)
49 dict.Set("net_error", net_error);
50 return dict;
51 }
52
53 } // namespace
54
55 namespace net {
56
CreateAuthHandlerFromString(const std::string & challenge,HttpAuth::Target target,const SSLInfo & ssl_info,const NetworkAnonymizationKey & network_anonymization_key,const url::SchemeHostPort & scheme_host_port,const NetLogWithSource & net_log,HostResolver * host_resolver,std::unique_ptr<HttpAuthHandler> * handler)57 int HttpAuthHandlerFactory::CreateAuthHandlerFromString(
58 const std::string& challenge,
59 HttpAuth::Target target,
60 const SSLInfo& ssl_info,
61 const NetworkAnonymizationKey& network_anonymization_key,
62 const url::SchemeHostPort& scheme_host_port,
63 const NetLogWithSource& net_log,
64 HostResolver* host_resolver,
65 std::unique_ptr<HttpAuthHandler>* handler) {
66 HttpAuthChallengeTokenizer props(challenge.begin(), challenge.end());
67 return CreateAuthHandler(&props, target, ssl_info, network_anonymization_key,
68 scheme_host_port, CREATE_CHALLENGE, 1, net_log,
69 host_resolver, handler);
70 }
71
CreatePreemptiveAuthHandlerFromString(const std::string & challenge,HttpAuth::Target target,const NetworkAnonymizationKey & network_anonymization_key,const url::SchemeHostPort & scheme_host_port,int digest_nonce_count,const NetLogWithSource & net_log,HostResolver * host_resolver,std::unique_ptr<HttpAuthHandler> * handler)72 int HttpAuthHandlerFactory::CreatePreemptiveAuthHandlerFromString(
73 const std::string& challenge,
74 HttpAuth::Target target,
75 const NetworkAnonymizationKey& network_anonymization_key,
76 const url::SchemeHostPort& scheme_host_port,
77 int digest_nonce_count,
78 const NetLogWithSource& net_log,
79 HostResolver* host_resolver,
80 std::unique_ptr<HttpAuthHandler>* handler) {
81 HttpAuthChallengeTokenizer props(challenge.begin(), challenge.end());
82 SSLInfo null_ssl_info;
83 return CreateAuthHandler(&props, target, null_ssl_info,
84 network_anonymization_key, scheme_host_port,
85 CREATE_PREEMPTIVE, digest_nonce_count, net_log,
86 host_resolver, handler);
87 }
88
HttpAuthHandlerRegistryFactory(const HttpAuthPreferences * http_auth_preferences)89 HttpAuthHandlerRegistryFactory::HttpAuthHandlerRegistryFactory(
90 const HttpAuthPreferences* http_auth_preferences) {
91 set_http_auth_preferences(http_auth_preferences);
92 }
93
94 HttpAuthHandlerRegistryFactory::~HttpAuthHandlerRegistryFactory() = default;
95
SetHttpAuthPreferences(const std::string & scheme,const HttpAuthPreferences * prefs)96 void HttpAuthHandlerRegistryFactory::SetHttpAuthPreferences(
97 const std::string& scheme,
98 const HttpAuthPreferences* prefs) {
99 HttpAuthHandlerFactory* factory = GetSchemeFactory(scheme);
100 if (factory)
101 factory->set_http_auth_preferences(prefs);
102 }
103
RegisterSchemeFactory(const std::string & scheme,std::unique_ptr<HttpAuthHandlerFactory> factory)104 void HttpAuthHandlerRegistryFactory::RegisterSchemeFactory(
105 const std::string& scheme,
106 std::unique_ptr<HttpAuthHandlerFactory> factory) {
107 std::string lower_scheme = base::ToLowerASCII(scheme);
108 if (factory) {
109 factory->set_http_auth_preferences(http_auth_preferences());
110 factory_map_[lower_scheme] = std::move(factory);
111 } else {
112 factory_map_.erase(lower_scheme);
113 }
114 }
115
116 // static
117 std::unique_ptr<HttpAuthHandlerRegistryFactory>
CreateDefault(const HttpAuthPreferences * prefs,const std::string & gssapi_library_name,HttpAuthMechanismFactory negotiate_auth_system_factory)118 HttpAuthHandlerFactory::CreateDefault(
119 const HttpAuthPreferences* prefs
120 #if BUILDFLAG(USE_EXTERNAL_GSSAPI)
121 ,
122 const std::string& gssapi_library_name
123 #endif
124 #if BUILDFLAG(USE_KERBEROS)
125 ,
126 HttpAuthMechanismFactory negotiate_auth_system_factory
127 #endif
128 ) {
129 return HttpAuthHandlerRegistryFactory::Create(prefs
130 #if BUILDFLAG(USE_EXTERNAL_GSSAPI)
131 ,
132 gssapi_library_name
133 #endif
134 #if BUILDFLAG(USE_KERBEROS)
135 ,
136 negotiate_auth_system_factory
137 #endif
138 );
139 }
140
141 // static
142 std::unique_ptr<HttpAuthHandlerRegistryFactory>
Create(const HttpAuthPreferences * prefs,const std::string & gssapi_library_name,HttpAuthMechanismFactory negotiate_auth_system_factory)143 HttpAuthHandlerRegistryFactory::Create(
144 const HttpAuthPreferences* prefs
145 #if BUILDFLAG(USE_EXTERNAL_GSSAPI)
146 ,
147 const std::string& gssapi_library_name
148 #endif
149 #if BUILDFLAG(USE_KERBEROS)
150 ,
151 HttpAuthMechanismFactory negotiate_auth_system_factory
152 #endif
153 ) {
154 auto registry_factory =
155 std::make_unique<HttpAuthHandlerRegistryFactory>(prefs);
156
157 registry_factory->RegisterSchemeFactory(
158 kBasicAuthScheme, std::make_unique<HttpAuthHandlerBasic::Factory>());
159
160 registry_factory->RegisterSchemeFactory(
161 kDigestAuthScheme, std::make_unique<HttpAuthHandlerDigest::Factory>());
162
163 auto ntlm_factory = std::make_unique<HttpAuthHandlerNTLM::Factory>();
164 #if BUILDFLAG(IS_WIN)
165 ntlm_factory->set_sspi_library(
166 std::make_unique<SSPILibraryDefault>(NTLMSP_NAME));
167 #endif // BUILDFLAG(IS_WIN)
168 registry_factory->RegisterSchemeFactory(kNtlmAuthScheme,
169 std::move(ntlm_factory));
170
171 #if BUILDFLAG(USE_KERBEROS)
172 auto negotiate_factory = std::make_unique<HttpAuthHandlerNegotiate::Factory>(
173 negotiate_auth_system_factory);
174 #if BUILDFLAG(IS_WIN)
175 negotiate_factory->set_library(
176 std::make_unique<SSPILibraryDefault>(NEGOSSP_NAME));
177 #elif BUILDFLAG(USE_EXTERNAL_GSSAPI)
178 negotiate_factory->set_library(
179 std::make_unique<GSSAPISharedLibrary>(gssapi_library_name));
180 #endif
181 registry_factory->RegisterSchemeFactory(kNegotiateAuthScheme,
182 std::move(negotiate_factory));
183 #endif // BUILDFLAG(USE_KERBEROS)
184
185 if (prefs) {
186 registry_factory->set_http_auth_preferences(prefs);
187 for (auto& factory_entry : registry_factory->factory_map_) {
188 factory_entry.second->set_http_auth_preferences(prefs);
189 }
190 }
191 return registry_factory;
192 }
193
CreateAuthHandler(HttpAuthChallengeTokenizer * challenge,HttpAuth::Target target,const SSLInfo & ssl_info,const NetworkAnonymizationKey & network_anonymization_key,const url::SchemeHostPort & scheme_host_port,CreateReason reason,int digest_nonce_count,const NetLogWithSource & net_log,HostResolver * host_resolver,std::unique_ptr<HttpAuthHandler> * handler)194 int HttpAuthHandlerRegistryFactory::CreateAuthHandler(
195 HttpAuthChallengeTokenizer* challenge,
196 HttpAuth::Target target,
197 const SSLInfo& ssl_info,
198 const NetworkAnonymizationKey& network_anonymization_key,
199 const url::SchemeHostPort& scheme_host_port,
200 CreateReason reason,
201 int digest_nonce_count,
202 const NetLogWithSource& net_log,
203 HostResolver* host_resolver,
204 std::unique_ptr<HttpAuthHandler>* handler) {
205 auto scheme = challenge->auth_scheme();
206
207 int net_error;
208 if (scheme.empty()) {
209 handler->reset();
210 net_error = ERR_INVALID_RESPONSE;
211 } else {
212 bool all_schemes_allowed_for_origin =
213 http_auth_preferences() &&
214 http_auth_preferences()->IsAllowedToUseAllHttpAuthSchemes(
215 scheme_host_port);
216 auto* factory = all_schemes_allowed_for_origin || IsSchemeAllowed(scheme)
217 ? GetSchemeFactory(scheme)
218 : nullptr;
219 if (!factory) {
220 handler->reset();
221 net_error = ERR_UNSUPPORTED_AUTH_SCHEME;
222 } else {
223 net_error = factory->CreateAuthHandler(
224 challenge, target, ssl_info, network_anonymization_key,
225 scheme_host_port, reason, digest_nonce_count, net_log, host_resolver,
226 handler);
227 }
228 }
229
230 net_log.AddEvent(
231 NetLogEventType::AUTH_HANDLER_CREATE_RESULT,
232 [&](NetLogCaptureMode capture_mode) {
233 return NetLogParamsForCreateAuth(
234 scheme, challenge->challenge_text(), net_error, scheme_host_port,
235 *handler
236 ? std::make_optional((*handler)->AllowsDefaultCredentials())
237 : std::nullopt,
238 capture_mode);
239 });
240 return net_error;
241 }
242
IsSchemeAllowedForTesting(const std::string & scheme) const243 bool HttpAuthHandlerRegistryFactory::IsSchemeAllowedForTesting(
244 const std::string& scheme) const {
245 return IsSchemeAllowed(scheme);
246 }
247
IsSchemeAllowed(const std::string & scheme) const248 bool HttpAuthHandlerRegistryFactory::IsSchemeAllowed(
249 const std::string& scheme) const {
250 const std::set<std::string>& allowed_schemes =
251 http_auth_preferences() && http_auth_preferences()->allowed_schemes()
252 ? *http_auth_preferences()->allowed_schemes()
253 : default_auth_schemes_;
254 return allowed_schemes.find(scheme) != allowed_schemes.end();
255 }
256
257 #if BUILDFLAG(USE_KERBEROS) && !BUILDFLAG(IS_ANDROID) && BUILDFLAG(IS_POSIX)
258 std::optional<std::string>
GetNegotiateLibraryNameForTesting() const259 HttpAuthHandlerRegistryFactory::GetNegotiateLibraryNameForTesting() const {
260 if (!IsSchemeAllowed(kNegotiateAuthScheme))
261 return std::nullopt;
262
263 return reinterpret_cast<net::HttpAuthHandlerNegotiate::Factory*>(
264 GetSchemeFactory(net::kNegotiateAuthScheme))
265 ->GetLibraryNameForTesting(); // IN-TEST
266 }
267 #endif
268
GetSchemeFactory(const std::string & scheme) const269 HttpAuthHandlerFactory* HttpAuthHandlerRegistryFactory::GetSchemeFactory(
270 const std::string& scheme) const {
271 std::string lower_scheme = base::ToLowerASCII(scheme);
272 auto it = factory_map_.find(lower_scheme);
273 if (it == factory_map_.end()) {
274 return nullptr; // |scheme| is not registered.
275 }
276 return it->second.get();
277 }
278
279 } // namespace net
280