1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
// 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
|