|  | // Copyright 2011 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/url_security_manager.h" | 
|  |  | 
|  | #include <urlmon.h> | 
|  | #include <wrl/client.h> | 
|  |  | 
|  | #include "base/debug/crash_logging.h" | 
|  | #include "base/debug/dump_without_crashing.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/notreached.h" | 
|  | #include "base/strings/string_util.h" | 
|  | #include "base/strings/utf_string_conversions.h" | 
|  | #include "net/http/http_auth_filter.h" | 
|  | #include "url/scheme_host_port.h" | 
|  |  | 
|  | // The Windows implementation of URLSecurityManager uses WinINet/IE's | 
|  | // URL security zone manager.  See the MSDN page "URL Security Zones" at | 
|  | // http://msdn.microsoft.com/en-us/library/ms537021(VS.85).aspx for more | 
|  | // info on the Internet Security Manager and Internet Zone Manager objects. | 
|  | // | 
|  | // On Windows, we honor the WinINet/IE settings and group policy related to | 
|  | // URL Security Zones.  See the Microsoft Knowledge Base article 182569 | 
|  | // "Internet Explorer security zones registry entries for advanced users" | 
|  | // (http://support.microsoft.com/kb/182569) for more info on these registry | 
|  | // keys. | 
|  |  | 
|  | namespace net { | 
|  |  | 
|  | class URLSecurityManagerWin : public URLSecurityManagerAllowlist { | 
|  | public: | 
|  | URLSecurityManagerWin(); | 
|  |  | 
|  | URLSecurityManagerWin(const URLSecurityManagerWin&) = delete; | 
|  | URLSecurityManagerWin& operator=(const URLSecurityManagerWin&) = delete; | 
|  |  | 
|  | ~URLSecurityManagerWin() override; | 
|  |  | 
|  | // URLSecurityManager methods: | 
|  | bool CanUseDefaultCredentials( | 
|  | const url::SchemeHostPort& auth_scheme_host_port) const override; | 
|  |  | 
|  | private: | 
|  | bool EnsureSystemSecurityManager(); | 
|  |  | 
|  | Microsoft::WRL::ComPtr<IInternetSecurityManager> security_manager_; | 
|  | }; | 
|  |  | 
|  | URLSecurityManagerWin::URLSecurityManagerWin() = default; | 
|  | URLSecurityManagerWin::~URLSecurityManagerWin() = default; | 
|  |  | 
|  | bool URLSecurityManagerWin::CanUseDefaultCredentials( | 
|  | const url::SchemeHostPort& auth_scheme_host_port) const { | 
|  | if (HasDefaultAllowlist()) | 
|  | return URLSecurityManagerAllowlist::CanUseDefaultCredentials( | 
|  | auth_scheme_host_port); | 
|  | if (!const_cast<URLSecurityManagerWin*>(this)->EnsureSystemSecurityManager()) | 
|  | return false; | 
|  |  | 
|  | std::u16string url16 = base::ASCIIToUTF16(auth_scheme_host_port.Serialize()); | 
|  | DWORD policy = 0; | 
|  | HRESULT hr; | 
|  | hr = security_manager_->ProcessUrlAction( | 
|  | base::as_wcstr(url16), URLACTION_CREDENTIALS_USE, | 
|  | reinterpret_cast<BYTE*>(&policy), sizeof(policy), nullptr, 0, PUAF_NOUI, | 
|  | 0); | 
|  | if (FAILED(hr)) { | 
|  | LOG(ERROR) << "IInternetSecurityManager::ProcessUrlAction failed: " << hr; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Four possible policies for URLACTION_CREDENTIALS_USE.  See the MSDN page | 
|  | // "About URL Security Zones" at | 
|  | // http://msdn.microsoft.com/en-us/library/ms537183(VS.85).aspx | 
|  | switch (policy) { | 
|  | case URLPOLICY_CREDENTIALS_SILENT_LOGON_OK: | 
|  | return true; | 
|  | case URLPOLICY_CREDENTIALS_CONDITIONAL_PROMPT: { | 
|  | // This policy means "prompt the user for permission if the resource is | 
|  | // not located in the Intranet zone".  TODO(wtc): Note that it's | 
|  | // prompting for permission (to use the default credentials), as opposed | 
|  | // to prompting the user to enter a user name and password. | 
|  |  | 
|  | // URLZONE_LOCAL_MACHINE 0 | 
|  | // URLZONE_INTRANET      1 | 
|  | // URLZONE_TRUSTED       2 | 
|  | // URLZONE_INTERNET      3 | 
|  | // URLZONE_UNTRUSTED     4 | 
|  | DWORD zone = 0; | 
|  | hr = security_manager_->MapUrlToZone(base::as_wcstr(url16), &zone, 0); | 
|  | if (FAILED(hr)) { | 
|  | LOG(ERROR) << "IInternetSecurityManager::MapUrlToZone failed: " << hr; | 
|  | return false; | 
|  | } | 
|  | return zone <= URLZONE_INTRANET; | 
|  | } | 
|  | case URLPOLICY_CREDENTIALS_MUST_PROMPT_USER: | 
|  | return false; | 
|  | case URLPOLICY_CREDENTIALS_ANONYMOUS_ONLY: | 
|  | // TODO(wtc): we should fail the authentication. | 
|  | return false; | 
|  | default: | 
|  | LOG(ERROR) << "Unexpected policy: " << policy; | 
|  | SCOPED_CRASH_KEY_NUMBER("CanUseDefaultCredentials", "policy", policy); | 
|  | base::debug::DumpWithoutCrashing(); | 
|  | return false; | 
|  | } | 
|  | } | 
|  | // TODO(cbentzel): Could CanDelegate use the security zone as well? | 
|  |  | 
|  | bool URLSecurityManagerWin::EnsureSystemSecurityManager() { | 
|  | if (!security_manager_.Get()) { | 
|  | HRESULT hr = | 
|  | CoInternetCreateSecurityManager(nullptr, &security_manager_, 0); | 
|  | if (FAILED(hr) || !security_manager_.Get()) { | 
|  | LOG(ERROR) << "Unable to create the Windows Security Manager instance"; | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // static | 
|  | std::unique_ptr<URLSecurityManager> URLSecurityManager::Create() { | 
|  | return std::make_unique<URLSecurityManagerWin>(); | 
|  | } | 
|  |  | 
|  | }  //  namespace net |