http_auth_handler_basic.cc 4.9 KB

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