Add SPI to disable cross origin access control checks
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 7 Mar 2020 04:07:53 +0000 (04:07 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 7 Mar 2020 04:07:53 +0000 (04:07 +0000)
https://bugs.webkit.org/show_bug.cgi?id=208748
Source/WebCore:

<rdar://problem/59861114>

Patch by Alex Christensen <achristensen@webkit.org> on 2020-03-06
Reviewed by Tim Hatcher.

Because loading is done process-globally in the WebProcess, use a CrossOriginAccessControlCheckDisabler::singleton for those checks.
Pass a parameter to the NetworkResourceLoaders to disable these checks only for loads from a web process without access control checks.
As long as we're changing the signature of passesAccessControlCheck, make it return an Expected instead of a bool with an out parameter.

* loader/CrossOriginAccessControl.cpp:
(WebCore::CrossOriginAccessControlCheckDisabler::singleton):
(WebCore::CrossOriginAccessControlCheckDisabler::setCrossOriginAccessControlCheckEnabled):
(WebCore::CrossOriginAccessControlCheckDisabler::crossOriginAccessControlCheckEnabled const):
(WebCore::passesAccessControlCheck):
(WebCore::validatePreflightResponse):
* loader/CrossOriginAccessControl.h:
* loader/CrossOriginPreflightChecker.cpp:
(WebCore::CrossOriginPreflightChecker::validatePreflightResponse):
* loader/DocumentThreadableLoader.cpp:
(WebCore::DocumentThreadableLoader::loadRequest):
* loader/SubresourceLoader.cpp:
(WebCore::SubresourceLoader::willSendRequestInternal):
(WebCore::SubresourceLoader::didReceiveResponse):
(WebCore::SubresourceLoader::checkResponseCrossOriginAccessControl):
(WebCore::SubresourceLoader::checkRedirectionCrossOriginAccessControl):
* loader/SubresourceLoader.h:
* loader/cache/CachedResource.cpp:
(WebCore::CachedResource::loadFrom):

Source/WebKit:

<rdar://problem/59861114>

Patch by Alex Christensen <achristensen@webkit.org> on 2020-03-06
Reviewed by Tim Hatcher.

* NetworkProcess/NetworkCORSPreflightChecker.cpp:
(WebKit::NetworkCORSPreflightChecker::NetworkCORSPreflightChecker):
(WebKit::NetworkCORSPreflightChecker::didCompleteWithError):
* NetworkProcess/NetworkCORSPreflightChecker.h:
* NetworkProcess/NetworkLoadChecker.cpp:
(WebKit::NetworkLoadChecker::NetworkLoadChecker):
(WebKit::NetworkLoadChecker::validateResponse):
(WebKit::NetworkLoadChecker::checkCORSRequestWithPreflight):
* NetworkProcess/NetworkLoadChecker.h:
* NetworkProcess/NetworkResourceLoadParameters.cpp:
(WebKit::NetworkResourceLoadParameters::encode const):
(WebKit::NetworkResourceLoadParameters::decode):
* NetworkProcess/NetworkResourceLoadParameters.h:
* NetworkProcess/NetworkResourceLoader.cpp:
(WebKit::NetworkResourceLoader::crossOriginAccessControlCheckEnabled const):
* NetworkProcess/NetworkResourceLoader.h:
* NetworkProcess/PingLoad.cpp:
(WebKit::PingLoad::PingLoad):
* Shared/WebPageCreationParameters.cpp:
(WebKit::WebPageCreationParameters::encode const):
(WebKit::WebPageCreationParameters::decode):
* Shared/WebPageCreationParameters.h:
* UIProcess/API/APIPageConfiguration.cpp:
(API::PageConfiguration::copy const):
* UIProcess/API/APIPageConfiguration.h:
(API::PageConfiguration::crossOriginAccessControlCheckEnabled const):
(API::PageConfiguration::setCrossOriginAccessControlCheckEnabled):
* UIProcess/API/Cocoa/WKWebViewConfiguration.mm:
(-[WKWebViewConfiguration _setCrossOriginAccessControlCheckEnabled:]):
(-[WKWebViewConfiguration _crossOriginAccessControlCheckEnabled]):
* UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h:
* UIProcess/WebPageProxy.cpp:
* WebProcess/Network/WebLoaderStrategy.cpp:
(WebKit::addParametersShared):
(WebKit::WebLoaderStrategy::scheduleLoadFromNetworkProcess):
(WebKit::WebLoaderStrategy::loadResourceSynchronously):
(WebKit::WebLoaderStrategy::startPingLoad):
(WebKit::addParametersFromFrame): Deleted.
* WebProcess/WebPage/WebPage.cpp:
(WebKit::m_processDisplayName):

Tools:

Patch by Alex Christensen <achristensen@webkit.org> on 2020-03-06
Reviewed by Tim Hatcher.

* TestWebKitAPI/Tests/WebKitCocoa/WKURLSchemeHandler-1.mm:
Add a test that verifies this SPI allows Access-Control-Allow-Origin: * with credentials.

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

29 files changed:
Source/WebCore/ChangeLog
Source/WebCore/loader/CrossOriginAccessControl.cpp
Source/WebCore/loader/CrossOriginAccessControl.h
Source/WebCore/loader/CrossOriginPreflightChecker.cpp
Source/WebCore/loader/DocumentThreadableLoader.cpp
Source/WebCore/loader/SubresourceLoader.cpp
Source/WebCore/loader/SubresourceLoader.h
Source/WebCore/loader/cache/CachedResource.cpp
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/NetworkCORSPreflightChecker.cpp
Source/WebKit/NetworkProcess/NetworkCORSPreflightChecker.h
Source/WebKit/NetworkProcess/NetworkLoadChecker.cpp
Source/WebKit/NetworkProcess/NetworkLoadChecker.h
Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.cpp
Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.h
Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp
Source/WebKit/NetworkProcess/NetworkResourceLoader.h
Source/WebKit/NetworkProcess/PingLoad.cpp
Source/WebKit/Shared/WebPageCreationParameters.cpp
Source/WebKit/Shared/WebPageCreationParameters.h
Source/WebKit/UIProcess/API/APIPageConfiguration.cpp
Source/WebKit/UIProcess/API/APIPageConfiguration.h
Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfiguration.mm
Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKitCocoa/WKURLSchemeHandler-1.mm

index 322f378..34b4e29 100644 (file)
@@ -1,3 +1,35 @@
+2020-03-06  Alex Christensen  <achristensen@webkit.org>
+
+        Add SPI to disable cross origin access control checks
+        https://bugs.webkit.org/show_bug.cgi?id=208748
+        <rdar://problem/59861114>
+
+        Reviewed by Tim Hatcher.
+
+        Because loading is done process-globally in the WebProcess, use a CrossOriginAccessControlCheckDisabler::singleton for those checks.
+        Pass a parameter to the NetworkResourceLoaders to disable these checks only for loads from a web process without access control checks.
+        As long as we're changing the signature of passesAccessControlCheck, make it return an Expected instead of a bool with an out parameter.
+
+        * loader/CrossOriginAccessControl.cpp:
+        (WebCore::CrossOriginAccessControlCheckDisabler::singleton):
+        (WebCore::CrossOriginAccessControlCheckDisabler::setCrossOriginAccessControlCheckEnabled):
+        (WebCore::CrossOriginAccessControlCheckDisabler::crossOriginAccessControlCheckEnabled const):
+        (WebCore::passesAccessControlCheck):
+        (WebCore::validatePreflightResponse):
+        * loader/CrossOriginAccessControl.h:
+        * loader/CrossOriginPreflightChecker.cpp:
+        (WebCore::CrossOriginPreflightChecker::validatePreflightResponse):
+        * loader/DocumentThreadableLoader.cpp:
+        (WebCore::DocumentThreadableLoader::loadRequest):
+        * loader/SubresourceLoader.cpp:
+        (WebCore::SubresourceLoader::willSendRequestInternal):
+        (WebCore::SubresourceLoader::didReceiveResponse):
+        (WebCore::SubresourceLoader::checkResponseCrossOriginAccessControl):
+        (WebCore::SubresourceLoader::checkRedirectionCrossOriginAccessControl):
+        * loader/SubresourceLoader.h:
+        * loader/cache/CachedResource.cpp:
+        (WebCore::CachedResource::loadFrom):
+
 2020-03-06  Myles C. Maxfield  <mmaxfield@apple.com>
 
         [GPU Process] Implement CanvasRenderingContext2D.putImageData()
index 7bd8618..39c5fc8 100644 (file)
@@ -35,6 +35,7 @@
 #include "Page.h"
 #include "ResourceRequest.h"
 #include "ResourceResponse.h"
+#include "RuntimeApplicationChecks.h"
 #include "SecurityOrigin.h"
 #include "SecurityPolicy.h"
 #include <mutex>
@@ -206,55 +207,74 @@ void cleanHTTPRequestHeadersForAccessControl(ResourceRequest& request, OptionSet
         request.clearHTTPAcceptEncoding();
 }
 
-bool passesAccessControlCheck(const ResourceResponse& response, StoredCredentialsPolicy storedCredentialsPolicy, SecurityOrigin& securityOrigin, String& errorDescription)
+CrossOriginAccessControlCheckDisabler& CrossOriginAccessControlCheckDisabler::singleton()
+{
+    ASSERT(!isInNetworkProcess());
+    static NeverDestroyed<CrossOriginAccessControlCheckDisabler> disabler;
+    return disabler.get();
+}
+
+void CrossOriginAccessControlCheckDisabler::setCrossOriginAccessControlCheckEnabled(bool enabled)
+{
+    ASSERT(!isInNetworkProcess());
+    m_accessControlCheckEnabled = enabled;
+}
+
+bool CrossOriginAccessControlCheckDisabler::crossOriginAccessControlCheckEnabled() const
+{
+    ASSERT(!isInNetworkProcess());
+    return m_accessControlCheckEnabled;
+}
+
+Expected<void, String> passesAccessControlCheck(const ResourceResponse& response, StoredCredentialsPolicy storedCredentialsPolicy, const SecurityOrigin& securityOrigin, const CrossOriginAccessControlCheckDisabler* checkDisabler)
 {
     // A wildcard Access-Control-Allow-Origin can not be used if credentials are to be sent,
     // even with Access-Control-Allow-Credentials set to true.
     const String& accessControlOriginString = response.httpHeaderField(HTTPHeaderName::AccessControlAllowOrigin);
-    if (accessControlOriginString == "*" && storedCredentialsPolicy == StoredCredentialsPolicy::DoNotUse)
-        return true;
+    bool starAllowed = storedCredentialsPolicy == StoredCredentialsPolicy::DoNotUse;
+    if (!starAllowed)
+        starAllowed = checkDisabler && !checkDisabler->crossOriginAccessControlCheckEnabled();
+    if (accessControlOriginString == "*" && starAllowed)
+        return { };
 
     String securityOriginString = securityOrigin.toString();
     if (accessControlOriginString != securityOriginString) {
         if (accessControlOriginString == "*")
-            errorDescription = "Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true."_s;
-        else if (accessControlOriginString.find(',') != notFound)
-            errorDescription = "Access-Control-Allow-Origin cannot contain more than one origin."_s;
-        else
-            errorDescription = makeString("Origin ", securityOriginString, " is not allowed by Access-Control-Allow-Origin.");
-        return false;
+            return makeUnexpected("Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true."_s);
+        if (accessControlOriginString.find(',') != notFound)
+            return makeUnexpected("Access-Control-Allow-Origin cannot contain more than one origin."_s);
+        return makeUnexpected(makeString("Origin ", securityOriginString, " is not allowed by Access-Control-Allow-Origin."));
     }
 
     if (storedCredentialsPolicy == StoredCredentialsPolicy::Use) {
         const String& accessControlCredentialsString = response.httpHeaderField(HTTPHeaderName::AccessControlAllowCredentials);
-        if (accessControlCredentialsString != "true") {
-            errorDescription = "Credentials flag is true, but Access-Control-Allow-Credentials is not \"true\".";
-            return false;
-        }
+        if (accessControlCredentialsString != "true")
+            return makeUnexpected("Credentials flag is true, but Access-Control-Allow-Credentials is not \"true\"."_s);
     }
 
-    return true;
+    return { };
 }
 
-bool validatePreflightResponse(const ResourceRequest& request, const ResourceResponse& response, StoredCredentialsPolicy storedCredentialsPolicy, SecurityOrigin& securityOrigin, String& errorDescription)
+Expected<void, String> validatePreflightResponse(const ResourceRequest& request, const ResourceResponse& response, StoredCredentialsPolicy storedCredentialsPolicy, const SecurityOrigin& securityOrigin, const CrossOriginAccessControlCheckDisabler* checkDisabler)
 {
-    if (!response.isSuccessful()) {
-        errorDescription = "Preflight response is not successful"_s;
-        return false;
-    }
+    if (!response.isSuccessful())
+        return makeUnexpected("Preflight response is not successful"_s);
 
-    if (!passesAccessControlCheck(response, storedCredentialsPolicy, securityOrigin, errorDescription))
-        return false;
+    auto accessControlCheckResult = passesAccessControlCheck(response, storedCredentialsPolicy, securityOrigin, checkDisabler);
+    if (!accessControlCheckResult)
+        return accessControlCheckResult;
 
     auto result = makeUnique<CrossOriginPreflightResultCacheItem>(storedCredentialsPolicy);
+    String errorDescription;
+    // FIXME: allowsCrossOriginMethod and allowsCrossOriginHeaders should return Expected<void, String> to avoid having an out parameter.
     if (!result->parse(response)
         || !result->allowsCrossOriginMethod(request.httpMethod(), storedCredentialsPolicy, errorDescription)
         || !result->allowsCrossOriginHeaders(request.httpHeaderFields(), storedCredentialsPolicy, errorDescription)) {
-        return false;
+        return makeUnexpected(errorDescription);
     }
 
     CrossOriginPreflightResultCache::singleton().appendEntry(securityOrigin.toString(), request.url(), WTFMove(result));
-    return true;
+    return { };
 }
 
 static inline bool shouldCrossOriginResourcePolicyCancelLoad(const SecurityOrigin& origin, const ResourceResponse& response)
index 0455107..171e318 100644 (file)
@@ -29,6 +29,7 @@
 #include "HTTPHeaderNames.h"
 #include "ReferrerPolicy.h"
 #include "StoredCredentialsPolicy.h"
+#include <wtf/Expected.h>
 #include <wtf/Forward.h>
 #include <wtf/OptionSet.h>
 
@@ -66,8 +67,18 @@ enum class HTTPHeadersToKeepFromCleaning {
 OptionSet<HTTPHeadersToKeepFromCleaning> httpHeadersToKeepFromCleaning(const HTTPHeaderMap&);
 WEBCORE_EXPORT void cleanHTTPRequestHeadersForAccessControl(ResourceRequest&, OptionSet<HTTPHeadersToKeepFromCleaning>);
 
-WEBCORE_EXPORT bool passesAccessControlCheck(const ResourceResponse&, StoredCredentialsPolicy, SecurityOrigin&, String& errorDescription);
-WEBCORE_EXPORT bool validatePreflightResponse(const ResourceRequest&, const ResourceResponse&, StoredCredentialsPolicy, SecurityOrigin&, String& errorDescription);
+class WEBCORE_EXPORT CrossOriginAccessControlCheckDisabler {
+public:
+    static CrossOriginAccessControlCheckDisabler& singleton();
+    virtual ~CrossOriginAccessControlCheckDisabler() = default;
+    void setCrossOriginAccessControlCheckEnabled(bool);
+    virtual bool crossOriginAccessControlCheckEnabled() const;
+private:
+    bool m_accessControlCheckEnabled { true };
+};
+
+WEBCORE_EXPORT Expected<void, String> passesAccessControlCheck(const ResourceResponse&, StoredCredentialsPolicy, const SecurityOrigin&, const CrossOriginAccessControlCheckDisabler*);
+WEBCORE_EXPORT Expected<void, String> validatePreflightResponse(const ResourceRequest&, const ResourceResponse&, StoredCredentialsPolicy, const SecurityOrigin&, const CrossOriginAccessControlCheckDisabler*);
 
 WEBCORE_EXPORT Optional<ResourceError> validateCrossOriginResourcePolicy(const SecurityOrigin&, const URL&, const ResourceResponse&);
 Optional<ResourceError> validateRangeRequestedFlag(const ResourceRequest&, const ResourceResponse&);
index b3df411..fe3461f 100644 (file)
@@ -63,12 +63,12 @@ void CrossOriginPreflightChecker::validatePreflightResponse(DocumentThreadableLo
     auto* frame = loader.document().frame();
     ASSERT(frame);
 
-    String errorDescription;
-    if (!WebCore::validatePreflightResponse(request, response, loader.options().storedCredentialsPolicy, loader.securityOrigin(), errorDescription)) {
+    auto result = WebCore::validatePreflightResponse(request, response, loader.options().storedCredentialsPolicy, loader.securityOrigin(), &CrossOriginAccessControlCheckDisabler::singleton());
+    if (!result) {
         if (auto* document = frame->document())
-            document->addConsoleMessage(MessageSource::Security, MessageLevel::Error, errorDescription);
+            document->addConsoleMessage(MessageSource::Security, MessageLevel::Error, result.error());
 
-        loader.preflightFailure(identifier, ResourceError(errorDomainWebKitInternal, 0, request.url(), errorDescription, ResourceError::Type::AccessControl));
+        loader.preflightFailure(identifier, ResourceError(errorDomainWebKitInternal, 0, request.url(), result.error(), ResourceError::Type::AccessControl));
         return;
     }
 
index 3742128..d56fa5b 100644 (file)
@@ -616,9 +616,9 @@ void DocumentThreadableLoader::loadRequest(ResourceRequest&& request, SecurityCh
             else {
                 ASSERT(m_options.mode == FetchOptions::Mode::Cors);
                 response.setTainting(ResourceResponse::Tainting::Cors);
-                String accessControlErrorDescription;
-                if (!passesAccessControlCheck(response, m_options.storedCredentialsPolicy, securityOrigin(), accessControlErrorDescription)) {
-                    logErrorAndFail(ResourceError(errorDomainWebKitInternal, 0, response.url(), accessControlErrorDescription, ResourceError::Type::AccessControl));
+                auto accessControlCheckResult = passesAccessControlCheck(response, m_options.storedCredentialsPolicy, securityOrigin(), &CrossOriginAccessControlCheckDisabler::singleton());
+                if (!accessControlCheckResult) {
+                    logErrorAndFail(ResourceError(errorDomainWebKitInternal, 0, response.url(), accessControlCheckResult.error(), ResourceError::Type::AccessControl));
                     return;
                 }
             }
index 8a5e196..2b34540 100644 (file)
@@ -281,9 +281,9 @@ void SubresourceLoader::willSendRequestInternal(ResourceRequest&& newRequest, co
             return completionHandler(WTFMove(newRequest));
         }
 
-        String errorDescription;
-        if (!checkRedirectionCrossOriginAccessControl(request(), redirectResponse, newRequest, errorDescription)) {
-            String errorMessage = "Cross-origin redirection to " + newRequest.url().string() + " denied by Cross-Origin Resource Sharing policy: " + errorDescription;
+        auto accessControlCheckResult = checkRedirectionCrossOriginAccessControl(request(), redirectResponse, newRequest);
+        if (!accessControlCheckResult) {
+            auto errorMessage = makeString("Cross-origin redirection to ", newRequest.url().string(), " denied by Cross-Origin Resource Sharing policy: ", accessControlCheckResult.error());
             if (m_frame && m_frame->document())
                 m_frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, errorMessage);
             RELEASE_LOG_IF_ALLOWED("willSendRequestInternal: resource load canceled because crosss-origin redirection denied by CORS policy");
@@ -411,12 +411,12 @@ void SubresourceLoader::didReceiveResponse(const ResourceResponse& response, Com
             m_frame->page()->diagnosticLoggingClient().logDiagnosticMessageWithResult(DiagnosticLoggingKeys::cachedResourceRevalidationKey(), emptyString(), DiagnosticLoggingResultFail, ShouldSample::Yes);
     }
 
-    String errorDescription;
-    if (!checkResponseCrossOriginAccessControl(response, errorDescription)) {
+    auto accessControlCheckResult = checkResponseCrossOriginAccessControl(response);
+    if (!accessControlCheckResult) {
         if (m_frame && m_frame->document())
-            m_frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, errorDescription);
+            m_frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, accessControlCheckResult.error());
         RELEASE_LOG_IF_ALLOWED("didReceiveResponse: canceling load because of cross origin access control");
-        cancel(ResourceError(String(), 0, request().url(), errorDescription, ResourceError::Type::AccessControl));
+        cancel(ResourceError(String(), 0, request().url(), accessControlCheckResult.error(), ResourceError::Type::AccessControl));
         return;
     }
 
@@ -600,22 +600,27 @@ static void logResourceLoaded(Frame* frame, CachedResource::Type type)
     frame->page()->diagnosticLoggingClient().logDiagnosticMessage(DiagnosticLoggingKeys::resourceLoadedKey(), resourceType, ShouldSample::Yes);
 }
 
-bool SubresourceLoader::checkResponseCrossOriginAccessControl(const ResourceResponse& response, String& errorDescription)
+Expected<void, String> SubresourceLoader::checkResponseCrossOriginAccessControl(const ResourceResponse& response)
 {
     if (!m_resource->isCrossOrigin() || options().mode != FetchOptions::Mode::Cors)
-        return true;
+        return { };
 
 #if ENABLE(SERVICE_WORKER)
-    if (response.source() == ResourceResponse::Source::ServiceWorker)
-        return response.tainting() != ResourceResponse::Tainting::Opaque;
+    if (response.source() == ResourceResponse::Source::ServiceWorker) {
+        if (response.tainting() == ResourceResponse::Tainting::Opaque) {
+            // FIXME: This should have an error message.
+            return makeUnexpected(String());
+        }
+        return { };
+    }
 #endif
 
     ASSERT(m_origin);
 
-    return passesAccessControlCheck(response, options().credentials == FetchOptions::Credentials::Include ? StoredCredentialsPolicy::Use : StoredCredentialsPolicy::DoNotUse, *m_origin, errorDescription);
+    return passesAccessControlCheck(response, options().credentials == FetchOptions::Credentials::Include ? StoredCredentialsPolicy::Use : StoredCredentialsPolicy::DoNotUse, *m_origin, &CrossOriginAccessControlCheckDisabler::singleton());
 }
 
-bool SubresourceLoader::checkRedirectionCrossOriginAccessControl(const ResourceRequest& previousRequest, const ResourceResponse& redirectResponse, ResourceRequest& newRequest, String& errorMessage)
+Expected<void, String> SubresourceLoader::checkRedirectionCrossOriginAccessControl(const ResourceRequest& previousRequest, const ResourceResponse& redirectResponse, ResourceRequest& newRequest)
 {
     bool crossOriginFlag = m_resource->isCrossOrigin();
     bool isNextRequestCrossOrigin = m_origin && !m_origin->canRequest(newRequest.url());
@@ -629,14 +634,17 @@ bool SubresourceLoader::checkRedirectionCrossOriginAccessControl(const ResourceR
     if (options().mode == FetchOptions::Mode::Cors) {
         if (m_resource->isCrossOrigin()) {
             auto locationString = redirectResponse.httpHeaderField(HTTPHeaderName::Location);
-            errorMessage = validateCrossOriginRedirectionURL(URL(redirectResponse.url(), locationString));
+            String errorMessage = validateCrossOriginRedirectionURL(URL(redirectResponse.url(), locationString));
             if (!errorMessage.isNull())
-                return false;
+                return makeUnexpected(WTFMove(errorMessage));
         }
 
         ASSERT(m_origin);
-        if (crossOriginFlag && !passesAccessControlCheck(redirectResponse, options().storedCredentialsPolicy, *m_origin, errorMessage))
-            return false;
+        if (crossOriginFlag) {
+            auto accessControlCheckResult = passesAccessControlCheck(redirectResponse, options().storedCredentialsPolicy, *m_origin, &CrossOriginAccessControlCheckDisabler::singleton());
+            if (!accessControlCheckResult)
+                return accessControlCheckResult;
+        }
     }
 
     bool redirectingToNewOrigin = false;
@@ -661,7 +669,7 @@ bool SubresourceLoader::checkRedirectionCrossOriginAccessControl(const ResourceR
     
     updateRequestReferrer(newRequest, referrerPolicy(), previousRequest.httpReferrer());
 
-    return true;
+    return { };
 }
 
 void SubresourceLoader::updateReferrerPolicy(const String& referrerPolicyValue)
index 9ecb782..11f5b1a 100644 (file)
@@ -89,8 +89,8 @@ private:
     void releaseResources() override;
 
     bool checkForHTTPStatusCodeError();
-    bool checkResponseCrossOriginAccessControl(const ResourceResponse&, String&);
-    bool checkRedirectionCrossOriginAccessControl(const ResourceRequest& previousRequest, const ResourceResponse&, ResourceRequest& newRequest, String&);
+    Expected<void, String> checkResponseCrossOriginAccessControl(const ResourceResponse&);
+    Expected<void, String> checkRedirectionCrossOriginAccessControl(const ResourceRequest& previousRequest, const ResourceResponse&, ResourceRequest& newRequest);
 
     void didReceiveDataOrBuffer(const char*, int, RefPtr<SharedBuffer>&&, long long encodedDataLength, DataPayloadType);
 
index 16a5351..5d86af6 100644 (file)
@@ -347,9 +347,9 @@ void CachedResource::loadFrom(const CachedResource& resource)
 
     if (isCrossOrigin() && m_options.mode == FetchOptions::Mode::Cors) {
         ASSERT(m_origin);
-        String errorMessage;
-        if (!WebCore::passesAccessControlCheck(resource.response(), m_options.storedCredentialsPolicy, *m_origin, errorMessage)) {
-            setResourceError(ResourceError(String(), 0, url(), errorMessage, ResourceError::Type::AccessControl));
+        auto accessControlCheckResult = WebCore::passesAccessControlCheck(resource.response(), m_options.storedCredentialsPolicy, *m_origin, &CrossOriginAccessControlCheckDisabler::singleton());
+        if (!accessControlCheckResult) {
+            setResourceError(ResourceError(String(), 0, url(), accessControlCheckResult.error(), ResourceError::Type::AccessControl));
             return;
         }
     }
index 2477c48..9ab46a2 100644 (file)
@@ -1,3 +1,52 @@
+2020-03-06  Alex Christensen  <achristensen@webkit.org>
+
+        Add SPI to disable cross origin access control checks
+        https://bugs.webkit.org/show_bug.cgi?id=208748
+        <rdar://problem/59861114>
+
+        Reviewed by Tim Hatcher.
+
+        * NetworkProcess/NetworkCORSPreflightChecker.cpp:
+        (WebKit::NetworkCORSPreflightChecker::NetworkCORSPreflightChecker):
+        (WebKit::NetworkCORSPreflightChecker::didCompleteWithError):
+        * NetworkProcess/NetworkCORSPreflightChecker.h:
+        * NetworkProcess/NetworkLoadChecker.cpp:
+        (WebKit::NetworkLoadChecker::NetworkLoadChecker):
+        (WebKit::NetworkLoadChecker::validateResponse):
+        (WebKit::NetworkLoadChecker::checkCORSRequestWithPreflight):
+        * NetworkProcess/NetworkLoadChecker.h:
+        * NetworkProcess/NetworkResourceLoadParameters.cpp:
+        (WebKit::NetworkResourceLoadParameters::encode const):
+        (WebKit::NetworkResourceLoadParameters::decode):
+        * NetworkProcess/NetworkResourceLoadParameters.h:
+        * NetworkProcess/NetworkResourceLoader.cpp:
+        (WebKit::NetworkResourceLoader::crossOriginAccessControlCheckEnabled const):
+        * NetworkProcess/NetworkResourceLoader.h:
+        * NetworkProcess/PingLoad.cpp:
+        (WebKit::PingLoad::PingLoad):
+        * Shared/WebPageCreationParameters.cpp:
+        (WebKit::WebPageCreationParameters::encode const):
+        (WebKit::WebPageCreationParameters::decode):
+        * Shared/WebPageCreationParameters.h:
+        * UIProcess/API/APIPageConfiguration.cpp:
+        (API::PageConfiguration::copy const):
+        * UIProcess/API/APIPageConfiguration.h:
+        (API::PageConfiguration::crossOriginAccessControlCheckEnabled const):
+        (API::PageConfiguration::setCrossOriginAccessControlCheckEnabled):
+        * UIProcess/API/Cocoa/WKWebViewConfiguration.mm:
+        (-[WKWebViewConfiguration _setCrossOriginAccessControlCheckEnabled:]):
+        (-[WKWebViewConfiguration _crossOriginAccessControlCheckEnabled]):
+        * UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h:
+        * UIProcess/WebPageProxy.cpp:
+        * WebProcess/Network/WebLoaderStrategy.cpp:
+        (WebKit::addParametersShared):
+        (WebKit::WebLoaderStrategy::scheduleLoadFromNetworkProcess):
+        (WebKit::WebLoaderStrategy::loadResourceSynchronously):
+        (WebKit::WebLoaderStrategy::startPingLoad):
+        (WebKit::addParametersFromFrame): Deleted.
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::m_processDisplayName):
+
 2020-03-06  Myles C. Maxfield  <mmaxfield@apple.com>
 
         [GPU Process] Implement CanvasRenderingContext2D.putImageData()
index 372d968..7939099 100644 (file)
@@ -31,6 +31,7 @@
 #include "Logging.h"
 #include "NetworkLoadParameters.h"
 #include "NetworkProcess.h"
+#include "NetworkResourceLoader.h"
 #include <WebCore/CrossOriginAccessControl.h>
 #include <WebCore/SecurityOrigin.h>
 
@@ -40,11 +41,12 @@ namespace WebKit {
 
 using namespace WebCore;
 
-NetworkCORSPreflightChecker::NetworkCORSPreflightChecker(NetworkProcess& networkProcess, Parameters&& parameters, bool shouldCaptureExtraNetworkLoadMetrics, CompletionCallback&& completionCallback)
+NetworkCORSPreflightChecker::NetworkCORSPreflightChecker(NetworkProcess& networkProcess, NetworkResourceLoader* networkResourceLoader, Parameters&& parameters, bool shouldCaptureExtraNetworkLoadMetrics, CompletionCallback&& completionCallback)
     : m_parameters(WTFMove(parameters))
     , m_networkProcess(networkProcess)
     , m_completionCallback(WTFMove(completionCallback))
     , m_shouldCaptureExtraNetworkLoadMetrics(shouldCaptureExtraNetworkLoadMetrics)
+    , m_networkResourceLoader(makeWeakPtr(networkResourceLoader))
 {
 }
 
@@ -137,10 +139,10 @@ void NetworkCORSPreflightChecker::didCompleteWithError(const WebCore::ResourceEr
 
     RELEASE_LOG_IF_ALLOWED("didComplete http_status_code: %d", m_response.httpStatusCode());
 
-    String errorDescription;
-    if (!validatePreflightResponse(m_parameters.originalRequest, m_response, m_parameters.storedCredentialsPolicy, m_parameters.sourceOrigin, errorDescription)) {
-        RELEASE_LOG_IF_ALLOWED("didComplete, AccessControl error: %s", errorDescription.utf8().data());
-        m_completionCallback(ResourceError { errorDomainWebKitInternal, 0, m_parameters.originalRequest.url(), errorDescription, ResourceError::Type::AccessControl });
+    auto result = validatePreflightResponse(m_parameters.originalRequest, m_response, m_parameters.storedCredentialsPolicy, m_parameters.sourceOrigin, m_networkResourceLoader.get());
+    if (!result) {
+        RELEASE_LOG_IF_ALLOWED("didComplete, AccessControl error: %s", result.error().utf8().data());
+        m_completionCallback(ResourceError { errorDomainWebKitInternal, 0, m_parameters.originalRequest.url(), result.error(), ResourceError::Type::AccessControl });
         return;
     }
     m_completionCallback(ResourceError { });
index dad429b..bbb1462 100644 (file)
@@ -42,6 +42,7 @@ class SecurityOrigin;
 namespace WebKit {
 
 class NetworkProcess;
+class NetworkResourceLoader;
 
 class NetworkCORSPreflightChecker final : private NetworkDataTaskClient {
     WTF_MAKE_FAST_ALLOCATED;
@@ -58,7 +59,7 @@ public:
     };
     using CompletionCallback = CompletionHandler<void(WebCore::ResourceError&&)>;
 
-    NetworkCORSPreflightChecker(NetworkProcess&, Parameters&&, bool shouldCaptureExtraNetworkLoadMetrics, CompletionCallback&&);
+    NetworkCORSPreflightChecker(NetworkProcess&, NetworkResourceLoader*, Parameters&&, bool shouldCaptureExtraNetworkLoadMetrics, CompletionCallback&&);
     ~NetworkCORSPreflightChecker();
     const WebCore::ResourceRequest& originalRequest() const { return m_parameters.originalRequest; }
 
@@ -84,6 +85,7 @@ private:
     RefPtr<NetworkDataTask> m_task;
     bool m_shouldCaptureExtraNetworkLoadMetrics { false };
     WebCore::NetworkTransactionInformation m_loadInformation;
+    WeakPtr<NetworkResourceLoader> m_networkResourceLoader;
 };
 
 } // namespace WebKit
index 39f5bd9..6edc251 100644 (file)
@@ -30,6 +30,7 @@
 #include "Logging.h"
 #include "NetworkCORSPreflightChecker.h"
 #include "NetworkProcess.h"
+#include "NetworkResourceLoader.h"
 #include "NetworkSchemeRegistry.h"
 #include <WebCore/ContentRuleListResults.h>
 #include <WebCore/ContentSecurityPolicy.h>
@@ -49,7 +50,7 @@ static inline bool isSameOrigin(const URL& url, const SecurityOrigin* origin)
     return url.protocolIsData() || url.protocolIsBlob() || !origin || origin->canRequest(url);
 }
 
-NetworkLoadChecker::NetworkLoadChecker(NetworkProcess& networkProcess, NetworkSchemeRegistry* schemeRegistry, FetchOptions&& options, PAL::SessionID sessionID, WebPageProxyIdentifier webPageProxyID, HTTPHeaderMap&& originalRequestHeaders, URL&& url, RefPtr<SecurityOrigin>&& sourceOrigin, RefPtr<SecurityOrigin>&& topOrigin, PreflightPolicy preflightPolicy, String&& referrer, bool isHTTPSUpgradeEnabled, bool shouldCaptureExtraNetworkLoadMetrics, LoadType requestLoadType)
+NetworkLoadChecker::NetworkLoadChecker(NetworkProcess& networkProcess, NetworkResourceLoader* networkResourceLoader, NetworkSchemeRegistry* schemeRegistry, FetchOptions&& options, PAL::SessionID sessionID, WebPageProxyIdentifier webPageProxyID, HTTPHeaderMap&& originalRequestHeaders, URL&& url, RefPtr<SecurityOrigin>&& sourceOrigin, RefPtr<SecurityOrigin>&& topOrigin, PreflightPolicy preflightPolicy, String&& referrer, bool isHTTPSUpgradeEnabled, bool shouldCaptureExtraNetworkLoadMetrics, LoadType requestLoadType)
     : m_options(WTFMove(options))
     , m_sessionID(sessionID)
     , m_networkProcess(networkProcess)
@@ -64,6 +65,7 @@ NetworkLoadChecker::NetworkLoadChecker(NetworkProcess& networkProcess, NetworkSc
     , m_isHTTPSUpgradeEnabled(isHTTPSUpgradeEnabled)
     , m_requestLoadType(requestLoadType)
     , m_schemeRegistry(schemeRegistry)
+    , m_networkResourceLoader(makeWeakPtr(networkResourceLoader))
 {
     m_isSameOriginRequest = isSameOrigin(m_url, m_origin.get());
     switch (options.credentials) {
@@ -187,9 +189,9 @@ ResourceError NetworkLoadChecker::validateResponse(const ResourceRequest& reques
     if (response.httpStatusCode() == 304)
         return { };
 
-    String errorMessage;
-    if (!passesAccessControlCheck(response, m_storedCredentialsPolicy, *m_origin, errorMessage))
-        return ResourceError { String { }, 0, m_url, WTFMove(errorMessage), ResourceError::Type::AccessControl };
+    auto result = passesAccessControlCheck(response, m_storedCredentialsPolicy, *m_origin, m_networkResourceLoader.get());
+    if (!result)
+        return ResourceError { String { }, 0, m_url, WTFMove(result.error()), ResourceError::Type::AccessControl };
 
     response.setTainting(ResourceResponse::Tainting::Cors);
     return { };
@@ -430,7 +432,7 @@ void NetworkLoadChecker::checkCORSRequestWithPreflight(ResourceRequest&& request
         m_webPageProxyID,
         m_storedCredentialsPolicy
     };
-    m_corsPreflightChecker = makeUnique<NetworkCORSPreflightChecker>(m_networkProcess.get(), WTFMove(parameters), m_shouldCaptureExtraNetworkLoadMetrics, [this, request = WTFMove(request), handler = WTFMove(handler), isRedirected = isRedirected()](auto&& error) mutable {
+    m_corsPreflightChecker = makeUnique<NetworkCORSPreflightChecker>(m_networkProcess.get(), m_networkResourceLoader.get(), WTFMove(parameters), m_shouldCaptureExtraNetworkLoadMetrics, [this, request = WTFMove(request), handler = WTFMove(handler), isRedirected = isRedirected()](auto&& error) mutable {
         RELEASE_LOG_IF_ALLOWED("checkCORSRequestWithPreflight - makeCrossOriginAccessRequestWithPreflight preflight complete, success: %d forRedirect? %d", error.isNull(), isRedirected);
 
         if (!error.isNull()) {
index a475612..a785cd5 100644 (file)
@@ -57,7 +57,7 @@ class NetworkLoadChecker : public CanMakeWeakPtr<NetworkLoadChecker> {
 public:
     enum class LoadType : bool { MainFrame, Other };
 
-    NetworkLoadChecker(NetworkProcess&, NetworkSchemeRegistry*, WebCore::FetchOptions&&, PAL::SessionID, WebPageProxyIdentifier, WebCore::HTTPHeaderMap&&, URL&&, RefPtr<WebCore::SecurityOrigin>&&, RefPtr<WebCore::SecurityOrigin>&& topOrigin, WebCore::PreflightPolicy, String&& referrer, bool isHTTPSUpgradeEnabled = false, bool shouldCaptureExtraNetworkLoadMetrics = false, LoadType requestLoadType = LoadType::Other);
+    NetworkLoadChecker(NetworkProcess&, NetworkResourceLoader*, NetworkSchemeRegistry*, WebCore::FetchOptions&&, PAL::SessionID, WebPageProxyIdentifier, WebCore::HTTPHeaderMap&&, URL&&, RefPtr<WebCore::SecurityOrigin>&&, RefPtr<WebCore::SecurityOrigin>&& topOrigin, WebCore::PreflightPolicy, String&& referrer, bool isHTTPSUpgradeEnabled = false, bool shouldCaptureExtraNetworkLoadMetrics = false, LoadType requestLoadType = LoadType::Other);
     ~NetworkLoadChecker();
 
     struct RedirectionTriplet {
@@ -157,6 +157,7 @@ private:
 
     LoadType m_requestLoadType;
     RefPtr<NetworkSchemeRegistry> m_schemeRegistry;
+    WeakPtr<NetworkResourceLoader> m_networkResourceLoader;
 };
 
 }
index 56297b6..994aaed 100644 (file)
@@ -108,6 +108,7 @@ void NetworkResourceLoadParameters::encode(IPC::Encoder& encoder) const
     encoder << isHTTPSUpgradeEnabled;
     encoder << pageHasResourceLoadClient;
     encoder << parentFrameID;
+    encoder << crossOriginAccessControlCheckEnabled;
 
 #if ENABLE(SERVICE_WORKER)
     encoder << serviceWorkersMode;
@@ -265,6 +266,12 @@ Optional<NetworkResourceLoadParameters> NetworkResourceLoadParameters::decode(IP
         return WTF::nullopt;
     result.parentFrameID = WTFMove(*parentFrameID);
 
+    Optional<bool> crossOriginAccessControlCheckEnabled;
+    decoder >> crossOriginAccessControlCheckEnabled;
+    if (!crossOriginAccessControlCheckEnabled)
+        return WTF::nullopt;
+    result.crossOriginAccessControlCheckEnabled = *crossOriginAccessControlCheckEnabled;
+    
 #if ENABLE(SERVICE_WORKER)
     Optional<ServiceWorkersMode> serviceWorkersMode;
     decoder >> serviceWorkersMode;
index f220269..a014b50 100644 (file)
@@ -63,6 +63,7 @@ public:
     bool isHTTPSUpgradeEnabled { false };
     bool pageHasResourceLoadClient { false };
     Optional<WebCore::FrameIdentifier> parentFrameID;
+    bool crossOriginAccessControlCheckEnabled { true };
 
 #if ENABLE(SERVICE_WORKER)
     WebCore::ServiceWorkersMode serviceWorkersMode { WebCore::ServiceWorkersMode::None };
index ccf8b29..a48acc8 100644 (file)
@@ -118,7 +118,7 @@ NetworkResourceLoader::NetworkResourceLoader(NetworkResourceLoadParameters&& par
 
     if (synchronousReply || parameters.shouldRestrictHTTPResponseAccess || parameters.options.keepAlive) {
         NetworkLoadChecker::LoadType requestLoadType = isMainFrameLoad() ? NetworkLoadChecker::LoadType::MainFrame : NetworkLoadChecker::LoadType::Other;
-        m_networkLoadChecker = makeUnique<NetworkLoadChecker>(connection.networkProcess(), &connection.schemeRegistry(), FetchOptions { m_parameters.options }, sessionID(), m_parameters.webPageProxyID, HTTPHeaderMap { m_parameters.originalRequestHeaders }, URL { m_parameters.request.url() }, m_parameters.sourceOrigin.copyRef(), m_parameters.topOrigin.copyRef(), m_parameters.preflightPolicy, originalRequest().httpReferrer(), m_parameters.isHTTPSUpgradeEnabled, shouldCaptureExtraNetworkLoadMetrics(), requestLoadType);
+        m_networkLoadChecker = makeUnique<NetworkLoadChecker>(connection.networkProcess(), this,  &connection.schemeRegistry(), FetchOptions { m_parameters.options }, sessionID(), m_parameters.webPageProxyID, HTTPHeaderMap { m_parameters.originalRequestHeaders }, URL { m_parameters.request.url() }, m_parameters.sourceOrigin.copyRef(), m_parameters.topOrigin.copyRef(), m_parameters.preflightPolicy, originalRequest().httpReferrer(), m_parameters.isHTTPSUpgradeEnabled, shouldCaptureExtraNetworkLoadMetrics(), requestLoadType);
         if (m_parameters.cspResponseHeaders)
             m_networkLoadChecker->setCSPResponseHeaders(ContentSecurityPolicyResponseHeaders { m_parameters.cspResponseHeaders.value() });
 #if ENABLE(CONTENT_EXTENSIONS)
@@ -1246,6 +1246,11 @@ bool NetworkResourceLoader::shouldCaptureExtraNetworkLoadMetrics() const
     return m_shouldCaptureExtraNetworkLoadMetrics;
 }
 
+bool NetworkResourceLoader::crossOriginAccessControlCheckEnabled() const
+{
+    return m_parameters.crossOriginAccessControlCheckEnabled;
+}
+
 #if ENABLE(RESOURCE_LOAD_STATISTICS) && !RELEASE_LOG_DISABLED
 bool NetworkResourceLoader::shouldLogCookieInformation(NetworkConnectionToWebProcess& connection, const PAL::SessionID& sessionID)
 {
index e23de93..67e08d5 100644 (file)
@@ -35,6 +35,7 @@
 #include "NetworkResourceLoadParameters.h"
 #include <WebCore/AdClickAttribution.h>
 #include <WebCore/ContentSecurityPolicyClient.h>
+#include <WebCore/CrossOriginAccessControl.h>
 #include <WebCore/ResourceResponse.h>
 #include <WebCore/SecurityPolicyViolationEvent.h>
 #include <WebCore/Timer.h>
@@ -68,6 +69,7 @@ class NetworkResourceLoader final
     , public NetworkLoadClient
     , public IPC::MessageSender
     , public WebCore::ContentSecurityPolicyClient
+    , public WebCore::CrossOriginAccessControlCheckDisabler
     , public CanMakeWeakPtr<NetworkResourceLoader> {
 public:
     static Ref<NetworkResourceLoader> create(NetworkResourceLoadParameters&& parameters, NetworkConnectionToWebProcess& connection, Messages::NetworkConnectionToWebProcess::PerformSynchronousLoadDelayedReply&& reply = nullptr)
@@ -114,6 +116,9 @@ public:
     void didReceiveChallenge(const WebCore::AuthenticationChallenge&) final;
     bool shouldCaptureExtraNetworkLoadMetrics() const final;
 
+    // CrossOriginAccessControlCheckDisabler
+    bool crossOriginAccessControlCheckEnabled() const override;
+        
     void convertToDownload(DownloadID, const WebCore::ResourceRequest&, const WebCore::ResourceResponse&);
 
     bool isMainResource() const { return m_parameters.request.requester() == WebCore::ResourceRequest::Requester::Main; }
index e54a887..b8fa58c 100644 (file)
@@ -45,7 +45,7 @@ PingLoad::PingLoad(NetworkProcess& networkProcess, PAL::SessionID sessionID, Net
     , m_parameters(WTFMove(parameters))
     , m_completionHandler(WTFMove(completionHandler))
     , m_timeoutTimer(*this, &PingLoad::timeoutTimerFired)
-    , m_networkLoadChecker(makeUniqueRef<NetworkLoadChecker>(networkProcess, nullptr, FetchOptions { m_parameters.options}, m_sessionID, m_parameters.webPageProxyID, WTFMove(m_parameters.originalRequestHeaders), URL { m_parameters.request.url() }, m_parameters.sourceOrigin.copyRef(), m_parameters.topOrigin.copyRef(), m_parameters.preflightPolicy, m_parameters.request.httpReferrer()))
+    , m_networkLoadChecker(makeUniqueRef<NetworkLoadChecker>(networkProcess, nullptr, nullptr, FetchOptions { m_parameters.options}, m_sessionID, m_parameters.webPageProxyID, WTFMove(m_parameters.originalRequestHeaders), URL { m_parameters.request.url() }, m_parameters.sourceOrigin.copyRef(), m_parameters.topOrigin.copyRef(), m_parameters.preflightPolicy, m_parameters.request.httpReferrer()))
 {
     initialize(networkProcess);
 }
@@ -55,7 +55,7 @@ PingLoad::PingLoad(NetworkConnectionToWebProcess& connection, NetworkResourceLoa
     , m_parameters(WTFMove(parameters))
     , m_completionHandler(WTFMove(completionHandler))
     , m_timeoutTimer(*this, &PingLoad::timeoutTimerFired)
-    , m_networkLoadChecker(makeUniqueRef<NetworkLoadChecker>(connection.networkProcess(), &connection.schemeRegistry(), FetchOptions { m_parameters.options}, m_sessionID, m_parameters.webPageProxyID, WTFMove(m_parameters.originalRequestHeaders), URL { m_parameters.request.url() }, m_parameters.sourceOrigin.copyRef(), m_parameters.topOrigin.copyRef(), m_parameters.preflightPolicy, m_parameters.request.httpReferrer()))
+    , m_networkLoadChecker(makeUniqueRef<NetworkLoadChecker>(connection.networkProcess(), nullptr,  &connection.schemeRegistry(), FetchOptions { m_parameters.options}, m_sessionID, m_parameters.webPageProxyID, WTFMove(m_parameters.originalRequestHeaders), URL { m_parameters.request.url() }, m_parameters.sourceOrigin.copyRef(), m_parameters.topOrigin.copyRef(), m_parameters.preflightPolicy, m_parameters.request.httpReferrer()))
     , m_blobFiles(connection.resolveBlobReferences(m_parameters))
 {
     for (auto& file : m_blobFiles) {
index a2c1da4..f8ab8be 100644 (file)
@@ -138,6 +138,7 @@ void WebPageCreationParameters::encode(IPC::Encoder& encoder) const
     encoder << oldPageID;
     encoder << overriddenMediaType;
     encoder << corsDisablingPatterns;
+    encoder << crossOriginAccessControlCheckEnabled;
     encoder << processDisplayName;
 
     encoder << shouldCaptureAudioInUIProcess;
@@ -443,6 +444,12 @@ Optional<WebPageCreationParameters> WebPageCreationParameters::decode(IPC::Decod
         return WTF::nullopt;
     parameters.corsDisablingPatterns = WTFMove(*corsDisablingPatterns);
 
+    Optional<bool> crossOriginAccessControlCheckEnabled;
+    decoder >> crossOriginAccessControlCheckEnabled;
+    if (!crossOriginAccessControlCheckEnabled)
+        return WTF::nullopt;
+    parameters.crossOriginAccessControlCheckEnabled = *crossOriginAccessControlCheckEnabled;
+    
     Optional<String> processDisplayName;
     decoder >> processDisplayName;
     if (!processDisplayName)
index a315807..6d17392 100644 (file)
@@ -209,6 +209,7 @@ struct WebPageCreationParameters {
 
     String overriddenMediaType;
     Vector<String> corsDisablingPatterns;
+    bool crossOriginAccessControlCheckEnabled { true };
     String processDisplayName;
 
     bool shouldCaptureAudioInUIProcess { false };
index 0a04163..fbba47c 100644 (file)
@@ -90,6 +90,7 @@ Ref<PageConfiguration> PageConfiguration::copy() const
     for (auto& pair : this->m_urlSchemeHandlers)
         copy->m_urlSchemeHandlers.set(pair.key, pair.value.copyRef());
     copy->m_corsDisablingPatterns = this->m_corsDisablingPatterns;
+    copy->m_crossOriginAccessControlCheckEnabled = this->m_crossOriginAccessControlCheckEnabled;
     copy->m_webViewCategory = this->m_webViewCategory;
 
     copy->m_processDisplayName = this->m_processDisplayName;
index 3b42462..88a0fad 100644 (file)
@@ -138,6 +138,9 @@ public:
     const Vector<WTF::String>& corsDisablingPatterns() const { return m_corsDisablingPatterns; }
     void setCORSDisablingPatterns(Vector<WTF::String>&& patterns) { m_corsDisablingPatterns = WTFMove(patterns); }
 
+    bool crossOriginAccessControlCheckEnabled() const { return m_crossOriginAccessControlCheckEnabled; }
+    void setCrossOriginAccessControlCheckEnabled(bool enabled) { m_crossOriginAccessControlCheckEnabled = enabled; }
+
     const WTF::String& processDisplayName() const { return m_processDisplayName; }
     void setProcessDisplayName(const WTF::String& name) { m_processDisplayName = name; }
 
@@ -181,6 +184,7 @@ private:
 
     HashMap<WTF::String, Ref<WebKit::WebURLSchemeHandler>> m_urlSchemeHandlers;
     Vector<WTF::String> m_corsDisablingPatterns;
+    bool m_crossOriginAccessControlCheckEnabled { true };
     WTF::String m_processDisplayName;
     WebKit::WebViewCategory m_webViewCategory { WebKit::WebViewCategory::AppBoundDomain };
 };
index 86d229d..86a3ba5 100644 (file)
@@ -913,6 +913,16 @@ ALLOW_DEPRECATED_DECLARATIONS_END
     _pageConfiguration->setCORSDisablingPatterns(WTFMove(vector));
 }
 
+- (void)_setCrossOriginAccessControlCheckEnabled:(BOOL)enabled
+{
+    _pageConfiguration->setCrossOriginAccessControlCheckEnabled(enabled);
+}
+
+- (BOOL)_crossOriginAccessControlCheckEnabled
+{
+    return _pageConfiguration->crossOriginAccessControlCheckEnabled();
+}
+
 - (BOOL)_drawsBackground
 {
     return _drawsBackground;
index 25e6ff9..fb72d9d 100644 (file)
@@ -84,6 +84,7 @@ typedef NS_ENUM(NSUInteger, _WKWebViewCategory) {
 
 @property (nonatomic, readonly) WKWebsiteDataStore *_websiteDataStoreIfExists WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 @property (nonatomic, copy, setter=_setCORSDisablingPatterns:) NSArray<NSString *> *_corsDisablingPatterns WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+@property (nonatomic, setter=_setCrossOriginAccessControlCheckEnabled:) BOOL _crossOriginAccessControlCheckEnabled WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 
 #if TARGET_OS_IPHONE
 @property (nonatomic, setter=_setClientNavigationsRunAtForegroundPriority:) BOOL _clientNavigationsRunAtForegroundPriority WK_API_AVAILABLE(ios(WK_IOS_TBA));
index 54aca16..e81da4a 100644 (file)
@@ -7722,6 +7722,7 @@ WebPageCreationParameters WebPageProxy::creationParameters(WebProcessProxy& proc
 
     parameters.overriddenMediaType = m_overriddenMediaType;
     parameters.corsDisablingPatterns = m_configuration->corsDisablingPatterns();
+    parameters.crossOriginAccessControlCheckEnabled = m_configuration->crossOriginAccessControlCheckEnabled();
     parameters.hasResourceLoadClient = !!m_resourceLoadClient;
 
     process.addWebUserContentControllerProxy(m_userContentController, parameters);
index 3532702..446eb53 100644 (file)
@@ -262,8 +262,10 @@ bool WebLoaderStrategy::tryLoadingUsingURLSchemeHandler(ResourceLoader& resource
     return true;
 }
 
-static void addParametersFromFrame(const Frame* frame, NetworkResourceLoadParameters& parameters)
+static void addParametersShared(const Frame* frame, NetworkResourceLoadParameters& parameters)
 {
+    parameters.crossOriginAccessControlCheckEnabled = CrossOriginAccessControlCheckDisabler::singleton().crossOriginAccessControlCheckEnabled();
+
     if (!frame)
         return;
 
@@ -311,7 +313,7 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL
     loadParameters.maximumBufferingTime = maximumBufferingTime;
     loadParameters.options = resourceLoader.options();
     loadParameters.preflightPolicy = resourceLoader.options().preflightPolicy;
-    addParametersFromFrame(frame, loadParameters);
+    addParametersShared(frame, loadParameters);
 
 #if ENABLE(SERVICE_WORKER)
     loadParameters.serviceWorkersMode = resourceLoader.options().serviceWorkersMode;
@@ -608,7 +610,7 @@ void WebLoaderStrategy::loadResourceSynchronously(FrameLoader& frameLoader, unsi
     if (webPage)
         loadParameters.isNavigatingToAppBoundDomain = webPage->isNavigatingToAppBoundDomain();
 
-    addParametersFromFrame(webFrame->coreFrame(), loadParameters);
+    addParametersShared(webFrame->coreFrame(), loadParameters);
 
     data.shrink(0);
 
@@ -681,7 +683,7 @@ void WebLoaderStrategy::startPingLoad(Frame& frame, ResourceRequest& request, co
         if (auto* contentSecurityPolicy = document->contentSecurityPolicy())
             loadParameters.cspResponseHeaders = contentSecurityPolicy->responseHeaders();
     }
-    addParametersFromFrame(&frame, loadParameters);
+    addParametersShared(&frame, loadParameters);
     
     auto* webFrameLoaderClient = toWebFrameLoaderClient(frame.loader().client());
     auto* webFrame = webFrameLoaderClient ? webFrameLoaderClient->webFrame() : nullptr;
index 91e3c0e..c6f1367 100644 (file)
@@ -529,6 +529,8 @@ WebPage::WebPage(PageIdentifier pageID, WebPageCreationParameters&& parameters)
 #endif
 
     pageConfiguration.corsDisablingPatterns = WTFMove(parameters.corsDisablingPatterns);
+    if (!parameters.crossOriginAccessControlCheckEnabled)
+        CrossOriginAccessControlCheckDisabler::singleton().setCrossOriginAccessControlCheckEnabled(false);
 
 #if ENABLE(ATTACHMENT_ELEMENT) && PLATFORM(IOS_FAMILY)
     if (parameters.frontboardExtensionHandle)
index 12ad34a..2412a0f 100644 (file)
@@ -1,3 +1,13 @@
+2020-03-06  Alex Christensen  <achristensen@webkit.org>
+
+        Add SPI to disable cross origin access control checks
+        https://bugs.webkit.org/show_bug.cgi?id=208748
+
+        Reviewed by Tim Hatcher.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/WKURLSchemeHandler-1.mm:
+        Add a test that verifies this SPI allows Access-Control-Allow-Origin: * with credentials.
+
 2020-03-06  Basuke Suzuki  <basuke.suzuki@sony.com>
 
         [webkitpy] Fix executive on Windows to run wpt server correctly
index 7d9345e..81bc342 100644 (file)
@@ -886,6 +886,59 @@ TEST(URLSchemeHandler, DisableCORS)
     EXPECT_FALSE(corsfailure);
 }
 
+TEST(URLSchemeHandler, DisableCORSCredentials)
+{
+    TestWebKitAPI::HTTPServer server({
+        { "/subresource", { {{ "Access-Control-Allow-Origin", "*" }}, "subresourcecontent" } }
+    });
+
+    bool corssuccess = false;
+    bool corsfailure = false;
+    bool done = false;
+
+    auto handler = adoptNS([[TestURLSchemeHandler alloc] init]);
+
+    WKWebViewConfiguration *configuration = [[[WKWebViewConfiguration alloc] init] autorelease];
+    [configuration setURLSchemeHandler:handler.get() forURLScheme:@"cors"];
+
+    [handler setStartURLSchemeTaskHandler:[&](WKWebView *, id<WKURLSchemeTask> task) {
+        if ([task.request.URL.path isEqualToString:@"/main.html"]) {
+            NSData *data = [[NSString stringWithFormat:@"<script>fetch('http://127.0.0.1:%d/subresource', {credentials:'include'}).then(function(){fetch('/corssuccess')}).catch(function(){fetch('/corsfailure')})</script>", server.port()] dataUsingEncoding:NSUTF8StringEncoding];
+            [task didReceiveResponse:[[[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:@"text/html" expectedContentLength:data.length textEncodingName:nil] autorelease]];
+            [task didReceiveData:data];
+            [task didFinish];
+        } else if ([task.request.URL.path isEqualToString:@"/corssuccess"]) {
+            corssuccess = true;
+            done = true;
+        } else if ([task.request.URL.path isEqualToString:@"/corsfailure"]) {
+            corsfailure = true;
+            done = true;
+        } else
+            ASSERT_NOT_REACHED();
+    }];
+    
+    {
+        auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration]);
+        [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"cors://host1/main.html"]]];
+        TestWebKitAPI::Util::run(&done);
+    }
+    EXPECT_FALSE(corssuccess);
+    EXPECT_TRUE(corsfailure);
+    
+    corssuccess = false;
+    corsfailure = false;
+    done = false;
+
+    configuration._crossOriginAccessControlCheckEnabled = NO;
+    {
+        auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration]);
+        [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"cors://host1/main.html"]]];
+        TestWebKitAPI::Util::run(&done);
+    }
+    EXPECT_TRUE(corssuccess);
+    EXPECT_FALSE(corsfailure);
+}
+
 TEST(URLSchemeHandler, DisableCORSScript)
 {
     TestWebKitAPI::HTTPServer server({