Title: [275276] trunk
Revision
275276
Author
you...@apple.com
Date
2021-03-31 04:16:12 -0700 (Wed, 31 Mar 2021)

Log Message

Apply permission policy to geolocation
https://bugs.webkit.org/show_bug.cgi?id=223248

Reviewed by Eric Carlson.

Source/WebCore:

Only allow third-party iframes if allowed by permission policy,
following https://w3c.github.io/geolocation-api/#permissions-policy.
Covered by API tests.

* Modules/geolocation/Geolocation.cpp:
(WebCore::Geolocation::shouldBlockGeolocationRequests):
* html/FeaturePolicy.cpp:
(WebCore::policyTypeName):
(WebCore::FeaturePolicy::parse):
(WebCore::FeaturePolicy::allows const):
* html/FeaturePolicy.h:

Tools:

* TestWebKitAPI/Tests/WebKitCocoa/UIDelegate.mm:
(-[GeolocationDelegateNew setValidationHandler:]):
(-[GeolocationDelegateNew _webView:requestGeolocationPermissionForOrigin:initiatedByFrame:decisionHandler:]):
(-[GeolocationPermissionMessageHandler userContentController:didReceiveScriptMessage:]):

LayoutTests:

* http/tests/security/sandboxed-iframe-geolocation-getCurrentPosition-expected.txt:
* http/tests/security/sandboxed-iframe-geolocation-watchPosition-expected.txt:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (275275 => 275276)


--- trunk/LayoutTests/ChangeLog	2021-03-31 11:11:17 UTC (rev 275275)
+++ trunk/LayoutTests/ChangeLog	2021-03-31 11:16:12 UTC (rev 275276)
@@ -1,3 +1,13 @@
+2021-03-31  Youenn Fablet  <you...@apple.com>
+
+        Apply permission policy to geolocation
+        https://bugs.webkit.org/show_bug.cgi?id=223248
+
+        Reviewed by Eric Carlson.
+
+        * http/tests/security/sandboxed-iframe-geolocation-getCurrentPosition-expected.txt:
+        * http/tests/security/sandboxed-iframe-geolocation-watchPosition-expected.txt:
+
 2021-03-31  Carlos Alberto Lopez Perez  <clo...@igalia.com>
 
         REGRESSION(r274244): [GTK][WPE] Two http/tests/security/contentSecurityPolicy tests crash

Modified: trunk/LayoutTests/http/tests/security/sandboxed-iframe-geolocation-getCurrentPosition-expected.txt (275275 => 275276)


--- trunk/LayoutTests/http/tests/security/sandboxed-iframe-geolocation-getCurrentPosition-expected.txt	2021-03-31 11:11:17 UTC (rev 275275)
+++ trunk/LayoutTests/http/tests/security/sandboxed-iframe-geolocation-getCurrentPosition-expected.txt	2021-03-31 11:16:12 UTC (rev 275276)
@@ -1,3 +1,4 @@
+CONSOLE MESSAGE: Feature policy 'Geolocation' check failed for iframe with origin 'null' and allow attribute ''.
 Tests that navigator.geolocation.getCurrentPosition() returns error PERMISSION_DENIED when called from a document in a sandboxed iframe.
 
 

Modified: trunk/LayoutTests/http/tests/security/sandboxed-iframe-geolocation-watchPosition-expected.txt (275275 => 275276)


--- trunk/LayoutTests/http/tests/security/sandboxed-iframe-geolocation-watchPosition-expected.txt	2021-03-31 11:11:17 UTC (rev 275275)
+++ trunk/LayoutTests/http/tests/security/sandboxed-iframe-geolocation-watchPosition-expected.txt	2021-03-31 11:16:12 UTC (rev 275276)
@@ -1,3 +1,4 @@
+CONSOLE MESSAGE: Feature policy 'Geolocation' check failed for iframe with origin 'null' and allow attribute ''.
 Tests that navigator.geolocation.watchPosition() returns error PERMISSION_DENIED when called from a document in a sandboxed iframe.
 
 

Modified: trunk/Source/WebCore/ChangeLog (275275 => 275276)


--- trunk/Source/WebCore/ChangeLog	2021-03-31 11:11:17 UTC (rev 275275)
+++ trunk/Source/WebCore/ChangeLog	2021-03-31 11:16:12 UTC (rev 275276)
@@ -1,3 +1,22 @@
+2021-03-31  Youenn Fablet  <you...@apple.com>
+
+        Apply permission policy to geolocation
+        https://bugs.webkit.org/show_bug.cgi?id=223248
+
+        Reviewed by Eric Carlson.
+
+        Only allow third-party iframes if allowed by permission policy,
+        following https://w3c.github.io/geolocation-api/#permissions-policy.
+        Covered by API tests.
+
+        * Modules/geolocation/Geolocation.cpp:
+        (WebCore::Geolocation::shouldBlockGeolocationRequests):
+        * html/FeaturePolicy.cpp:
+        (WebCore::policyTypeName):
+        (WebCore::FeaturePolicy::parse):
+        (WebCore::FeaturePolicy::allows const):
+        * html/FeaturePolicy.h:
+
 2021-03-31  Thibault Saunier  <tsaun...@igalia.com> and Philippe Normand  <pnorm...@igalia.com>
 
         [WebRTC][GStreamer] Build and use the openh264 based encoder if present on the system

Modified: trunk/Source/WebCore/Modules/geolocation/Geolocation.cpp (275275 => 275276)


--- trunk/Source/WebCore/Modules/geolocation/Geolocation.cpp	2021-03-31 11:11:17 UTC (rev 275275)
+++ trunk/Source/WebCore/Modules/geolocation/Geolocation.cpp	2021-03-31 11:16:12 UTC (rev 275276)
@@ -31,6 +31,7 @@
 #if ENABLE(GEOLOCATION)
 
 #include "Document.h"
+#include "FeaturePolicy.h"
 #include "Frame.h"
 #include "GeoNotifier.h"
 #include "GeolocationController.h"
@@ -351,6 +352,9 @@
     
 bool Geolocation::shouldBlockGeolocationRequests()
 {
+    if (!isFeaturePolicyAllowedByDocumentAndAllOwners(FeaturePolicy::Type::Geolocation, *document(), LogFeaturePolicyFailure::Yes))
+        return true;
+
     bool isSecure = SecurityOrigin::isSecure(document()->url()) || document()->isSecureContext();
     bool hasMixedContent = !document()->foundMixedContent().isEmpty();
     bool isLocalOrigin = securityOrigin()->isLocal();
@@ -358,7 +362,7 @@
         if (isLocalOrigin || (isSecure && !hasMixedContent) || isRequestFromIBooks())
             return false;
     }
-    
+
     logError(securityOrigin()->toString(), isSecure, hasMixedContent, document());
     return true;
 }

Modified: trunk/Source/WebCore/html/FeaturePolicy.cpp (275275 => 275276)


--- trunk/Source/WebCore/html/FeaturePolicy.cpp	2021-03-31 11:11:17 UTC (rev 275275)
+++ trunk/Source/WebCore/html/FeaturePolicy.cpp	2021-03-31 11:16:12 UTC (rev 275276)
@@ -48,6 +48,8 @@
         return "SpeakerSelection";
     case FeaturePolicy::Type::DisplayCapture:
         return "DisplayCapture";
+    case FeaturePolicy::Type::Geolocation:
+        return "Geolocation";
     case FeaturePolicy::Type::SyncXHR:
         return "SyncXHR";
     case FeaturePolicy::Type::Fullscreen:
@@ -167,6 +169,7 @@
     bool isMicrophoneInitialized = false;
     bool isSpeakerSelectionInitialized = false;
     bool isDisplayCaptureInitialized = false;
+    bool isGeolocationInitialized = false;
     bool isSyncXHRInitialized = false;
     bool isFullscreenInitialized = false;
 #if ENABLE(DEVICE_ORIENTATION)
@@ -199,6 +202,11 @@
             updateList(document, policy.m_displayCaptureRule, item.substring(16));
             continue;
         }
+        if (item.startsWith("geolocation")) {
+            isGeolocationInitialized = true;
+            updateList(document, policy.m_geolocationRule, item.substring(12));
+            continue;
+        }
         if (item.startsWith("sync-xhr")) {
             isSyncXHRInitialized = true;
             updateList(document, policy.m_syncXHRRule, item.substring(9));
@@ -244,6 +252,8 @@
         policy.m_speakerSelectionRule.allowedList.add(document.securityOrigin().data());
     if (!isDisplayCaptureInitialized)
         policy.m_displayCaptureRule.allowedList.add(document.securityOrigin().data());
+    if (!isGeolocationInitialized)
+        policy.m_geolocationRule.allowedList.add(document.securityOrigin().data());
 #if ENABLE(DEVICE_ORIENTATION)
     if (!isGyroscopeInitialized)
         policy.m_gyroscopeRule.allowedList.add(document.securityOrigin().data());
@@ -289,6 +299,8 @@
         return isAllowedByFeaturePolicy(m_speakerSelectionRule, origin);
     case Type::DisplayCapture:
         return isAllowedByFeaturePolicy(m_displayCaptureRule, origin);
+    case Type::Geolocation:
+        return isAllowedByFeaturePolicy(m_geolocationRule, origin);
     case Type::SyncXHR:
         return isAllowedByFeaturePolicy(m_syncXHRRule, origin);
     case Type::Fullscreen:

Modified: trunk/Source/WebCore/html/FeaturePolicy.h (275275 => 275276)


--- trunk/Source/WebCore/html/FeaturePolicy.h	2021-03-31 11:11:17 UTC (rev 275275)
+++ trunk/Source/WebCore/html/FeaturePolicy.h	2021-03-31 11:16:12 UTC (rev 275276)
@@ -43,6 +43,7 @@
         Microphone,
         SpeakerSelection,
         DisplayCapture,
+        Geolocation,
         SyncXHR,
         Fullscreen,
 #if ENABLE(DEVICE_ORIENTATION)
@@ -67,6 +68,7 @@
     AllowRule m_microphoneRule;
     AllowRule m_speakerSelectionRule;
     AllowRule m_displayCaptureRule;
+    AllowRule m_geolocationRule;
     AllowRule m_syncXHRRule;
     AllowRule m_fullscreenRule;
 #if ENABLE(DEVICE_ORIENTATION)

Modified: trunk/Tools/ChangeLog (275275 => 275276)


--- trunk/Tools/ChangeLog	2021-03-31 11:11:17 UTC (rev 275275)
+++ trunk/Tools/ChangeLog	2021-03-31 11:16:12 UTC (rev 275276)
@@ -1,3 +1,15 @@
+2021-03-31  Youenn Fablet  <you...@apple.com>
+
+        Apply permission policy to geolocation
+        https://bugs.webkit.org/show_bug.cgi?id=223248
+
+        Reviewed by Eric Carlson.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/UIDelegate.mm:
+        (-[GeolocationDelegateNew setValidationHandler:]):
+        (-[GeolocationDelegateNew _webView:requestGeolocationPermissionForOrigin:initiatedByFrame:decisionHandler:]):
+        (-[GeolocationPermissionMessageHandler userContentController:didReceiveScriptMessage:]):
+
 2021-03-30  Chris Dumez  <cdu...@apple.com>
 
         Service Worker scripts use too much memory in the network process

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/UIDelegate.mm (275275 => 275276)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/UIDelegate.mm	2021-03-31 11:11:17 UTC (rev 275275)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/UIDelegate.mm	2021-03-31 11:16:12 UTC (rev 275276)
@@ -49,6 +49,7 @@
 #endif
 
 static bool done;
+static bool didReceiveMessage;
 
 @interface AudioObserver : NSObject
 @end
@@ -215,33 +216,43 @@
 }
 
 @interface GeolocationDelegateNew : NSObject <WKUIDelegatePrivate>
+- (void)setValidationHandler:(Function<void(WKSecurityOrigin*, WKFrameInfo*)>&&)validationHandler;
 @end
 
-@implementation GeolocationDelegateNew
+@implementation GeolocationDelegateNew {
+    Function<void(WKSecurityOrigin*, WKFrameInfo*)> _validationHandler;
+}
+- (void)setValidationHandler:(Function<void(WKSecurityOrigin*, WKFrameInfo*)>&&)validationHandler {
+    _validationHandler = WTFMove(validationHandler);
+}
+
 - (void)_webView:(WKWebView *)webView requestGeolocationPermissionForOrigin:(WKSecurityOrigin*)origin initiatedByFrame:(WKFrameInfo *)frame decisionHandler:(void (^)(WKPermissionDecision decision))decisionHandler {
-    EXPECT_WK_STREQ(origin.protocol, @"https");
-    EXPECT_WK_STREQ(origin.host, @"127.0.0.1");
-    EXPECT_EQ(origin.port, 9090);
+    if (_validationHandler)
+        _validationHandler(origin, frame);
 
-    EXPECT_WK_STREQ(frame.securityOrigin.protocol, @"https");
-    EXPECT_WK_STREQ(frame.securityOrigin.host, @"127.0.0.1");
-    EXPECT_EQ(frame.securityOrigin.port, 9091);
-    EXPECT_FALSE(frame.isMainFrame);
-    EXPECT_TRUE(frame.webView == webView);
-
     done  = true;
     decisionHandler(WKPermissionDecisionGrant);
 }
 @end
+ 
+@interface GeolocationPermissionMessageHandler : NSObject <WKScriptMessageHandler>
+@end
 
+@implementation GeolocationPermissionMessageHandler
+- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
+{
+    didReceiveMessage = true;
+}
+@end
+
 static const char* mainFrameText = R"DOCDOCDOC(
 <html><body>
-<iframe src='' allow='camera:https://127.0.0.1:9091'></iframe>
+<iframe src='' allow='geolocation:https://127.0.0.1:9091'></iframe>
 </body></html>
 )DOCDOCDOC";
 static const char* frameText = R"DOCDOCDOC(
 <html><body><script>
-navigator.geolocation.getCurrentPosition(() => { });
+navigator.geolocation.getCurrentPosition(() => { webkit.messageHandlers.testHandler.postMessage("ok") }, () => { webkit.messageHandlers.testHandler.postMessage("ko") });
 </script></body></html>
 )DOCDOCDOC";
 
@@ -267,10 +278,14 @@
 
     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
     configuration.get().processPool = pool.get();
+
+    auto messageHandler = adoptNS([[GeolocationPermissionMessageHandler alloc] init]);
+    [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"testHandler"];
+
     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
 
-    auto delegate = adoptNS([[GeolocationDelegateNew alloc] init]);
-    [webView setUIDelegate:delegate.get()];
+    auto permissionDelegate = adoptNS([[GeolocationDelegateNew alloc] init]);
+    [webView setUIDelegate:permissionDelegate.get()];
 
     auto navigationDelegate = adoptNS([TestNavigationDelegate new]);
     [navigationDelegate setDidReceiveAuthenticationChallenge:^(WKWebView *, NSURLAuthenticationChallenge *challenge, void (^callback)(NSURLSessionAuthChallengeDisposition, NSURLCredential *)) {
@@ -279,10 +294,76 @@
     }];
     webView.get().navigationDelegate = navigationDelegate.get();
 
+    [permissionDelegate setValidationHandler:[&webView](WKSecurityOrigin *origin, WKFrameInfo *frame) {
+        EXPECT_WK_STREQ(origin.protocol, @"https");
+        EXPECT_WK_STREQ(origin.host, @"127.0.0.1");
+        EXPECT_EQ(origin.port, 9090);
+
+        EXPECT_WK_STREQ(frame.securityOrigin.protocol, @"https");
+        EXPECT_WK_STREQ(frame.securityOrigin.host, @"127.0.0.1");
+        EXPECT_EQ(frame.securityOrigin.port, 9091);
+        EXPECT_FALSE(frame.isMainFrame);
+        EXPECT_TRUE(frame.webView == webView);
+    }];
+
+    done = false;
+    didReceiveMessage = false;
     [webView loadRequest:server1.request()];
-    TestWebKitAPI::Util::run(&done);
+    TestWebKitAPI::Util::run(&didReceiveMessage);
+    EXPECT_TRUE(done);
 }
 
+static const char* notAllowingMainFrameText = R"DOCDOCDOC(
+<html><body>
+<iframe src='' allow='geolocation:https://127.0.0.1:9092'></iframe>
+</body></html>
+)DOCDOCDOC";
+
+TEST(WebKit, GeolocationPermissionInDisallowedIFrame)
+{
+    TestWebKitAPI::HTTPServer server1({
+        { "/", { notAllowingMainFrameText } }
+    }, TestWebKitAPI::HTTPServer::Protocol::Https, nullptr, nullptr, 9090);
+
+    TestWebKitAPI::HTTPServer server2({
+        { "/frame", { frameText } },
+    }, TestWebKitAPI::HTTPServer::Protocol::Https, nullptr, nullptr, 9091);
+
+    auto pool = adoptNS([[WKProcessPool alloc] init]);
+
+    WKGeolocationProviderV1 providerCallback;
+    memset(&providerCallback, 0, sizeof(WKGeolocationProviderV1));
+    providerCallback.base.version = 1;
+    providerCallback.startUpdating = [] (WKGeolocationManagerRef manager, const void*) {
+        WKGeolocationManagerProviderDidChangePosition(manager, adoptWK(WKGeolocationPositionCreate(0, 50.644358, 3.345453, 2.53)).get());
+    };
+    WKGeolocationManagerSetProvider(WKContextGetGeolocationManager((WKContextRef)pool.get()), &providerCallback.base);
+
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    configuration.get().processPool = pool.get();
+
+    auto messageHandler = adoptNS([[GeolocationPermissionMessageHandler alloc] init]);
+    [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"testHandler"];
+
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
+
+    auto permissionDelegate = adoptNS([[GeolocationDelegateNew alloc] init]);
+    [webView setUIDelegate:permissionDelegate.get()];
+
+    auto navigationDelegate = adoptNS([TestNavigationDelegate new]);
+    [navigationDelegate setDidReceiveAuthenticationChallenge:^(WKWebView *, NSURLAuthenticationChallenge *challenge, void (^callback)(NSURLSessionAuthChallengeDisposition, NSURLCredential *)) {
+        EXPECT_WK_STREQ(challenge.protectionSpace.authenticationMethod, NSURLAuthenticationMethodServerTrust);
+        callback(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
+    }];
+    webView.get().navigationDelegate = navigationDelegate.get();
+
+    done = false;
+    didReceiveMessage = false;
+    [webView loadRequest:server1.request()];
+    TestWebKitAPI::Util::run(&didReceiveMessage);
+    EXPECT_FALSE(done);
+}
+
 @interface InjectedBundleNodeHandleIsSelectElementDelegate : NSObject <WKUIDelegatePrivate>
 @end
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to