Add the capability to change all of a website's cookies to SameSite=Strict
authorwilander@apple.com <wilander@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 23 Mar 2020 23:00:50 +0000 (23:00 +0000)
committerwilander@apple.com <wilander@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 23 Mar 2020 23:00:50 +0000 (23:00 +0000)
https://bugs.webkit.org/show_bug.cgi?id=209369
<rdar://problem/60710690>

Reviewed by Alex Christensen and David Kilzer.

Source/WebCore:

Test: http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict.html

* platform/network/NetworkStorageSession.cpp:
(WebCore::NetworkStorageSession::setAllCookiesToSameSiteStrict):
    Stub function for non-Cocoa platforms.
* platform/network/NetworkStorageSession.h:
* platform/network/cocoa/NetworkStorageSessionCocoa.mm:
(WebCore::NetworkStorageSession::setAllCookiesToSameSiteStrict):
* testing/Internals.h:
    Added code to expose SameSite=None and path properties of cookies.
    However, they don't seem to carry over so I'll have to revisit the
    internal workings.

Source/WebKit:

These changes add test infrastructure to run function
WebCore::NetworkStorageSession::setAllCookiesToSameSiteStrict() in the
network process.

* NetworkProcess/NetworkProcess.cpp:
(WebKit::NetworkProcess::setToSameSiteStrictCookiesForTesting):
* NetworkProcess/NetworkProcess.h:
* NetworkProcess/NetworkProcess.messages.in:
* UIProcess/API/C/WKWebsiteDataStoreRef.cpp:
(WKWebsiteDataStoreSetResourceLoadStatisticsToSameSiteStrictCookiesForTesting):
* UIProcess/API/C/WKWebsiteDataStoreRef.h:
* UIProcess/Network/NetworkProcessProxy.cpp:
(WebKit::NetworkProcessProxy::setToSameSiteStrictCookiesForTesting):
* UIProcess/Network/NetworkProcessProxy.h:
* UIProcess/WebsiteData/WebsiteDataStore.cpp:
(WebKit::WebsiteDataStore::setResourceLoadStatisticsToSameSiteStrictCookiesForTesting):
* UIProcess/WebsiteData/WebsiteDataStore.h:

Source/WTF:

* wtf/PlatformHave.h:
    Adds HAVE_CFNETWORK_SAMESITE_COOKIE_API for macOS Catalina and up,
    iOS 13 and up, Catalyst, watchOS, and Apple TV.

Tools:

These changes add TestRunner function statisticsSetToSameSiteStrictCookies().

* WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
* WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
(WTR::InjectedBundle::didReceiveMessageToPage):
* WebKitTestRunner/InjectedBundle/TestRunner.cpp:
(WTR::TestRunner::statisticsSetToSameSiteStrictCookies):
(WTR::TestRunner::statisticsCallDidSetToSameSiteStrictCookiesCallback):
* WebKitTestRunner/InjectedBundle/TestRunner.h:
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::setStatisticsToSameSiteStrictCookies):
* WebKitTestRunner/TestController.h:
* WebKitTestRunner/TestInvocation.cpp:
(WTR::TestInvocation::didReceiveMessageFromInjectedBundle):
(WTR::TestInvocation::didSetToSameSiteStrictCookies):
* WebKitTestRunner/TestInvocation.h:

LayoutTests:

* http/tests/resourceLoadStatistics/resources/set-all-kinds-of-cookies.php: Added.
* http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict-expected.txt: Added.
* http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict.html: Added.
* platform/ios/TestExpectations:
    Marked http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict.html
    as Pass.
* platform/mac-wk2/TestExpectations:
    Marked http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict.html
    as Pass for Catalina+.
* platform/wk2/TestExpectations:
    Skipped http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict.html
    since it's only available on macOS Catalina and up and the functionality is not
    implemented on non-Cocoa platforms.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@258884 268f45cc-cd09-0410-ab3c-d52691b4dbfc

33 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/resourceLoadStatistics/resources/set-all-kinds-of-cookies.php [new file with mode: 0644]
LayoutTests/http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict.html [new file with mode: 0644]
LayoutTests/platform/ios/TestExpectations
LayoutTests/platform/mac-wk2/TestExpectations
LayoutTests/platform/wk2/TestExpectations
Source/WTF/ChangeLog
Source/WTF/wtf/PlatformHave.h
Source/WebCore/ChangeLog
Source/WebCore/platform/network/NetworkStorageSession.cpp
Source/WebCore/platform/network/NetworkStorageSession.h
Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm
Source/WebCore/testing/Internals.h
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/NetworkProcess.cpp
Source/WebKit/NetworkProcess/NetworkProcess.h
Source/WebKit/NetworkProcess/NetworkProcess.messages.in
Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.cpp
Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.h
Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp
Source/WebKit/UIProcess/Network/NetworkProcessProxy.h
Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp
Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h
Tools/ChangeLog
Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl
Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp
Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp
Tools/WebKitTestRunner/InjectedBundle/TestRunner.h
Tools/WebKitTestRunner/TestController.cpp
Tools/WebKitTestRunner/TestController.h
Tools/WebKitTestRunner/TestInvocation.cpp
Tools/WebKitTestRunner/TestInvocation.h

index d552774..252d84c 100644 (file)
@@ -1,3 +1,25 @@
+2020-03-23  John Wilander  <wilander@apple.com>
+
+        Add the capability to change all of a website's cookies to SameSite=Strict
+        https://bugs.webkit.org/show_bug.cgi?id=209369
+        <rdar://problem/60710690>
+
+        Reviewed by Alex Christensen and David Kilzer.
+
+        * http/tests/resourceLoadStatistics/resources/set-all-kinds-of-cookies.php: Added.
+        * http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict-expected.txt: Added.
+        * http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict.html: Added.
+        * platform/ios/TestExpectations:
+            Marked http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict.html
+            as Pass.
+        * platform/mac-wk2/TestExpectations:
+            Marked http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict.html
+            as Pass for Catalina+.
+        * platform/wk2/TestExpectations:
+            Skipped http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict.html
+            since it's only available on macOS Catalina and up and the functionality is not
+            implemented on non-Cocoa platforms.
+
 2020-03-23  Jason Lawrence  <lawrence.j@apple.com>
 
         [ Mac wk1 Debug ] http/tests/css/shared-stylesheet-mutation-preconstruct.html is flaky failing.
diff --git a/LayoutTests/http/tests/resourceLoadStatistics/resources/set-all-kinds-of-cookies.php b/LayoutTests/http/tests/resourceLoadStatistics/resources/set-all-kinds-of-cookies.php
new file mode 100644 (file)
index 0000000..3cb2387
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+header("HTTP/1.1 200 OK");
+
+setcookie("persistentCookie", "1", time() + 300, "/");
+setcookie("persistentSecureCookie", "1", time() + 300, "/", "", TRUE);
+setcookie("persistentHttpOnlyCookie", "1", time() + 300, "/", "", FALSE, TRUE);
+setcookie("persistentSameSiteLaxCookie", "1", ["expires" => time() + 300, "path" => "/", "samesite" => "Lax"]);
+setcookie("persistentSameSiteStrictCookie", "1", ["expires" => time() + 300, "path" => "/", "samesite" => "Strict"]);
+
+setcookie("sessionCookie", "1", "", "/");
+setcookie("sessionSecureCookie", "1", "", "/", "", TRUE);
+setcookie("sessionHttpOnlyCookie", "1", "", "/", "", FALSE, TRUE);
+setcookie("sessionSameSiteLaxCookie", "1", ["path" => "/", "samesite" => "Lax"]);
+setcookie("sessionSameSiteStrictCookie", "1", ["path" => "/", "samesite" => "Strict"]);
+?>
diff --git a/LayoutTests/http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict-expected.txt b/LayoutTests/http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict-expected.txt
new file mode 100644 (file)
index 0000000..d5bc1cf
--- /dev/null
@@ -0,0 +1,31 @@
+Tests setting all of a site's cookies to SameSite=strict.
+
+'clientSideCookie' 1 Before Change -- domain: '127.0.0.1' isSession: 'true'
+'clientSideCookie' 2 After Change --- domain: '127.0.0.1' isSession: 'true' isSameSiteStrict: 'true'
+
+'persistentCookie' 1 Before Change -- domain: '127.0.0.1' expiry set
+'persistentCookie' 2 After Change --- domain: '127.0.0.1' expiry set isSameSiteStrict: 'true'
+
+'persistentHttpOnlyCookie' 1 Before Change -- domain: '127.0.0.1' expiry set isHttpOnly: 'true'
+'persistentHttpOnlyCookie' 2 After Change --- domain: '127.0.0.1' expiry set isHttpOnly: 'true' isSameSiteStrict: 'true'
+
+'persistentSameSiteLaxCookie' 1 Before Change -- domain: '127.0.0.1' expiry set isSameSiteLax: 'true'
+'persistentSameSiteLaxCookie' 2 After Change --- domain: '127.0.0.1' expiry set isSameSiteStrict: 'true'
+
+'persistentSameSiteStrictCookie' 1 Before Change -- domain: '127.0.0.1' expiry set isSameSiteStrict: 'true'
+'persistentSameSiteStrictCookie' 2 After Change --- domain: '127.0.0.1' expiry set isSameSiteStrict: 'true'
+
+'sessionCookie' 1 Before Change -- domain: '127.0.0.1' isSession: 'true'
+'sessionCookie' 2 After Change --- domain: '127.0.0.1' isSession: 'true' isSameSiteStrict: 'true'
+
+'sessionHttpOnlyCookie' 1 Before Change -- domain: '127.0.0.1' isHttpOnly: 'true' isSession: 'true'
+'sessionHttpOnlyCookie' 2 After Change --- domain: '127.0.0.1' isHttpOnly: 'true' isSession: 'true' isSameSiteStrict: 'true'
+
+'sessionSameSiteLaxCookie' 1 Before Change -- domain: '127.0.0.1' isSession: 'true' isSameSiteLax: 'true'
+'sessionSameSiteLaxCookie' 2 After Change --- domain: '127.0.0.1' isSession: 'true' isSameSiteStrict: 'true'
+
+'sessionSameSiteStrictCookie' 1 Before Change -- domain: '127.0.0.1' isSession: 'true' isSameSiteStrict: 'true'
+'sessionSameSiteStrictCookie' 2 After Change --- domain: '127.0.0.1' isSession: 'true' isSameSiteStrict: 'true'
+
+
+
diff --git a/LayoutTests/http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict.html b/LayoutTests/http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict.html
new file mode 100644 (file)
index 0000000..5749853
--- /dev/null
@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/cookies/resources/cookie-utilities.js"></script>
+</head>
+<body onload="setTimeout('run()', 0)">
+<div id="description">Tests setting all of a site's cookies to SameSite=strict.</div>
+<br>
+<div id="output"></div>
+<br>
+<script>
+    testRunner.waitUntilDone();
+    testRunner.dumpAsText();
+
+    function sortStringArray(a, b) {
+        a = a.toLowerCase();
+        b = b.toLowerCase();
+
+        return a > b ? 1 : b > a ? -1 : 0;
+    }
+
+    function addLinebreakToOutput() {
+        let element = document.createElement("br");
+        output.appendChild(element);
+    }
+
+    function addOutput(message) {
+        let element = document.createElement("div");
+        element.innerText = message;
+        output.appendChild(element);
+    }
+
+    function stringifyCookieProperties(cookie, isBefore) {
+        let cookieString = "'" + cookie.name + (isBefore ? "' 1 Before Change --" : "' 2 After Change ---");
+        if (cookie.domain)
+            cookieString += " domain: '" + cookie.domain + "'";
+        if (cookie.path)
+            cookieString += " path: '" + cookie.path + "'";
+        if (cookie.expires)
+            cookieString += " expiry set";
+        if (cookie.isHttpOnly)
+            cookieString += " isHttpOnly: '" + cookie.isHttpOnly + "'";
+        if (cookie.isSecure)
+            cookieString += " isSecure: '" + cookie.isSecure + "'";
+        if (cookie.isSession)
+            cookieString += " isSession: '" + cookie.isSession + "'";
+        if (cookie.isSameSiteNone)
+            cookieString += " isSameSiteNone: '" + cookie.isSameSiteNone + "'";
+        if (cookie.isSameSiteLax)
+            cookieString += " isSameSiteLax: '" + cookie.isSameSiteLax + "'";
+        if (cookie.isSameSiteStrict)
+            cookieString += " isSameSiteStrict: '" + cookie.isSameSiteStrict + "'";
+        return cookieString;
+    }
+
+    let cookiesBeforeChange;
+    let cookiesAfterChange;
+
+    function checkCookies() {
+        if (!cookiesBeforeChange.length) {
+            addOutput("FAIL: No cookies found before change.");
+            testRunner.notifyDone();
+            return;
+        }
+
+        if (!cookiesBeforeChange.length || !cookiesAfterChange.length) {
+            addOutput("FAIL: No cookies found after change.");
+            testRunner.notifyDone();
+            return;
+        }
+
+        if (cookiesBeforeChange.length !== cookiesAfterChange.length) {
+            addOutput("FAIL: Not the same amount of cookies before and after change.");
+            testRunner.notifyDone();
+            return;
+        }
+
+        let unsortedTestPassedMessages = [];
+        for (let i = 0; i < cookiesBeforeChange.length; ++i) {
+            unsortedTestPassedMessages.push(stringifyCookieProperties(cookiesBeforeChange[i], true));
+            unsortedTestPassedMessages.push(stringifyCookieProperties(cookiesAfterChange[i], false));
+        }
+
+        let sortedTestPassedMessages = unsortedTestPassedMessages.sort(sortStringArray);
+        let row = 1;
+        for (let testPassedMessage of sortedTestPassedMessages) {
+            addOutput(testPassedMessage);
+            if (row % 2 === 0)
+                addLinebreakToOutput();
+            ++row;
+        }
+    }
+
+    function run() {
+        fetch("resources/set-all-kinds-of-cookies.php?dummy=" + Math.random())
+            .then(() => {
+                document.cookie = "clientSideCookie=1";
+                cookiesBeforeChange = internals.getCookies();
+                testRunner.statisticsSetToSameSiteStrictCookies("http://127.0.0.1:8000", function () {
+                    cookiesAfterChange = internals.getCookies();
+                    checkCookies();
+                    testRunner.notifyDone();
+                });
+            })
+    }
+</script>
+</body>
+</html>
index 965fba9..a451a57 100644 (file)
@@ -2738,6 +2738,10 @@ http/tests/resourceLoadStatistics/clear-in-memory-and-persistent-store.html [ Pa
 http/tests/resourceLoadStatistics/clear-in-memory-and-persistent-store-one-hour.html [ Pass ]
 http/tests/resourceLoadStatistics/strip-referrer-to-origin-for-third-party-redirects.html [ Pass ]
 http/tests/resourceLoadStatistics/strip-referrer-to-origin-for-third-party-requests.html [ Pass ]
+
+# The SameSite cookie API is only available in macOS Catalina and above, and thus skipped for WK2 in general.
+http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict.html [ Pass ]
+
 http/tests/storageAccess/deny-storage-access-under-opener.html [ Pass ]
 http/tests/storageAccess/deny-storage-access-under-opener-if-auto-dismiss.html [ Pass ]
 http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource.html [ Pass ]
index 698b3d5..9159780 100644 (file)
@@ -739,6 +739,9 @@ webkit.org/b/185994 fast/text/user-installed-fonts/shadow-postscript-family.html
 [ HighSierra+ ] http/tests/resourceLoadStatistics/strip-referrer-to-origin-for-third-party-requests.html [ Pass ]
 [ HighSierra+ ] http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource.html [ Pass ]
 
+# The SameSite cookie API is only available in macOS Catalina and above.
+[ Catalina+ ] http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict.html [ Pass ]
+
 # Skipped in general expectations since they only work on iOS and Mac, WK2.
 media/deactivate-audio-session.html [ Pass ]
 
index ee327d4..dcf202c 100644 (file)
@@ -732,6 +732,10 @@ http/tests/resourceLoadStatistics/grandfathering.html [ Pass ]
 webkit.org/b/180703 http/tests/resourceLoadStatistics/telemetry-generation.html [ Pass Failure ]
 http/tests/resourceLoadStatistics/prune-statistics.html [ Pass ]
 http/tests/resourceLoadStatistics [ Pass ]
+
+# The SameSite cookie API is only available in macOS Catalina and above.
+http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict.html [ Skip ]
+
 http/tests/websocket/connection-refusal-in-frame-resource-load-statistics.html [ Pass ]
 # These are only supported behind a compile time flag in macOS High Sierra + iOS 11, and above.
 http/tests/resourceLoadStatistics/cookie-deletion.html [ Pass Timeout ]
index ad4c2f9..d822448 100644 (file)
@@ -1,3 +1,15 @@
+2020-03-23  John Wilander  <wilander@apple.com>
+
+        Add the capability to change all of a website's cookies to SameSite=Strict
+        https://bugs.webkit.org/show_bug.cgi?id=209369
+        <rdar://problem/60710690>
+
+        Reviewed by Alex Christensen and David Kilzer.
+
+        * wtf/PlatformHave.h:
+            Adds HAVE_CFNETWORK_SAMESITE_COOKIE_API for macOS Catalina and up,
+            iOS 13 and up, Catalyst, watchOS, and Apple TV.
+
 2020-03-23  youenn fablet  <youenn@apple.com>
 
         Rename blankURL to aboutBlankURL
index b17539b..7fa6027 100644 (file)
 #define HAVE_CFNETWORK_NEGOTIATED_SSL_PROTOCOL_CIPHER 1
 #endif
 
+#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) || (PLATFORM(IOS_FAMILY) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 130000) || PLATFORM(MACCATALYST) || PLATFORM(WATCHOS) || PLATFORM(APPLETV)
+#define HAVE_CFNETWORK_SAMESITE_COOKIE_API 1
+#endif
+
 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101600) || (PLATFORM(IOS_FAMILY) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 140000)
 #define HAVE_CFNETWORK_METRICS_APIS_V4 1
 #endif
index a30510b..14aa632 100644 (file)
@@ -1,3 +1,24 @@
+2020-03-23  John Wilander  <wilander@apple.com>
+
+        Add the capability to change all of a website's cookies to SameSite=Strict
+        https://bugs.webkit.org/show_bug.cgi?id=209369
+        <rdar://problem/60710690>
+
+        Reviewed by Alex Christensen and David Kilzer.
+
+        Test: http/tests/resourceLoadStatistics/set-all-cookies-to-same-site-strict.html
+
+        * platform/network/NetworkStorageSession.cpp:
+        (WebCore::NetworkStorageSession::setAllCookiesToSameSiteStrict):
+            Stub function for non-Cocoa platforms.
+        * platform/network/NetworkStorageSession.h:
+        * platform/network/cocoa/NetworkStorageSessionCocoa.mm:
+        (WebCore::NetworkStorageSession::setAllCookiesToSameSiteStrict):
+        * testing/Internals.h:
+            Added code to expose SameSite=None and path properties of cookies.
+            However, they don't seem to carry over so I'll have to revisit the
+            internal workings.
+
 2020-03-23  Michael Catanzaro  <mcatanzaro@gnome.org>
 
         [WPE][GTK] Allow distributors to brand user agent
index 9101590..c58669f 100644 (file)
@@ -88,6 +88,14 @@ bool NetworkStorageSession::shouldBlockThirdPartyCookiesButKeepFirstPartyCookies
     return m_registrableDomainsToBlockButKeepCookiesFor.contains(registrableDomain);
 }
 
+#if !PLATFORM(COCOA)
+void NetworkStorageSession::setAllCookiesToSameSiteStrict(const RegistrableDomain&, CompletionHandler<void()>&& completionHandler)
+{
+    // Not implemented.
+    completionHandler();
+}
+#endif
+
 bool NetworkStorageSession::hasHadUserInteractionAsFirstParty(const RegistrableDomain& registrableDomain) const
 {
     if (registrableDomain.isEmpty())
index a87b91c..885ff87 100644 (file)
@@ -177,6 +177,7 @@ public:
     WEBCORE_EXPORT bool shouldBlockCookies(const URL& firstPartyForCookies, const URL& resource, Optional<FrameIdentifier>, Optional<PageIdentifier>) const;
     WEBCORE_EXPORT bool shouldBlockThirdPartyCookies(const RegistrableDomain&) const;
     WEBCORE_EXPORT bool shouldBlockThirdPartyCookiesButKeepFirstPartyCookiesFor(const RegistrableDomain&) const;
+    WEBCORE_EXPORT void setAllCookiesToSameSiteStrict(const RegistrableDomain&, CompletionHandler<void()>&&);
     WEBCORE_EXPORT bool hasHadUserInteractionAsFirstParty(const RegistrableDomain&) const;
     WEBCORE_EXPORT void setPrevalentDomainsToBlockAndDeleteCookiesFor(const Vector<RegistrableDomain>&);
     WEBCORE_EXPORT void setPrevalentDomainsToBlockButKeepCookiesFor(const Vector<RegistrableDomain>&);
index 290e341..72ee849 100644 (file)
@@ -116,6 +116,37 @@ void NetworkStorageSession::hasCookies(const RegistrableDomain& domain, Completi
     completionHandler(false);
 }
 
+void NetworkStorageSession::setAllCookiesToSameSiteStrict(const RegistrableDomain& domain, CompletionHandler<void()>&& completionHandler)
+{
+    ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
+
+#if HAVE(CFNETWORK_SAMESITE_COOKIE_API)
+    RetainPtr<NSMutableArray<NSHTTPCookie *>> oldCookiesToDelete = adoptNS([[NSMutableArray alloc] init]);
+    RetainPtr<NSMutableArray<NSHTTPCookie *>> newCookiesToAdd = adoptNS([[NSMutableArray alloc] init]);
+
+    for (NSHTTPCookie *nsCookie in nsCookieStorage().cookies) {
+        if (RegistrableDomain::uncheckedCreateFromHost(nsCookie.domain) == domain && nsCookie.sameSitePolicy != NSHTTPCookieSameSiteStrict) {
+            [oldCookiesToDelete addObject:nsCookie];
+            RetainPtr<NSMutableDictionary<NSHTTPCookiePropertyKey, id>> mutableProperties = adoptNS([[nsCookie properties] mutableCopy]);
+            mutableProperties.get()[NSHTTPCookieSameSitePolicy] = NSHTTPCookieSameSiteStrict;
+            NSHTTPCookie *strictCookie = [NSHTTPCookie cookieWithProperties:mutableProperties.get()];
+            [newCookiesToAdd addObject:strictCookie];
+        }
+    }
+
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+    for (NSHTTPCookie *oldCookie in oldCookiesToDelete.get())
+        deleteHTTPCookie(cookieStorage().get(), oldCookie);
+
+    for (NSHTTPCookie *newCookie in newCookiesToAdd.get())
+        [nsCookieStorage() setCookie:newCookie];
+    END_BLOCK_OBJC_EXCEPTIONS;
+#else
+    UNUSED_PARAM(domain);
+#endif
+    completionHandler();
+}
+
 void NetworkStorageSession::flushCookieStore()
 {
     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
index 72f49e2..e235234 100644 (file)
@@ -848,11 +848,13 @@ public:
         String name;
         String value;
         String domain;
+        String path;
         // Expiration dates are expressed as milliseconds since the UNIX epoch.
         double expires { 0 };
         bool isHttpOnly { false };
         bool isSecure { false };
         bool isSession { false };
+        bool isSameSiteNone { false };
         bool isSameSiteLax { false };
         bool isSameSiteStrict { false };
 
@@ -860,14 +862,16 @@ public:
             : name(cookie.name)
             , value(cookie.value)
             , domain(cookie.domain)
+            , path(cookie.path)
             , expires(cookie.expires.valueOr(0))
             , isHttpOnly(cookie.httpOnly)
             , isSecure(cookie.secure)
             , isSession(cookie.session)
+            , isSameSiteNone(cookie.sameSite == Cookie::SameSitePolicy::None)
             , isSameSiteLax(cookie.sameSite == Cookie::SameSitePolicy::Lax)
             , isSameSiteStrict(cookie.sameSite == Cookie::SameSitePolicy::Strict)
         {
-            ASSERT(!(isSameSiteLax && isSameSiteStrict));
+            ASSERT(!(isSameSiteLax && isSameSiteStrict) && !(isSameSiteLax && isSameSiteNone) && !(isSameSiteStrict && isSameSiteNone));
         }
 
         CookieData()
index 7749bf3..9f0fdb9 100644 (file)
@@ -1,3 +1,29 @@
+2020-03-23  John Wilander  <wilander@apple.com>
+
+        Add the capability to change all of a website's cookies to SameSite=Strict
+        https://bugs.webkit.org/show_bug.cgi?id=209369
+        <rdar://problem/60710690>
+
+        Reviewed by Alex Christensen and David Kilzer.
+
+        These changes add test infrastructure to run function
+        WebCore::NetworkStorageSession::setAllCookiesToSameSiteStrict() in the
+        network process.
+
+        * NetworkProcess/NetworkProcess.cpp:
+        (WebKit::NetworkProcess::setToSameSiteStrictCookiesForTesting):
+        * NetworkProcess/NetworkProcess.h:
+        * NetworkProcess/NetworkProcess.messages.in:
+        * UIProcess/API/C/WKWebsiteDataStoreRef.cpp:
+        (WKWebsiteDataStoreSetResourceLoadStatisticsToSameSiteStrictCookiesForTesting):
+        * UIProcess/API/C/WKWebsiteDataStoreRef.h:
+        * UIProcess/Network/NetworkProcessProxy.cpp:
+        (WebKit::NetworkProcessProxy::setToSameSiteStrictCookiesForTesting):
+        * UIProcess/Network/NetworkProcessProxy.h:
+        * UIProcess/WebsiteData/WebsiteDataStore.cpp:
+        (WebKit::WebsiteDataStore::setResourceLoadStatisticsToSameSiteStrictCookiesForTesting):
+        * UIProcess/WebsiteData/WebsiteDataStore.h:
+
 2020-03-23  Daniel Bates  <dabates@apple.com>
 
         Support inserting text or dictation alternative by simulating keyboard input
index 5ab6d4c..0e2316d 100644 (file)
@@ -1306,6 +1306,16 @@ void NetworkProcess::setFirstPartyWebsiteDataRemovalModeForTesting(PAL::SessionI
         completionHandler();
     }
 }
+
+void NetworkProcess::setToSameSiteStrictCookiesForTesting(PAL::SessionID sessionID, const WebCore::RegistrableDomain& domain, CompletionHandler<void()>&& completionHandler)
+{
+    if (auto* networkStorageSession = storageSession(sessionID))
+        networkStorageSession->setAllCookiesToSameSiteStrict(domain, WTFMove(completionHandler));
+    else {
+        ASSERT_NOT_REACHED();
+        completionHandler();
+    }
+}
 #endif // ENABLE(RESOURCE_LOAD_STATISTICS)
 
 void NetworkProcess::preconnectTo(PAL::SessionID sessionID, const URL& url, const String& userAgent, WebCore::StoredCredentialsPolicy storedCredentialsPolicy, NavigatingToAppBoundDomain isNavigatingToAppBoundDomain)
index 65bb646..1c19841 100644 (file)
@@ -265,6 +265,7 @@ public:
     void setShouldDowngradeReferrerForTesting(bool, CompletionHandler<void()>&&);
     void setShouldBlockThirdPartyCookiesForTesting(PAL::SessionID, WebCore::ThirdPartyCookieBlockingMode, CompletionHandler<void()>&&);
     void setFirstPartyWebsiteDataRemovalModeForTesting(PAL::SessionID, WebCore::FirstPartyWebsiteDataRemovalMode, CompletionHandler<void()>&&);
+    void setToSameSiteStrictCookiesForTesting(PAL::SessionID, const WebCore::RegistrableDomain&, CompletionHandler<void()>&&);
 #endif
 
     using CacheStorageRootPathCallback = CompletionHandler<void(String&&)>;
index afe01a7..aaee493 100644 (file)
@@ -142,6 +142,7 @@ messages -> NetworkProcess LegacyReceiver {
     SetShouldDowngradeReferrerForTesting(bool enabled) -> () Async
     SetShouldBlockThirdPartyCookiesForTesting(PAL::SessionID sessionID, enum:uint8_t WebCore::ThirdPartyCookieBlockingMode blockingMode) -> () Async
     SetFirstPartyWebsiteDataRemovalModeForTesting(PAL::SessionID sessionID, enum:uint8_t WebCore::FirstPartyWebsiteDataRemovalMode mode) -> () Async
+    SetToSameSiteStrictCookiesForTesting(PAL::SessionID sessionID, WebCore::RegistrableDomain domain) -> () Async
 #endif
 
     SetSessionIsControlledByAutomation(PAL::SessionID sessionID, bool controlled);
index 335fc20..97afcab 100644 (file)
@@ -582,6 +582,17 @@ void WKWebsiteDataStoreSetResourceLoadStatisticsFirstPartyWebsiteDataRemovalMode
 #endif
 }
 
+void WKWebsiteDataStoreSetResourceLoadStatisticsToSameSiteStrictCookiesForTesting(WKWebsiteDataStoreRef dataStoreRef, WKStringRef hostName, void* context, WKWebsiteDataStoreSetResourceLoadStatisticsToSameSiteStrictCookiesForTestingFunction completionHandler)
+{
+#if ENABLE(RESOURCE_LOAD_STATISTICS)
+    WebKit::toImpl(dataStoreRef)->setResourceLoadStatisticsToSameSiteStrictCookiesForTesting(URL(URL(), WebKit::toImpl(hostName)->string()), [context, completionHandler] {
+        completionHandler(context);
+    });
+#else
+    completionHandler(context);
+#endif
+}
+
 void WKWebsiteDataStoreStatisticsResetToConsistentState(WKWebsiteDataStoreRef dataStoreRef, void* context, WKWebsiteDataStoreStatisticsResetToConsistentStateFunction completionHandler)
 {
 #if ENABLE(RESOURCE_LOAD_STATISTICS)
index 5802fea..e5b8bed 100644 (file)
@@ -127,6 +127,8 @@ typedef void (*WKWebsiteDataStoreSetResourceLoadStatisticsShouldBlockThirdPartyC
 WK_EXPORT void WKWebsiteDataStoreSetResourceLoadStatisticsShouldBlockThirdPartyCookiesForTesting(WKWebsiteDataStoreRef dataStoreRef, bool enabled, bool onlyOnSitesWithoutUserInteraction, void* context, WKWebsiteDataStoreSetResourceLoadStatisticsShouldBlockThirdPartyCookiesForTestingFunction completionHandler);
 typedef void (*WKWebsiteDataStoreSetResourceLoadStatisticsFirstPartyWebsiteDataRemovalModeForTestingFunction)(void* functionContext);
 WK_EXPORT void WKWebsiteDataStoreSetResourceLoadStatisticsFirstPartyWebsiteDataRemovalModeForTesting(WKWebsiteDataStoreRef dataStoreRef, bool enabled, void* context, WKWebsiteDataStoreSetResourceLoadStatisticsFirstPartyWebsiteDataRemovalModeForTestingFunction completionHandler);
+typedef void (*WKWebsiteDataStoreSetResourceLoadStatisticsToSameSiteStrictCookiesForTestingFunction)(void* functionContext);
+WK_EXPORT void WKWebsiteDataStoreSetResourceLoadStatisticsToSameSiteStrictCookiesForTesting(WKWebsiteDataStoreRef dataStoreRef, WKStringRef hostName, void* context, WKWebsiteDataStoreSetResourceLoadStatisticsToSameSiteStrictCookiesForTestingFunction completionHandler);
 typedef void (*WKWebsiteDataStoreStatisticsResetToConsistentStateFunction)(void* functionContext);
 WK_EXPORT void WKWebsiteDataStoreStatisticsResetToConsistentState(WKWebsiteDataStoreRef dataStoreRef, void* context, WKWebsiteDataStoreStatisticsResetToConsistentStateFunction completionHandler);
 
index ed64582..a153c48 100644 (file)
@@ -1170,6 +1170,16 @@ void NetworkProcessProxy::setFirstPartyWebsiteDataRemovalModeForTesting(PAL::Ses
 
     sendWithAsyncReply(Messages::NetworkProcess::SetFirstPartyWebsiteDataRemovalModeForTesting(sessionID, mode), WTFMove(completionHandler));
 }
+
+void NetworkProcessProxy::setToSameSiteStrictCookiesForTesting(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void()>&& completionHandler)
+{
+    if (!canSendMessage()) {
+        completionHandler();
+        return;
+    }
+
+    sendWithAsyncReply(Messages::NetworkProcess::SetToSameSiteStrictCookiesForTesting(sessionID, domain), WTFMove(completionHandler));
+}
 #endif // ENABLE(RESOURCE_LOAD_STATISTICS)
 
 void NetworkProcessProxy::sendProcessWillSuspendImminentlyForTesting()
index 9c04a85..6465470 100644 (file)
@@ -175,6 +175,7 @@ public:
     void setShouldDowngradeReferrerForTesting(bool, CompletionHandler<void()>&&);
     void setShouldBlockThirdPartyCookiesForTesting(PAL::SessionID, WebCore::ThirdPartyCookieBlockingMode, CompletionHandler<void()>&&);
     void setFirstPartyWebsiteDataRemovalModeForTesting(PAL::SessionID, WebCore::FirstPartyWebsiteDataRemovalMode, CompletionHandler<void()>&&);
+    void setToSameSiteStrictCookiesForTesting(PAL::SessionID, const RegistrableDomain&, CompletionHandler<void()>&&);
 #endif
     
     void synthesizeAppIsBackground(bool background);
index 7e6ae89..c7a2c53 100644 (file)
@@ -1857,6 +1857,16 @@ void WebsiteDataStore::setResourceLoadStatisticsFirstPartyWebsiteDataRemovalMode
             networkProcess->setFirstPartyWebsiteDataRemovalModeForTesting(m_sessionID, mode, [callbackAggregator = callbackAggregator.copyRef()] { });
     }
 }
+
+void WebsiteDataStore::setResourceLoadStatisticsToSameSiteStrictCookiesForTesting(const URL& url, CompletionHandler<void()>&& completionHandler)
+{
+    auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
+
+    for (auto& processPool : processPools()) {
+        if (auto* networkProcess = processPool->networkProcess())
+            networkProcess->setToSameSiteStrictCookiesForTesting(m_sessionID, WebCore::RegistrableDomain { url }, [callbackAggregator = callbackAggregator.copyRef()] { });
+    }
+}
 #endif // ENABLE(RESOURCE_LOAD_STATISTICS)
 
 void WebsiteDataStore::setCacheMaxAgeCapForPrevalentResources(Seconds seconds, CompletionHandler<void()>&& completionHandler)
index 4f5ca17..da024e5 100644 (file)
@@ -196,6 +196,7 @@ public:
     void setResourceLoadStatisticsShouldDowngradeReferrerForTesting(bool, CompletionHandler<void()>&&);
     void setResourceLoadStatisticsShouldBlockThirdPartyCookiesForTesting(bool enabled, bool onlyOnSitesWithoutUserInteraction, CompletionHandler<void()>&&);
     void setResourceLoadStatisticsFirstPartyWebsiteDataRemovalModeForTesting(bool enabled, CompletionHandler<void()>&&);
+    void setResourceLoadStatisticsToSameSiteStrictCookiesForTesting(const URL&, CompletionHandler<void()>&&);
     WebCore::ThirdPartyCookieBlockingMode thirdPartyCookieBlockingMode() const;
     bool isItpStateExplicitlySet() const { return m_isItpStateExplicitlySet; }
     void useExplicitITPState() { m_isItpStateExplicitlySet = true; }
index 53b1c46..721eb05 100644 (file)
@@ -1,3 +1,28 @@
+2020-03-23  John Wilander  <wilander@apple.com>
+
+        Add the capability to change all of a website's cookies to SameSite=Strict
+        https://bugs.webkit.org/show_bug.cgi?id=209369
+        <rdar://problem/60710690>
+
+        Reviewed by Alex Christensen and David Kilzer.
+
+        These changes add TestRunner function statisticsSetToSameSiteStrictCookies().
+
+        * WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
+        * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+        (WTR::InjectedBundle::didReceiveMessageToPage):
+        * WebKitTestRunner/InjectedBundle/TestRunner.cpp:
+        (WTR::TestRunner::statisticsSetToSameSiteStrictCookies):
+        (WTR::TestRunner::statisticsCallDidSetToSameSiteStrictCookiesCallback):
+        * WebKitTestRunner/InjectedBundle/TestRunner.h:
+        * WebKitTestRunner/TestController.cpp:
+        (WTR::TestController::setStatisticsToSameSiteStrictCookies):
+        * WebKitTestRunner/TestController.h:
+        * WebKitTestRunner/TestInvocation.cpp:
+        (WTR::TestInvocation::didReceiveMessageFromInjectedBundle):
+        (WTR::TestInvocation::didSetToSameSiteStrictCookies):
+        * WebKitTestRunner/TestInvocation.h:
+
 2020-03-23  Nikos Mouchtaris  <nmouchtaris@apple.com>
 
         Uneviewed, added myself to contributors.json.
index 1e97c66..fa67f37 100644 (file)
@@ -345,6 +345,7 @@ interface TestRunner {
     void setStatisticsShouldDowngradeReferrer(boolean value, object callback);
     void setStatisticsShouldBlockThirdPartyCookies(boolean value, object callback, optional boolean onlyOnSitesWithoutUserInteraction);
     void setStatisticsFirstPartyWebsiteDataRemovalMode(boolean value, object callback);
+    void statisticsSetToSameSiteStrictCookies(DOMString hostName, object callback);
     void loadedThirdPartyDomains(object callback);
 
     // Injected bundle form client.
index 52f1689..1667580 100644 (file)
@@ -357,6 +357,11 @@ void InjectedBundle::didReceiveMessageToPage(WKBundlePageRef page, WKStringRef m
         return;
     }
 
+    if (WKStringIsEqualToUTF8CString(messageName, "CallDidSetToSameSiteStrictCookies")) {
+        m_testRunner->statisticsCallDidSetToSameSiteStrictCookiesCallback();
+        return;
+    }
+
     if (WKStringIsEqualToUTF8CString(messageName, "CallDidResetStatisticsToConsistentState")) {
         m_testRunner->statisticsCallDidResetToConsistentStateCallback();
         return;
index e0c7ebf..95ae642 100644 (file)
@@ -754,6 +754,7 @@ enum {
     StatisticsDidSetShouldDowngradeReferrerCallbackID,
     StatisticsDidSetShouldBlockThirdPartyCookiesCallbackID,
     StatisticsDidSetFirstPartyWebsiteDataRemovalModeCallbackID,
+    StatisticsDidSetToSameSiteStrictCookiesCallbackID,
     AllStorageAccessEntriesCallbackID,
     LoadedThirdPartyDomainsCallbackID,
     DidRemoveAllSessionCredentialsCallbackID,
@@ -2286,6 +2287,20 @@ void TestRunner::statisticsCallClearThroughWebsiteDataRemovalCallback()
     callTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID);
 }
 
+void TestRunner::statisticsSetToSameSiteStrictCookies(JSStringRef hostName, JSValueRef completionHandler)
+{
+    cacheTestRunnerCallback(StatisticsDidSetToSameSiteStrictCookiesCallbackID, completionHandler);
+
+    auto messageName = adoptWK(WKStringCreateWithUTF8CString("StatisticsSetToSameSiteStrictCookies"));
+    auto messageBody = adoptWK(WKStringCreateWithJSString(hostName));
+    WKBundlePostMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get());
+}
+
+void TestRunner::statisticsCallDidSetToSameSiteStrictCookiesCallback()
+{
+    callTestRunnerCallback(StatisticsDidSetToSameSiteStrictCookiesCallbackID);
+}
+
 void TestRunner::statisticsResetToConsistentState(JSValueRef completionHandler)
 {
     cacheTestRunnerCallback(StatisticsDidResetToConsistentStateCallbackID, completionHandler);
index 5f2475c..728d36e 100644 (file)
@@ -448,6 +448,8 @@ public:
     void statisticsCallDidSetShouldBlockThirdPartyCookiesCallback();
     void setStatisticsFirstPartyWebsiteDataRemovalMode(bool value, JSValueRef callback);
     void statisticsCallDidSetFirstPartyWebsiteDataRemovalModeCallback();
+    void statisticsSetToSameSiteStrictCookies(JSStringRef hostName, JSValueRef callback);
+    void statisticsCallDidSetToSameSiteStrictCookiesCallback();
     void statisticsResetToConsistentState(JSValueRef completionHandler);
     void statisticsCallDidResetToConsistentStateCallback();
     void loadedThirdPartyDomains(JSValueRef callback);
index 3cbcd62..ba9829f 100644 (file)
@@ -3704,6 +3704,14 @@ void TestController::setStatisticsFirstPartyWebsiteDataRemovalMode(bool value)
     m_currentInvocation->didSetFirstPartyWebsiteDataRemovalMode();
 }
 
+void TestController::setStatisticsToSameSiteStrictCookies(WKStringRef hostName)
+{
+    ResourceStatisticsCallbackContext context(*this);
+    WKWebsiteDataStoreSetResourceLoadStatisticsToSameSiteStrictCookiesForTesting(websiteDataStore(), hostName, &context, resourceStatisticsVoidResultCallback);
+    runUntil(context.done, noTimeout);
+    m_currentInvocation->didSetToSameSiteStrictCookies();
+}
+
 void TestController::statisticsResetToConsistentState()
 {
     ResourceStatisticsCallbackContext context(*this);
index 8eb9674..8bca645 100644 (file)
@@ -262,6 +262,7 @@ public:
     void setStatisticsShouldDowngradeReferrer(bool value);
     void setStatisticsShouldBlockThirdPartyCookies(bool value, bool onlyOnSitesWithoutUserInteraction);
     void setStatisticsFirstPartyWebsiteDataRemovalMode(bool value);
+    void setStatisticsToSameSiteStrictCookies(WKStringRef hostName);
     void statisticsResetToConsistentState();
 
     void getAllStorageAccessEntries();
index e4749d2..cbd1469 100644 (file)
@@ -950,6 +950,13 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName
         return;
     }
 
+    if (WKStringIsEqualToUTF8CString(messageName, "StatisticsSetToSameSiteStrictCookies")) {
+        ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
+        WKStringRef hostName = static_cast<WKStringRef>(messageBody);
+        TestController::singleton().setStatisticsToSameSiteStrictCookies(hostName);
+        return;
+    }
+
     if (WKStringIsEqualToUTF8CString(messageName, "StatisticsResetToConsistentState")) {
         if (m_shouldDumpResourceLoadStatistics)
             m_savedResourceLoadStatistics = TestController::singleton().dumpResourceLoadStatistics();
@@ -1916,6 +1923,12 @@ void TestInvocation::didSetFirstPartyWebsiteDataRemovalMode()
     WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), nullptr);
 }
 
+void TestInvocation::didSetToSameSiteStrictCookies()
+{
+    WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallDidSetToSameSiteStrictCookies"));
+    WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), nullptr);
+}
+
 void TestInvocation::didResetStatisticsToConsistentState()
 {
     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallDidResetStatisticsToConsistentState"));
index dc1f953..e84f5eb 100644 (file)
@@ -77,6 +77,7 @@ public:
     void didSetShouldDowngradeReferrer();
     void didSetShouldBlockThirdPartyCookies();
     void didSetFirstPartyWebsiteDataRemovalMode();
+    void didSetToSameSiteStrictCookies();
     void didResetStatisticsToConsistentState();
     void didSetBlockCookiesForHost();
     void didSetStatisticsDebugMode();