xref: /aosp_15_r20/external/cronet/net/http/http_auth_handler_factory.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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