http_auth_ntlm_mechanism.cc 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // Copyright 2019 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_ntlm_mechanism.h"
  5. #include "base/base64.h"
  6. #include "base/containers/span.h"
  7. #include "base/logging.h"
  8. #include "base/rand_util.h"
  9. #include "base/time/time.h"
  10. #include "net/base/net_errors.h"
  11. #include "net/base/network_interfaces.h"
  12. #include "net/http/http_auth_challenge_tokenizer.h"
  13. #include "net/http/http_auth_multi_round_parse.h"
  14. #include "net/http/http_auth_preferences.h"
  15. #include "net/http/http_auth_scheme.h"
  16. namespace net {
  17. namespace {
  18. uint64_t GetMSTime() {
  19. return base::Time::Now().since_origin().InMicroseconds() * 10;
  20. }
  21. void GenerateRandom(uint8_t* output, size_t n) {
  22. base::RandBytes(output, n);
  23. }
  24. // static
  25. HttpAuthNtlmMechanism::GetMSTimeProc g_get_ms_time_proc = GetMSTime;
  26. // static
  27. HttpAuthNtlmMechanism::GenerateRandomProc g_generate_random_proc =
  28. GenerateRandom;
  29. // static
  30. HttpAuthNtlmMechanism::HostNameProc g_host_name_proc = GetHostName;
  31. template <typename T>
  32. T SwapOut(T* target, T source) {
  33. T t = *target;
  34. *target = source;
  35. return t;
  36. }
  37. int SetAuthTokenFromBinaryToken(std::string* auth_token,
  38. const std::vector<uint8_t>& next_token) {
  39. if (next_token.empty())
  40. return ERR_UNEXPECTED;
  41. std::string encode_output;
  42. base::Base64Encode(
  43. base::StringPiece(reinterpret_cast<const char*>(next_token.data()),
  44. next_token.size()),
  45. &encode_output);
  46. *auth_token = std::string("NTLM ") + encode_output;
  47. return OK;
  48. }
  49. } // namespace
  50. HttpAuthNtlmMechanism::ScopedProcSetter::ScopedProcSetter(
  51. GetMSTimeProc ms_time_proc,
  52. GenerateRandomProc random_proc,
  53. HostNameProc host_name_proc) {
  54. old_ms_time_proc_ = SwapOut(&g_get_ms_time_proc, ms_time_proc);
  55. old_random_proc_ = SwapOut(&g_generate_random_proc, random_proc);
  56. old_host_name_proc_ = SwapOut(&g_host_name_proc, host_name_proc);
  57. }
  58. HttpAuthNtlmMechanism::ScopedProcSetter::~ScopedProcSetter() {
  59. g_get_ms_time_proc = old_ms_time_proc_;
  60. g_generate_random_proc = old_random_proc_;
  61. g_host_name_proc = old_host_name_proc_;
  62. }
  63. HttpAuthNtlmMechanism::HttpAuthNtlmMechanism(
  64. const HttpAuthPreferences* http_auth_preferences)
  65. : ntlm_client_(ntlm::NtlmFeatures(
  66. http_auth_preferences ? http_auth_preferences->NtlmV2Enabled()
  67. : true)) {}
  68. HttpAuthNtlmMechanism::~HttpAuthNtlmMechanism() = default;
  69. bool HttpAuthNtlmMechanism::Init(const NetLogWithSource& net_log) {
  70. return true;
  71. }
  72. bool HttpAuthNtlmMechanism::NeedsIdentity() const {
  73. // This gets called for each round-trip. Only require identity on the first
  74. // call (when challenge_token_ is empty). On subsequent calls, we use the
  75. // initially established identity.
  76. return challenge_token_.empty();
  77. }
  78. bool HttpAuthNtlmMechanism::AllowsExplicitCredentials() const {
  79. return true;
  80. }
  81. HttpAuth::AuthorizationResult HttpAuthNtlmMechanism::ParseChallenge(
  82. HttpAuthChallengeTokenizer* tok) {
  83. if (!first_token_sent_)
  84. return ParseFirstRoundChallenge(HttpAuth::Scheme::AUTH_SCHEME_NTLM, tok);
  85. challenge_token_.clear();
  86. std::string encoded_token;
  87. return ParseLaterRoundChallenge(HttpAuth::Scheme::AUTH_SCHEME_NTLM, tok,
  88. &encoded_token, &challenge_token_);
  89. }
  90. int HttpAuthNtlmMechanism::GenerateAuthToken(
  91. const AuthCredentials* credentials,
  92. const std::string& spn,
  93. const std::string& channel_bindings,
  94. std::string* auth_token,
  95. const NetLogWithSource& net_log,
  96. CompletionOnceCallback callback) {
  97. if (!credentials) {
  98. LOG(ERROR) << "Username and password are expected to be non-nullptr.";
  99. return ERR_MISSING_AUTH_CREDENTIALS;
  100. }
  101. if (challenge_token_.empty()) {
  102. if (first_token_sent_)
  103. return ERR_UNEXPECTED;
  104. first_token_sent_ = true;
  105. return SetAuthTokenFromBinaryToken(auth_token,
  106. ntlm_client_.GetNegotiateMessage());
  107. }
  108. // The username may be in the form "DOMAIN\user". Parse it into the two
  109. // components.
  110. std::u16string domain;
  111. std::u16string user;
  112. const std::u16string& username = credentials->username();
  113. const char16_t backslash_character = '\\';
  114. size_t backslash_idx = username.find(backslash_character);
  115. if (backslash_idx == std::u16string::npos) {
  116. user = username;
  117. } else {
  118. domain = username.substr(0, backslash_idx);
  119. user = username.substr(backslash_idx + 1);
  120. }
  121. std::string hostname = g_host_name_proc();
  122. if (hostname.empty())
  123. return ERR_UNEXPECTED;
  124. uint8_t client_challenge[8];
  125. g_generate_random_proc(client_challenge, 8);
  126. auto next_token = ntlm_client_.GenerateAuthenticateMessage(
  127. domain, user, credentials->password(), hostname, channel_bindings, spn,
  128. g_get_ms_time_proc(), client_challenge,
  129. base::as_bytes(base::make_span(challenge_token_)));
  130. return SetAuthTokenFromBinaryToken(auth_token, next_token);
  131. }
  132. void HttpAuthNtlmMechanism::SetDelegation(
  133. HttpAuth::DelegationType delegation_type) {
  134. // Nothing to do.
  135. }
  136. } // namespace net