// Copyright (c) 2012 The Chromium Authors. All rights reserved. // 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_handler_ntlm.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_preferences.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); } } // namespace // static HttpAuthHandlerNTLM::GetMSTimeProc HttpAuthHandlerNTLM::get_ms_time_proc_ = GetMSTime; // static HttpAuthHandlerNTLM::GenerateRandomProc HttpAuthHandlerNTLM::generate_random_proc_ = GenerateRandom; // static HttpAuthHandlerNTLM::HostNameProc HttpAuthHandlerNTLM::get_host_name_proc_ = GetHostName; HttpAuthHandlerNTLM::HttpAuthHandlerNTLM( const HttpAuthPreferences* http_auth_preferences) : ntlm_client_(ntlm::NtlmFeatures( http_auth_preferences ? http_auth_preferences->NtlmV2Enabled() : false)) {} bool HttpAuthHandlerNTLM::NeedsIdentity() { // This gets called for each round-trip. Only require identity on // the first call (when auth_data_ is empty). On subsequent calls, // we use the initially established identity. return auth_data_.empty(); } bool HttpAuthHandlerNTLM::AllowsDefaultCredentials() { // Default credentials are not supported in the portable implementation of // NTLM, but are supported in the SSPI implementation. return false; } int HttpAuthHandlerNTLM::InitializeBeforeFirstChallenge() { return OK; } HttpAuthHandlerNTLM::~HttpAuthHandlerNTLM() = default; // static HttpAuthHandlerNTLM::GetMSTimeProc HttpAuthHandlerNTLM::SetGetMSTimeProc( GetMSTimeProc proc) { GetMSTimeProc old_proc = get_ms_time_proc_; get_ms_time_proc_ = proc; return old_proc; } // static HttpAuthHandlerNTLM::GenerateRandomProc HttpAuthHandlerNTLM::SetGenerateRandomProc(GenerateRandomProc proc) { GenerateRandomProc old_proc = generate_random_proc_; generate_random_proc_ = proc; return old_proc; } // static HttpAuthHandlerNTLM::HostNameProc HttpAuthHandlerNTLM::SetHostNameProc( HostNameProc proc) { HostNameProc old_proc = get_host_name_proc_; get_host_name_proc_ = proc; return old_proc; } HttpAuthHandlerNTLM::Factory::Factory() = default; HttpAuthHandlerNTLM::Factory::~Factory() = default; ntlm::Buffer HttpAuthHandlerNTLM::GetNextToken(const ntlm::Buffer& in_token) { // If in_token is non-empty, then assume it contains a challenge message, // and generate the Authenticate message in reply. Otherwise return the // Negotiate message. if (in_token.empty()) { return ntlm_client_.GetNegotiateMessage(); } std::string hostname = get_host_name_proc_(); if (hostname.empty()) return ntlm::Buffer(); uint8_t client_challenge[8]; generate_random_proc_(client_challenge, 8); uint64_t client_time = get_ms_time_proc_(); return ntlm_client_.GenerateAuthenticateMessage( domain_, credentials_.username(), credentials_.password(), hostname, channel_bindings_, CreateSPN(origin_), client_time, client_challenge, in_token); } int HttpAuthHandlerNTLM::Factory::CreateAuthHandler( HttpAuthChallengeTokenizer* challenge, HttpAuth::Target target, const SSLInfo& ssl_info, const GURL& origin, CreateReason reason, int digest_nonce_count, const NetLogWithSource& net_log, std::unique_ptr* handler) { if (reason == CREATE_PREEMPTIVE) return ERR_UNSUPPORTED_AUTH_SCHEME; // TODO(cbentzel): Move towards model of parsing in the factory // method and only constructing when valid. // NOTE: Default credentials are not supported for the portable implementation // of NTLM. std::unique_ptr tmp_handler( new HttpAuthHandlerNTLM(http_auth_preferences())); if (!tmp_handler->InitFromChallenge(challenge, target, ssl_info, origin, net_log)) return ERR_INVALID_RESPONSE; handler->swap(tmp_handler); return OK; } } // namespace net