Commit b056baab authored by estark's avatar estark Committed by Commit bot

Fix DevTools showCertificateViewer to use visible entry

When the Security.showCertificateViewer command is received by the
browser, it should show the certificate for the visible entry, not
necessarily the last committed entry, because there might be a transient
entry for an interstitial overlaying the last committed entry.

BUG=647759

Review-Url: https://codereview.chromium.org/2344113003
Cr-Commit-Position: refs/heads/master@{#419359}
parent 04cd71f8
......@@ -14,12 +14,18 @@
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "build/build_config.h"
#include "content/browser/frame_host/interstitial_page_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/interstitial_page_delegate.h"
#include "content/public/browser/javascript_dialog_manager.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/ssl_status.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test_utils.h"
......@@ -28,7 +34,9 @@
#include "content/public/test/test_navigation_observer.h"
#include "content/shell/browser/shell.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/cert_test_util.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/test_data_directory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/compositor/compositor_switches.h"
......@@ -117,7 +125,16 @@ class DevToolsProtocolTest : public ContentBrowserTest,
DevToolsProtocolTest()
: last_sent_id_(0),
waiting_for_command_result_id_(0),
in_dispatch_(false) {
in_dispatch_(false),
last_shown_certificate_(nullptr),
ok_cert_(nullptr),
expired_cert_(nullptr) {}
void SetUpOnMainThread() override {
ok_cert_ =
net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
expired_cert_ = net::ImportCertFromFile(net::GetTestCertsDirectory(),
"expired_cert.pem");
}
protected:
......@@ -131,6 +148,12 @@ class DevToolsProtocolTest : public ContentBrowserTest,
return true;
}
void ShowCertificateViewerInDevTools(
WebContents* web_contents,
scoped_refptr<net::X509Certificate> certificate) override {
last_shown_certificate_ = certificate;
}
void SendCommand(const std::string& method,
std::unique_ptr<base::DictionaryValue> params) {
SendCommand(method, std::move(params), true);
......@@ -272,6 +295,16 @@ class DevToolsProtocolTest : public ContentBrowserTest,
return urls;
}
const scoped_refptr<net::X509Certificate>& last_shown_certificate() {
return last_shown_certificate_;
}
const scoped_refptr<net::X509Certificate>& ok_cert() { return ok_cert_; }
const scoped_refptr<net::X509Certificate>& expired_cert() {
return expired_cert_;
}
std::unique_ptr<base::DictionaryValue> result_;
scoped_refptr<DevToolsAgentHost> agent_host_;
int last_sent_id_;
......@@ -321,6 +354,15 @@ class DevToolsProtocolTest : public ContentBrowserTest,
std::string waiting_for_notification_;
int waiting_for_command_result_id_;
bool in_dispatch_;
scoped_refptr<net::X509Certificate> last_shown_certificate_;
scoped_refptr<net::X509Certificate> ok_cert_;
scoped_refptr<net::X509Certificate> expired_cert_;
};
class TestInterstitialDelegate : public InterstitialPageDelegate {
private:
// InterstitialPageDelegate:
std::string GetHTMLContents() override { return "<p>Interstitial</p>"; }
};
class SyntheticKeyEventTest : public DevToolsProtocolTest {
......@@ -937,4 +979,57 @@ IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, VirtualTimeTest) {
EXPECT_THAT(console_messages_, ElementsAre("before", "done", "after"));
}
// Tests that the Security.showCertificateViewer command shows the
// certificate corresponding to the visible navigation entry, even when
// an interstitial is showing. Regression test for
// https://crbug.com/647759.
IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, ShowCertificateViewer) {
// First test that the correct certificate is shown for a normal
// (non-interstitial) page.
NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
Attach();
// Set a dummy certificate on the NavigationEntry.
shell()
->web_contents()
->GetController()
.GetVisibleEntry()
->GetSSL()
.certificate = ok_cert();
std::unique_ptr<base::DictionaryValue> params1(new base::DictionaryValue());
SendCommand("Security.showCertificateViewer", std::move(params1), true);
scoped_refptr<net::X509Certificate> normal_page_cert = shell()
->web_contents()
->GetController()
.GetVisibleEntry()
->GetSSL()
.certificate;
ASSERT_TRUE(normal_page_cert);
EXPECT_EQ(normal_page_cert, last_shown_certificate());
// Now test that the correct certificate is shown on an interstitial.
TestInterstitialDelegate* delegate = new TestInterstitialDelegate;
WebContentsImpl* web_contents =
static_cast<WebContentsImpl*>(shell()->web_contents());
GURL interstitial_url("https://example.test");
InterstitialPageImpl* interstitial = new InterstitialPageImpl(
web_contents, static_cast<RenderWidgetHostDelegate*>(web_contents), true,
interstitial_url, delegate);
interstitial->Show();
WaitForInterstitialAttach(web_contents);
// Set the transient navigation entry certificate.
NavigationEntry* transient_entry =
web_contents->GetController().GetTransientEntry();
ASSERT_TRUE(transient_entry);
transient_entry->GetSSL().certificate = expired_cert();
ASSERT_TRUE(transient_entry->GetSSL().certificate);
std::unique_ptr<base::DictionaryValue> params2(new base::DictionaryValue());
SendCommand("Security.showCertificateViewer", std::move(params2), true);
EXPECT_EQ(transient_entry->GetSSL().certificate, last_shown_certificate());
}
} // namespace content
......@@ -154,8 +154,8 @@ Response SecurityHandler::ShowCertificateViewer() {
if (!host_)
return Response::InternalError("Could not connect to view");
WebContents* web_contents = WebContents::FromRenderFrameHost(host_);
scoped_refptr<net::X509Certificate> certificate = web_contents->
GetController().GetLastCommittedEntry()->GetSSL().certificate;
scoped_refptr<net::X509Certificate> certificate =
web_contents->GetController().GetVisibleEntry()->GetSSL().certificate;
if (!certificate)
return Response::InternalError("Could not find certificate");
web_contents->GetDelegate()->ShowCertificateViewerInDevTools(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment