xref: /aosp_15_r20/external/cronet/net/http/http_auth_handler_basic.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 #include "net/http/http_auth_handler_basic.h"
6 
7 #include <string>
8 
9 #include "base/base64.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "net/base/net_errors.h"
13 #include "net/base/net_string_util.h"
14 #include "net/dns/host_resolver.h"
15 #include "net/http/http_auth.h"
16 #include "net/http/http_auth_challenge_tokenizer.h"
17 #include "net/http/http_auth_preferences.h"
18 #include "net/http/http_auth_scheme.h"
19 #include "url/scheme_host_port.h"
20 #include "url/url_constants.h"
21 
22 namespace net {
23 
24 namespace {
25 
26 // Parses a realm from an auth challenge, and converts to UTF8-encoding.
27 // Returns whether the realm is invalid or the parameters are invalid.
28 //
29 // Note that if a realm was not specified, we will default it to "";
30 // so specifying 'Basic realm=""' is equivalent to 'Basic'.
31 //
32 // This is more generous than RFC 2617, which is pretty clear in the
33 // production of challenge that realm is required.
34 //
35 // We allow it to be compatibility with certain embedded webservers that don't
36 // include a realm (see http://crbug.com/20984.)
37 //
38 // The over-the-wire realm is encoded as ISO-8859-1 (aka Latin-1).
39 //
40 // TODO(cbentzel): Realm may need to be decoded using RFC 2047 rules as
41 // well, see http://crbug.com/25790.
ParseRealm(const HttpAuthChallengeTokenizer & tokenizer,std::string * realm)42 bool ParseRealm(const HttpAuthChallengeTokenizer& tokenizer,
43                 std::string* realm) {
44   CHECK(realm);
45   realm->clear();
46   HttpUtil::NameValuePairsIterator parameters = tokenizer.param_pairs();
47   while (parameters.GetNext()) {
48     if (!base::EqualsCaseInsensitiveASCII(parameters.name_piece(), "realm"))
49       continue;
50 
51     if (!ConvertToUtf8AndNormalize(parameters.value_piece(), kCharsetLatin1,
52                                    realm)) {
53       return false;
54     }
55   }
56   return parameters.valid();
57 }
58 
59 }  // namespace
60 
Init(HttpAuthChallengeTokenizer * challenge,const SSLInfo & ssl_info,const NetworkAnonymizationKey & network_anonymization_key)61 bool HttpAuthHandlerBasic::Init(
62     HttpAuthChallengeTokenizer* challenge,
63     const SSLInfo& ssl_info,
64     const NetworkAnonymizationKey& network_anonymization_key) {
65   auth_scheme_ = HttpAuth::AUTH_SCHEME_BASIC;
66   score_ = 1;
67   properties_ = 0;
68   return ParseChallenge(challenge);
69 }
70 
ParseChallenge(HttpAuthChallengeTokenizer * challenge)71 bool HttpAuthHandlerBasic::ParseChallenge(
72     HttpAuthChallengeTokenizer* challenge) {
73   if (challenge->auth_scheme() != kBasicAuthScheme)
74     return false;
75 
76   std::string realm;
77   if (!ParseRealm(*challenge, &realm))
78     return false;
79 
80   realm_ = realm;
81   return true;
82 }
83 
GenerateAuthTokenImpl(const AuthCredentials * credentials,const HttpRequestInfo *,CompletionOnceCallback callback,std::string * auth_token)84 int HttpAuthHandlerBasic::GenerateAuthTokenImpl(
85     const AuthCredentials* credentials,
86     const HttpRequestInfo*,
87     CompletionOnceCallback callback,
88     std::string* auth_token) {
89   DCHECK(credentials);
90   // Firefox, Safari and Chromium all use UTF-8 encoding; IE uses iso-8859-1.
91   // RFC7617 does not specify a default encoding, but UTF-8 is the only allowed
92   // value for the optional charset parameter on the challenge.
93   std::string base64_username_password =
94       base::Base64Encode(base::UTF16ToUTF8(credentials->username()) + ":" +
95                          base::UTF16ToUTF8(credentials->password()));
96   *auth_token = "Basic " + base64_username_password;
97   return OK;
98 }
99 
HandleAnotherChallengeImpl(HttpAuthChallengeTokenizer * challenge)100 HttpAuth::AuthorizationResult HttpAuthHandlerBasic::HandleAnotherChallengeImpl(
101     HttpAuthChallengeTokenizer* challenge) {
102   // Basic authentication is always a single round, so any responses
103   // should be treated as a rejection.  However, if the new challenge
104   // is for a different realm, then indicate the realm change.
105   std::string realm;
106   if (!ParseRealm(*challenge, &realm))
107     return HttpAuth::AUTHORIZATION_RESULT_INVALID;
108   return (realm_ != realm) ? HttpAuth::AUTHORIZATION_RESULT_DIFFERENT_REALM
109                            : HttpAuth::AUTHORIZATION_RESULT_REJECT;
110 }
111 
112 HttpAuthHandlerBasic::Factory::Factory() = default;
113 
114 HttpAuthHandlerBasic::Factory::~Factory() = default;
115 
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)116 int HttpAuthHandlerBasic::Factory::CreateAuthHandler(
117     HttpAuthChallengeTokenizer* challenge,
118     HttpAuth::Target target,
119     const SSLInfo& ssl_info,
120     const NetworkAnonymizationKey& network_anonymization_key,
121     const url::SchemeHostPort& scheme_host_port,
122     CreateReason reason,
123     int digest_nonce_count,
124     const NetLogWithSource& net_log,
125     HostResolver* host_resolver,
126     std::unique_ptr<HttpAuthHandler>* handler) {
127   if (http_auth_preferences() &&
128       !http_auth_preferences()->basic_over_http_enabled() &&
129       scheme_host_port.scheme() == url::kHttpScheme) {
130     return ERR_UNSUPPORTED_AUTH_SCHEME;
131   }
132   // TODO(cbentzel): Move towards model of parsing in the factory
133   //                 method and only constructing when valid.
134   auto tmp_handler = std::make_unique<HttpAuthHandlerBasic>();
135   if (!tmp_handler->InitFromChallenge(challenge, target, ssl_info,
136                                       network_anonymization_key,
137                                       scheme_host_port, net_log)) {
138     return ERR_INVALID_RESPONSE;
139   }
140   *handler = std::move(tmp_handler);
141   return OK;
142 }
143 
144 }  // namespace net
145