1 // Copyright 2011 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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "net/http/http_auth.h"
11
12 #include <algorithm>
13 #include <optional>
14 #include <string_view>
15
16 #include "base/strings/string_tokenizer.h"
17 #include "base/strings/string_util.h"
18 #include "base/values.h"
19 #include "net/base/net_errors.h"
20 #include "net/dns/host_resolver.h"
21 #include "net/http/http_auth_challenge_tokenizer.h"
22 #include "net/http/http_auth_handler.h"
23 #include "net/http/http_auth_handler_factory.h"
24 #include "net/http/http_auth_scheme.h"
25 #include "net/http/http_request_headers.h"
26 #include "net/http/http_response_headers.h"
27 #include "net/http/http_util.h"
28 #include "net/log/net_log.h"
29 #include "net/log/net_log_values.h"
30
31 namespace net {
32
33 namespace {
34 const char* const kSchemeNames[] = {kBasicAuthScheme, kDigestAuthScheme,
35 kNtlmAuthScheme, kNegotiateAuthScheme,
36 kSpdyProxyAuthScheme, kMockAuthScheme};
37 } // namespace
38
39 HttpAuth::Identity::Identity() = default;
40
41 // static
ChooseBestChallenge(HttpAuthHandlerFactory * http_auth_handler_factory,const HttpResponseHeaders & response_headers,const SSLInfo & ssl_info,const NetworkAnonymizationKey & network_anonymization_key,Target target,const url::SchemeHostPort & scheme_host_port,const std::set<Scheme> & disabled_schemes,const NetLogWithSource & net_log,HostResolver * host_resolver,std::unique_ptr<HttpAuthHandler> * handler)42 void HttpAuth::ChooseBestChallenge(
43 HttpAuthHandlerFactory* http_auth_handler_factory,
44 const HttpResponseHeaders& response_headers,
45 const SSLInfo& ssl_info,
46 const NetworkAnonymizationKey& network_anonymization_key,
47 Target target,
48 const url::SchemeHostPort& scheme_host_port,
49 const std::set<Scheme>& disabled_schemes,
50 const NetLogWithSource& net_log,
51 HostResolver* host_resolver,
52 std::unique_ptr<HttpAuthHandler>* handler) {
53 DCHECK(http_auth_handler_factory);
54 DCHECK(handler->get() == nullptr);
55
56 // Choose the challenge whose authentication handler gives the maximum score.
57 std::unique_ptr<HttpAuthHandler> best;
58 const std::string header_name = GetChallengeHeaderName(target);
59 std::optional<std::string_view> cur_challenge;
60 size_t iter = 0;
61 while (
62 (cur_challenge = response_headers.EnumerateHeader(&iter, header_name))) {
63 std::unique_ptr<HttpAuthHandler> cur;
64 int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
65 *cur_challenge, target, ssl_info, network_anonymization_key,
66 scheme_host_port, net_log, host_resolver, &cur);
67 if (rv != OK) {
68 VLOG(1) << "Unable to create AuthHandler. Status: " << ErrorToString(rv)
69 << " Challenge: " << *cur_challenge;
70 continue;
71 }
72 if (cur.get() && (!best.get() || best->score() < cur->score()) &&
73 (disabled_schemes.find(cur->auth_scheme()) == disabled_schemes.end()))
74 best.swap(cur);
75 }
76 handler->swap(best);
77 }
78
79 // static
HandleChallengeResponse(HttpAuthHandler * handler,const HttpResponseHeaders & response_headers,Target target,const std::set<Scheme> & disabled_schemes,std::string * challenge_used)80 HttpAuth::AuthorizationResult HttpAuth::HandleChallengeResponse(
81 HttpAuthHandler* handler,
82 const HttpResponseHeaders& response_headers,
83 Target target,
84 const std::set<Scheme>& disabled_schemes,
85 std::string* challenge_used) {
86 DCHECK(handler);
87 DCHECK(challenge_used);
88
89 challenge_used->clear();
90 HttpAuth::Scheme current_scheme = handler->auth_scheme();
91 if (disabled_schemes.find(current_scheme) != disabled_schemes.end())
92 return HttpAuth::AUTHORIZATION_RESULT_REJECT;
93 const char* current_scheme_name = SchemeToString(current_scheme);
94 const std::string header_name = GetChallengeHeaderName(target);
95 size_t iter = 0;
96 std::optional<std::string_view> challenge;
97 HttpAuth::AuthorizationResult authorization_result =
98 HttpAuth::AUTHORIZATION_RESULT_INVALID;
99 while ((challenge = response_headers.EnumerateHeader(&iter, header_name))) {
100 HttpAuthChallengeTokenizer challenge_tokens(*challenge);
101 if (challenge_tokens.auth_scheme() != current_scheme_name)
102 continue;
103 authorization_result = handler->HandleAnotherChallenge(&challenge_tokens);
104 if (authorization_result != HttpAuth::AUTHORIZATION_RESULT_INVALID) {
105 *challenge_used = *challenge;
106 return authorization_result;
107 }
108 }
109 // Finding no matches is equivalent to rejection.
110 return HttpAuth::AUTHORIZATION_RESULT_REJECT;
111 }
112
113 // static
GetChallengeHeaderName(Target target)114 std::string HttpAuth::GetChallengeHeaderName(Target target) {
115 switch (target) {
116 case AUTH_PROXY:
117 return "Proxy-Authenticate";
118 case AUTH_SERVER:
119 return "WWW-Authenticate";
120 default:
121 NOTREACHED();
122 }
123 }
124
125 // static
GetAuthorizationHeaderName(Target target)126 std::string HttpAuth::GetAuthorizationHeaderName(Target target) {
127 switch (target) {
128 case AUTH_PROXY:
129 return HttpRequestHeaders::kProxyAuthorization;
130 case AUTH_SERVER:
131 return HttpRequestHeaders::kAuthorization;
132 default:
133 NOTREACHED();
134 }
135 }
136
137 // static
GetAuthTargetString(Target target)138 std::string HttpAuth::GetAuthTargetString(Target target) {
139 switch (target) {
140 case AUTH_PROXY:
141 return "proxy";
142 case AUTH_SERVER:
143 return "server";
144 default:
145 NOTREACHED();
146 }
147 }
148
149 // static
SchemeToString(Scheme scheme)150 const char* HttpAuth::SchemeToString(Scheme scheme) {
151 static_assert(std::size(kSchemeNames) == AUTH_SCHEME_MAX,
152 "http auth scheme names incorrect size");
153 if (scheme < AUTH_SCHEME_BASIC || scheme >= AUTH_SCHEME_MAX) {
154 NOTREACHED();
155 }
156 return kSchemeNames[scheme];
157 }
158
159 // static
StringToScheme(const std::string & str)160 HttpAuth::Scheme HttpAuth::StringToScheme(const std::string& str) {
161 for (uint8_t i = 0; i < std::size(kSchemeNames); i++) {
162 if (str == kSchemeNames[i])
163 return static_cast<Scheme>(i);
164 }
165 NOTREACHED();
166 }
167
168 // static
AuthorizationResultToString(AuthorizationResult authorization_result)169 const char* HttpAuth::AuthorizationResultToString(
170 AuthorizationResult authorization_result) {
171 switch (authorization_result) {
172 case AUTHORIZATION_RESULT_ACCEPT:
173 return "accept";
174 case AUTHORIZATION_RESULT_REJECT:
175 return "reject";
176 case AUTHORIZATION_RESULT_STALE:
177 return "stale";
178 case AUTHORIZATION_RESULT_INVALID:
179 return "invalid";
180 case AUTHORIZATION_RESULT_DIFFERENT_REALM:
181 return "different_realm";
182 }
183 NOTREACHED();
184 }
185
186 // static
NetLogAuthorizationResultParams(const char * name,AuthorizationResult authorization_result)187 base::Value::Dict HttpAuth::NetLogAuthorizationResultParams(
188 const char* name,
189 AuthorizationResult authorization_result) {
190 return NetLogParamsWithString(
191 name, AuthorizationResultToString(authorization_result));
192 }
193
194 } // namespace net
195