diff options
Diffstat (limited to 'Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestSSL.cpp')
-rw-r--r-- | Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestSSL.cpp | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestSSL.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestSSL.cpp new file mode 100644 index 000000000..10c5e73b6 --- /dev/null +++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestSSL.cpp @@ -0,0 +1,434 @@ +/* + * Copyright (C) 2012 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#include "LoadTrackingTest.h" +#include "WebKitTestServer.h" +#include <gtk/gtk.h> + +static WebKitTestServer* kHttpsServer; +static WebKitTestServer* kHttpServer; + +static const char* indexHTML = "<html><body>Testing WebKit2GTK+ SSL</body></htmll>"; +static const char* insecureContentHTML = "<html><script src=\"%s\"></script><body><p>Text + image <img src=\"%s\" align=\"right\"/></p></body></html>"; +static const char TLSExpectedSuccessTitle[] = "WebKit2Gtk+ TLS permission test"; +static const char TLSSuccessHTMLString[] = "<html><head><title>WebKit2Gtk+ TLS permission test</title></head><body></body></html>"; + +class SSLTest: public LoadTrackingTest { +public: + MAKE_GLIB_TEST_FIXTURE(SSLTest); + + SSLTest() + : m_tlsErrors(static_cast<GTlsCertificateFlags>(0)) + { + } + + virtual void provisionalLoadFailed(const gchar* failingURI, GError* error) + { + g_assert_error(error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED); + LoadTrackingTest::provisionalLoadFailed(failingURI, error); + } + + virtual void loadCommitted() + { + GTlsCertificate* certificate = 0; + webkit_web_view_get_tls_info(m_webView, &certificate, &m_tlsErrors); + m_certificate = certificate; + LoadTrackingTest::loadCommitted(); + } + + void waitUntilLoadFinished() + { + m_certificate = 0; + m_tlsErrors = static_cast<GTlsCertificateFlags>(0); + LoadTrackingTest::waitUntilLoadFinished(); + } + + GRefPtr<GTlsCertificate> m_certificate; + GTlsCertificateFlags m_tlsErrors; +}; + +static void testSSL(SSLTest* test, gconstpointer) +{ + WebKitWebContext* context = webkit_web_view_get_context(test->m_webView); + WebKitTLSErrorsPolicy originalPolicy = webkit_web_context_get_tls_errors_policy(context); + webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_IGNORE); + + test->loadURI(kHttpsServer->getURIForPath("/").data()); + test->waitUntilLoadFinished(); + g_assert(test->m_certificate); + // We always expect errors because we are using a self-signed certificate, + // but only G_TLS_CERTIFICATE_UNKNOWN_CA flags should be present. + g_assert(test->m_tlsErrors); + g_assert_cmpuint(test->m_tlsErrors, ==, G_TLS_CERTIFICATE_UNKNOWN_CA); + + // Non HTTPS loads shouldn't have a certificate nor errors. + test->loadHtml(indexHTML, 0); + test->waitUntilLoadFinished(); + g_assert(!test->m_certificate); + g_assert(!test->m_tlsErrors); + + webkit_web_context_set_tls_errors_policy(context, originalPolicy); +} + +class InsecureContentTest: public WebViewTest { +public: + MAKE_GLIB_TEST_FIXTURE(InsecureContentTest); + + InsecureContentTest() + : m_insecureContentRun(false) + , m_insecureContentDisplayed(false) + { + g_signal_connect(m_webView, "insecure-content-detected", G_CALLBACK(insecureContentDetectedCallback), this); + } + + static void insecureContentDetectedCallback(WebKitWebView* webView, WebKitInsecureContentEvent event, InsecureContentTest* test) + { + g_assert(webView == test->m_webView); + + if (event == WEBKIT_INSECURE_CONTENT_RUN) + test->m_insecureContentRun = true; + + if (event == WEBKIT_INSECURE_CONTENT_DISPLAYED) + test->m_insecureContentDisplayed = true; + } + + bool m_insecureContentRun; + bool m_insecureContentDisplayed; +}; + +static void testInsecureContent(InsecureContentTest* test, gconstpointer) +{ + WebKitWebContext* context = webkit_web_view_get_context(test->m_webView); + WebKitTLSErrorsPolicy originalPolicy = webkit_web_context_get_tls_errors_policy(context); + webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_IGNORE); + + test->loadURI(kHttpsServer->getURIForPath("/insecure-content/").data()); + test->waitUntilLoadFinished(); + + g_assert(!test->m_insecureContentRun); + // Images are currently always displayed, even bypassing mixed content settings. Check + // https://bugs.webkit.org/show_bug.cgi?id=142469 + g_assert(test->m_insecureContentDisplayed); + + webkit_web_context_set_tls_errors_policy(context, originalPolicy); +} + +static bool assertIfSSLRequestProcessed = false; + +static void testTLSErrorsPolicy(SSLTest* test, gconstpointer) +{ + WebKitWebContext* context = webkit_web_view_get_context(test->m_webView); + // TLS errors are treated as transport failures by default. + g_assert(webkit_web_context_get_tls_errors_policy(context) == WEBKIT_TLS_ERRORS_POLICY_FAIL); + + assertIfSSLRequestProcessed = true; + test->loadURI(kHttpsServer->getURIForPath("/").data()); + test->waitUntilLoadFinished(); + g_assert(test->m_loadFailed); + g_assert(test->m_loadEvents.contains(LoadTrackingTest::ProvisionalLoadFailed)); + g_assert(!test->m_loadEvents.contains(LoadTrackingTest::LoadCommitted)); + assertIfSSLRequestProcessed = false; + + webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_IGNORE); + g_assert(webkit_web_context_get_tls_errors_policy(context) == WEBKIT_TLS_ERRORS_POLICY_IGNORE); + + test->m_loadFailed = false; + test->loadURI(kHttpsServer->getURIForPath("/").data()); + test->waitUntilLoadFinished(); + g_assert(!test->m_loadFailed); + + webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_FAIL); + g_assert(webkit_web_context_get_tls_errors_policy(context) == WEBKIT_TLS_ERRORS_POLICY_FAIL); +} + +static void testTLSErrorsRedirect(SSLTest* test, gconstpointer) +{ + WebKitWebContext* context = webkit_web_view_get_context(test->m_webView); + WebKitTLSErrorsPolicy originalPolicy = webkit_web_context_get_tls_errors_policy(context); + webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_FAIL); + + assertIfSSLRequestProcessed = true; + test->loadURI(kHttpsServer->getURIForPath("/redirect").data()); + test->waitUntilLoadFinished(); + g_assert(test->m_loadFailed); + g_assert(test->m_loadEvents.contains(LoadTrackingTest::ProvisionalLoadFailed)); + g_assert(!test->m_loadEvents.contains(LoadTrackingTest::LoadCommitted)); + assertIfSSLRequestProcessed = false; + + webkit_web_context_set_tls_errors_policy(context, originalPolicy); +} + +static gboolean webViewAuthenticationCallback(WebKitWebView*, WebKitAuthenticationRequest* request) +{ + g_assert_not_reached(); + return TRUE; +} + + +static void testTLSErrorsHTTPAuth(SSLTest* test, gconstpointer) +{ + WebKitWebContext* context = webkit_web_view_get_context(test->m_webView); + WebKitTLSErrorsPolicy originalPolicy = webkit_web_context_get_tls_errors_policy(context); + webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_FAIL); + + assertIfSSLRequestProcessed = true; + g_signal_connect(test->m_webView, "authenticate", G_CALLBACK(webViewAuthenticationCallback), NULL); + test->loadURI(kHttpsServer->getURIForPath("/auth").data()); + test->waitUntilLoadFinished(); + g_assert(test->m_loadFailed); + g_assert(test->m_loadEvents.contains(LoadTrackingTest::ProvisionalLoadFailed)); + g_assert(!test->m_loadEvents.contains(LoadTrackingTest::LoadCommitted)); + assertIfSSLRequestProcessed = false; + + webkit_web_context_set_tls_errors_policy(context, originalPolicy); +} + +class TLSErrorsTest: public SSLTest { +public: + MAKE_GLIB_TEST_FIXTURE(TLSErrorsTest); + + TLSErrorsTest() + : m_tlsErrors(static_cast<GTlsCertificateFlags>(0)) + , m_failingURI(nullptr) + { + } + + ~TLSErrorsTest() + { + if (m_failingURI) + soup_uri_free(m_failingURI); + } + + bool loadFailedWithTLSErrors(const char* failingURI, GTlsCertificate* certificate, GTlsCertificateFlags tlsErrors) override + { + LoadTrackingTest::loadFailedWithTLSErrors(failingURI, certificate, tlsErrors); + + assertObjectIsDeletedWhenTestFinishes(G_OBJECT(certificate)); + m_certificate = certificate; + m_tlsErrors = tlsErrors; + if (m_failingURI) + soup_uri_free(m_failingURI); + m_failingURI = soup_uri_new(failingURI); + return true; + } + + GTlsCertificate* certificate() const { return m_certificate.get(); } + GTlsCertificateFlags tlsErrors() const { return m_tlsErrors; } + const char* host() const { return m_failingURI->host; } + +private: + GRefPtr<GTlsCertificate> m_certificate; + GTlsCertificateFlags m_tlsErrors; + SoupURI* m_failingURI; +}; + +static void testLoadFailedWithTLSErrors(TLSErrorsTest* test, gconstpointer) +{ + WebKitWebContext* context = webkit_web_view_get_context(test->m_webView); + WebKitTLSErrorsPolicy originalPolicy = webkit_web_context_get_tls_errors_policy(context); + webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_FAIL); + + assertIfSSLRequestProcessed = true; + // The load-failed-with-tls-errors signal should be emitted when there is a TLS failure. + test->loadURI(kHttpsServer->getURIForPath("/test-tls/").data()); + test->waitUntilLoadFinished(); + g_assert(G_IS_TLS_CERTIFICATE(test->certificate())); + g_assert_cmpuint(test->tlsErrors(), ==, G_TLS_CERTIFICATE_UNKNOWN_CA); + g_assert_cmpstr(test->host(), ==, soup_uri_get_host(kHttpsServer->baseURI())); + g_assert_cmpint(test->m_loadEvents[0], ==, LoadTrackingTest::ProvisionalLoadStarted); + g_assert_cmpint(test->m_loadEvents[1], ==, LoadTrackingTest::LoadFailedWithTLSErrors); + g_assert_cmpint(test->m_loadEvents[2], ==, LoadTrackingTest::LoadFinished); + assertIfSSLRequestProcessed = false; + + // Test allowing an exception for this certificate on this host. + webkit_web_context_allow_tls_certificate_for_host(context, test->certificate(), test->host()); + // The page should now load without errors. + test->loadURI(kHttpsServer->getURIForPath("/test-tls/").data()); + test->waitUntilLoadFinished(); + + g_assert_cmpint(test->m_loadEvents[0], ==, LoadTrackingTest::ProvisionalLoadStarted); + g_assert_cmpint(test->m_loadEvents[1], ==, LoadTrackingTest::LoadCommitted); + g_assert_cmpint(test->m_loadEvents[2], ==, LoadTrackingTest::LoadFinished); + g_assert_cmpstr(webkit_web_view_get_title(test->m_webView), ==, TLSExpectedSuccessTitle); + + webkit_web_context_set_tls_errors_policy(context, originalPolicy); +} + +class TLSSubresourceTest : public WebViewTest { +public: + MAKE_GLIB_TEST_FIXTURE(TLSSubresourceTest); + + static void resourceLoadStartedCallback(WebKitWebView* webView, WebKitWebResource* resource, WebKitURIRequest* request, TLSSubresourceTest* test) + { + if (webkit_web_view_get_main_resource(test->m_webView) == resource) + return; + + // Ignore favicons. + if (g_str_has_suffix(webkit_uri_request_get_uri(request), "favicon.ico")) + return; + + test->subresourceLoadStarted(resource); + } + + TLSSubresourceTest() + : m_tlsErrors(static_cast<GTlsCertificateFlags>(0)) + { + g_signal_connect(m_webView, "resource-load-started", G_CALLBACK(resourceLoadStartedCallback), this); + } + + static void subresourceFailedCallback(WebKitWebResource*, GError*) + { + g_assert_not_reached(); + } + + static void subresourceFailedWithTLSErrorsCallback(WebKitWebResource* resource, GTlsCertificate* certificate, GTlsCertificateFlags tlsErrors, TLSSubresourceTest* test) + { + test->subresourceFailedWithTLSErrors(resource, certificate, tlsErrors); + } + + void subresourceLoadStarted(WebKitWebResource* resource) + { + g_signal_connect(resource, "failed", G_CALLBACK(subresourceFailedCallback), nullptr); + g_signal_connect(resource, "failed-with-tls-errors", G_CALLBACK(subresourceFailedWithTLSErrorsCallback), this); + } + + void subresourceFailedWithTLSErrors(WebKitWebResource* resource, GTlsCertificate* certificate, GTlsCertificateFlags tlsErrors) + { + m_certificate = certificate; + m_tlsErrors = tlsErrors; + g_main_loop_quit(m_mainLoop); + } + + void waitUntilSubresourceLoadFail() + { + g_main_loop_run(m_mainLoop); + } + + GRefPtr<GTlsCertificate> m_certificate; + GTlsCertificateFlags m_tlsErrors; +}; + +static void testSubresourceLoadFailedWithTLSErrors(TLSSubresourceTest* test, gconstpointer) +{ + WebKitWebContext* context = webkit_web_view_get_context(test->m_webView); + webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_FAIL); + + assertIfSSLRequestProcessed = true; + test->loadURI(kHttpServer->getURIForPath("/").data()); + test->waitUntilSubresourceLoadFail(); + g_assert(G_IS_TLS_CERTIFICATE(test->m_certificate.get())); + g_assert_cmpuint(test->m_tlsErrors, ==, G_TLS_CERTIFICATE_UNKNOWN_CA); + assertIfSSLRequestProcessed = false; +} + +static void httpsServerCallback(SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer) +{ + if (message->method != SOUP_METHOD_GET) { + soup_message_set_status(message, SOUP_STATUS_NOT_IMPLEMENTED); + return; + } + + g_assert(!assertIfSSLRequestProcessed); + + if (g_str_equal(path, "/")) { + soup_message_set_status(message, SOUP_STATUS_OK); + soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, indexHTML, strlen(indexHTML)); + soup_message_body_complete(message->response_body); + } else if (g_str_equal(path, "/insecure-content/")) { + GUniquePtr<char> responseHTML(g_strdup_printf(insecureContentHTML, kHttpServer->getURIForPath("/test-script").data(), kHttpServer->getURIForPath("/test-image").data())); + soup_message_body_append(message->response_body, SOUP_MEMORY_COPY, responseHTML.get(), strlen(responseHTML.get())); + soup_message_set_status(message, SOUP_STATUS_OK); + soup_message_body_complete(message->response_body); + } else if (g_str_equal(path, "/test-tls/")) { + soup_message_set_status(message, SOUP_STATUS_OK); + soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, TLSSuccessHTMLString, strlen(TLSSuccessHTMLString)); + soup_message_body_complete(message->response_body); + } else if (g_str_equal(path, "/redirect")) { + soup_message_set_status(message, SOUP_STATUS_MOVED_PERMANENTLY); + soup_message_headers_append(message->response_headers, "Location", kHttpServer->getURIForPath("/test-image").data()); + } else if (g_str_equal(path, "/auth")) { + soup_message_set_status(message, SOUP_STATUS_UNAUTHORIZED); + soup_message_headers_append(message->response_headers, "WWW-Authenticate", "Basic realm=\"HTTPS auth\""); + } else if (g_str_equal(path, "/style.css")) { + soup_message_set_status(message, SOUP_STATUS_OK); + static const char* styleCSS = "body { color: black; }"; + soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, styleCSS, strlen(styleCSS)); + } else + soup_message_set_status(message, SOUP_STATUS_NOT_FOUND); +} + +static void httpServerCallback(SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer) +{ + if (message->method != SOUP_METHOD_GET) { + soup_message_set_status(message, SOUP_STATUS_NOT_IMPLEMENTED); + return; + } + + if (g_str_equal(path, "/test-script")) { + GUniquePtr<char> pathToFile(g_build_filename(Test::getResourcesDir().data(), "link-title.js", nullptr)); + char* contents; + gsize length; + g_file_get_contents(pathToFile.get(), &contents, &length, 0); + + soup_message_body_append(message->response_body, SOUP_MEMORY_TAKE, contents, length); + soup_message_set_status(message, SOUP_STATUS_OK); + soup_message_body_complete(message->response_body); + } else if (g_str_equal(path, "/test-image")) { + GUniquePtr<char> pathToFile(g_build_filename(Test::getResourcesDir().data(), "blank.ico", nullptr)); + char* contents; + gsize length; + g_file_get_contents(pathToFile.get(), &contents, &length, 0); + + soup_message_body_append(message->response_body, SOUP_MEMORY_TAKE, contents, length); + soup_message_set_status(message, SOUP_STATUS_OK); + soup_message_body_complete(message->response_body); + } else if (g_str_equal(path, "/")) { + soup_message_set_status(message, SOUP_STATUS_OK); + char* responseHTML = g_strdup_printf("<html><head><link rel='stylesheet' href='%s' type='text/css'></head><body>SSL subresource test</body></html>", + kHttpsServer->getURIForPath("/style.css").data()); + soup_message_body_append(message->response_body, SOUP_MEMORY_TAKE, responseHTML, strlen(responseHTML)); + soup_message_body_complete(message->response_body); + } else + soup_message_set_status(message, SOUP_STATUS_NOT_FOUND); +} + +void beforeAll() +{ + kHttpsServer = new WebKitTestServer(WebKitTestServer::ServerHTTPS); + kHttpsServer->run(httpsServerCallback); + + kHttpServer = new WebKitTestServer(WebKitTestServer::ServerHTTP); + kHttpServer->run(httpServerCallback); + + SSLTest::add("WebKitWebView", "ssl", testSSL); + InsecureContentTest::add("WebKitWebView", "insecure-content", testInsecureContent); + SSLTest::add("WebKitWebView", "tls-errors-policy", testTLSErrorsPolicy); + SSLTest::add("WebKitWebView", "tls-errors-redirect-to-http", testTLSErrorsRedirect); + SSLTest::add("WebKitWebView", "tls-http-auth", testTLSErrorsHTTPAuth); + TLSSubresourceTest::add("WebKitWebView", "tls-subresource", testSubresourceLoadFailedWithTLSErrors); + TLSErrorsTest::add("WebKitWebView", "load-failed-with-tls-errors", testLoadFailedWithTLSErrors); +} + +void afterAll() +{ + delete kHttpsServer; + delete kHttpServer; +} |