mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-12-01 17:56:10 +03:00
169 lines
5.0 KiB
C++
169 lines
5.0 KiB
C++
// Copyright 2019 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "net/http/http_auth_ntlm_mechanism.h"
|
|
|
|
#include "base/base64.h"
|
|
#include "base/containers/span.h"
|
|
#include "base/logging.h"
|
|
#include "base/rand_util.h"
|
|
#include "base/time/time.h"
|
|
#include "net/base/net_errors.h"
|
|
#include "net/base/network_interfaces.h"
|
|
#include "net/http/http_auth_challenge_tokenizer.h"
|
|
#include "net/http/http_auth_multi_round_parse.h"
|
|
#include "net/http/http_auth_preferences.h"
|
|
#include "net/http/http_auth_scheme.h"
|
|
|
|
namespace net {
|
|
|
|
namespace {
|
|
|
|
uint64_t GetMSTime() {
|
|
return base::Time::Now().since_origin().InMicroseconds() * 10;
|
|
}
|
|
|
|
void GenerateRandom(uint8_t* output, size_t n) {
|
|
base::RandBytes(output, n);
|
|
}
|
|
|
|
// static
|
|
HttpAuthNtlmMechanism::GetMSTimeProc g_get_ms_time_proc = GetMSTime;
|
|
|
|
// static
|
|
HttpAuthNtlmMechanism::GenerateRandomProc g_generate_random_proc =
|
|
GenerateRandom;
|
|
|
|
// static
|
|
HttpAuthNtlmMechanism::HostNameProc g_host_name_proc = GetHostName;
|
|
|
|
template <typename T>
|
|
T SwapOut(T* target, T source) {
|
|
T t = *target;
|
|
*target = source;
|
|
return t;
|
|
}
|
|
|
|
int SetAuthTokenFromBinaryToken(std::string* auth_token,
|
|
const std::vector<uint8_t>& next_token) {
|
|
if (next_token.empty())
|
|
return ERR_UNEXPECTED;
|
|
|
|
std::string encode_output;
|
|
base::Base64Encode(
|
|
base::StringPiece(reinterpret_cast<const char*>(next_token.data()),
|
|
next_token.size()),
|
|
&encode_output);
|
|
|
|
*auth_token = std::string("NTLM ") + encode_output;
|
|
return OK;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
HttpAuthNtlmMechanism::ScopedProcSetter::ScopedProcSetter(
|
|
GetMSTimeProc ms_time_proc,
|
|
GenerateRandomProc random_proc,
|
|
HostNameProc host_name_proc) {
|
|
old_ms_time_proc_ = SwapOut(&g_get_ms_time_proc, ms_time_proc);
|
|
old_random_proc_ = SwapOut(&g_generate_random_proc, random_proc);
|
|
old_host_name_proc_ = SwapOut(&g_host_name_proc, host_name_proc);
|
|
}
|
|
|
|
HttpAuthNtlmMechanism::ScopedProcSetter::~ScopedProcSetter() {
|
|
g_get_ms_time_proc = old_ms_time_proc_;
|
|
g_generate_random_proc = old_random_proc_;
|
|
g_host_name_proc = old_host_name_proc_;
|
|
}
|
|
|
|
HttpAuthNtlmMechanism::HttpAuthNtlmMechanism(
|
|
const HttpAuthPreferences* http_auth_preferences)
|
|
: ntlm_client_(ntlm::NtlmFeatures(
|
|
http_auth_preferences ? http_auth_preferences->NtlmV2Enabled()
|
|
: true)) {}
|
|
|
|
HttpAuthNtlmMechanism::~HttpAuthNtlmMechanism() = default;
|
|
|
|
bool HttpAuthNtlmMechanism::Init(const NetLogWithSource& net_log) {
|
|
return true;
|
|
}
|
|
|
|
bool HttpAuthNtlmMechanism::NeedsIdentity() const {
|
|
// This gets called for each round-trip. Only require identity on the first
|
|
// call (when challenge_token_ is empty). On subsequent calls, we use the
|
|
// initially established identity.
|
|
return challenge_token_.empty();
|
|
}
|
|
|
|
bool HttpAuthNtlmMechanism::AllowsExplicitCredentials() const {
|
|
return true;
|
|
}
|
|
|
|
HttpAuth::AuthorizationResult HttpAuthNtlmMechanism::ParseChallenge(
|
|
HttpAuthChallengeTokenizer* tok) {
|
|
if (!first_token_sent_)
|
|
return ParseFirstRoundChallenge(HttpAuth::Scheme::AUTH_SCHEME_NTLM, tok);
|
|
|
|
challenge_token_.clear();
|
|
std::string encoded_token;
|
|
return ParseLaterRoundChallenge(HttpAuth::Scheme::AUTH_SCHEME_NTLM, tok,
|
|
&encoded_token, &challenge_token_);
|
|
}
|
|
|
|
int HttpAuthNtlmMechanism::GenerateAuthToken(
|
|
const AuthCredentials* credentials,
|
|
const std::string& spn,
|
|
const std::string& channel_bindings,
|
|
std::string* auth_token,
|
|
const NetLogWithSource& net_log,
|
|
CompletionOnceCallback callback) {
|
|
if (!credentials) {
|
|
LOG(ERROR) << "Username and password are expected to be non-nullptr.";
|
|
return ERR_MISSING_AUTH_CREDENTIALS;
|
|
}
|
|
|
|
if (challenge_token_.empty()) {
|
|
if (first_token_sent_)
|
|
return ERR_UNEXPECTED;
|
|
first_token_sent_ = true;
|
|
return SetAuthTokenFromBinaryToken(auth_token,
|
|
ntlm_client_.GetNegotiateMessage());
|
|
}
|
|
|
|
// The username may be in the form "DOMAIN\user". Parse it into the two
|
|
// components.
|
|
std::u16string domain;
|
|
std::u16string user;
|
|
const std::u16string& username = credentials->username();
|
|
const char16_t backslash_character = '\\';
|
|
size_t backslash_idx = username.find(backslash_character);
|
|
if (backslash_idx == std::u16string::npos) {
|
|
user = username;
|
|
} else {
|
|
domain = username.substr(0, backslash_idx);
|
|
user = username.substr(backslash_idx + 1);
|
|
}
|
|
|
|
std::string hostname = g_host_name_proc();
|
|
if (hostname.empty())
|
|
return ERR_UNEXPECTED;
|
|
|
|
uint8_t client_challenge[8];
|
|
g_generate_random_proc(client_challenge, 8);
|
|
|
|
auto next_token = ntlm_client_.GenerateAuthenticateMessage(
|
|
domain, user, credentials->password(), hostname, channel_bindings, spn,
|
|
g_get_ms_time_proc(), client_challenge,
|
|
base::as_bytes(base::make_span(challenge_token_)));
|
|
|
|
return SetAuthTokenFromBinaryToken(auth_token, next_token);
|
|
}
|
|
|
|
void HttpAuthNtlmMechanism::SetDelegation(
|
|
HttpAuth::DelegationType delegation_type) {
|
|
// Nothing to do.
|
|
}
|
|
|
|
} // namespace net
|