[WebAuthn] Implement SPI -[_WKWebAuthenticationPanelDelegate panel:selectAssertionRes...
authorjiewen_tan@apple.com <jiewen_tan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 5 Mar 2020 23:58:10 +0000 (23:58 +0000)
committerjiewen_tan@apple.com <jiewen_tan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 5 Mar 2020 23:58:10 +0000 (23:58 +0000)
https://bugs.webkit.org/show_bug.cgi?id=208626
<rdar://problem/60074148>

Reviewed by Brent Fulgham.

Source/WebKit:

The patch adds a parameter (source) to the original SPI such that clients can know where those responses are from.
Besides that this patch also changes the completionHandler to accept a pointer instead of a reference such that clients
can pass a nullptr as a no op. In order to keep WebKitTestRunner running, the patch then overrides this SPI in the C API to
always return the first item.

* UIProcess/API/APIWebAuthenticationAssertionResponse.h:
* UIProcess/API/APIWebAuthenticationPanelClient.h:
(API::WebAuthenticationPanelClient::selectAssertionResponse const):
* UIProcess/API/C/WKPage.cpp:
(WKPageSetPageUIClient):
* UIProcess/API/Cocoa/_WKWebAuthenticationPanel.h:
* UIProcess/WebAuthentication/Authenticator.h:
* UIProcess/WebAuthentication/AuthenticatorManager.cpp:
(WebKit::AuthenticatorManager::selectAssertionResponse):
* UIProcess/WebAuthentication/AuthenticatorManager.h:
* UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm:
(WebKit::LocalAuthenticator::getAssertion):
* UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.h:
* UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm:
(WebKit::WebAuthenticationPanelClient::WebAuthenticationPanelClient):
(WebKit::wkWebAuthenticationSource):
(WebKit::WebAuthenticationPanelClient::selectAssertionResponse const):
* UIProcess/WebAuthentication/WebAuthenticationFlags.h:
* UIProcess/WebAuthentication/fido/CtapAuthenticator.cpp:
(WebKit::CtapAuthenticator::continueGetNextAssertionAfterResponseReceived):

Tools:

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm:
(-[TestWebAuthenticationPanelDelegate panel:selectAssertionResponse:source:completionHandler:]):
(TestWebKitAPI::TEST):
(-[TestWebAuthenticationPanelDelegate panel:selectAssertionResponse:completionHandler:]): Deleted.
* TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-hid-multiple-accounts.html:
* TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-la.html: Added.

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

18 files changed:
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/API/APIWebAuthenticationAssertionResponse.h
Source/WebKit/UIProcess/API/APIWebAuthenticationPanelClient.h
Source/WebKit/UIProcess/API/C/WKPage.cpp
Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationPanel.h
Source/WebKit/UIProcess/WebAuthentication/Authenticator.h
Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp
Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h
Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm
Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.h
Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm
Source/WebKit/UIProcess/WebAuthentication/WebAuthenticationFlags.h
Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm
Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-hid-multiple-accounts.html
Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-la.html [new file with mode: 0644]

index 905372a..d667e90 100644 (file)
@@ -1,3 +1,37 @@
+2020-03-05  Jiewen Tan  <jiewen_tan@apple.com>
+
+        [WebAuthn] Implement SPI -[_WKWebAuthenticationPanelDelegate panel:selectAssertionResponse:source:completionHandler:]
+        https://bugs.webkit.org/show_bug.cgi?id=208626
+        <rdar://problem/60074148>
+
+        Reviewed by Brent Fulgham.
+
+        The patch adds a parameter (source) to the original SPI such that clients can know where those responses are from.
+        Besides that this patch also changes the completionHandler to accept a pointer instead of a reference such that clients
+        can pass a nullptr as a no op. In order to keep WebKitTestRunner running, the patch then overrides this SPI in the C API to
+        always return the first item.
+
+        * UIProcess/API/APIWebAuthenticationAssertionResponse.h:
+        * UIProcess/API/APIWebAuthenticationPanelClient.h:
+        (API::WebAuthenticationPanelClient::selectAssertionResponse const):
+        * UIProcess/API/C/WKPage.cpp:
+        (WKPageSetPageUIClient):
+        * UIProcess/API/Cocoa/_WKWebAuthenticationPanel.h:
+        * UIProcess/WebAuthentication/Authenticator.h:
+        * UIProcess/WebAuthentication/AuthenticatorManager.cpp:
+        (WebKit::AuthenticatorManager::selectAssertionResponse):
+        * UIProcess/WebAuthentication/AuthenticatorManager.h:
+        * UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm:
+        (WebKit::LocalAuthenticator::getAssertion):
+        * UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.h:
+        * UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm:
+        (WebKit::WebAuthenticationPanelClient::WebAuthenticationPanelClient):
+        (WebKit::wkWebAuthenticationSource):
+        (WebKit::WebAuthenticationPanelClient::selectAssertionResponse const):
+        * UIProcess/WebAuthentication/WebAuthenticationFlags.h:
+        * UIProcess/WebAuthentication/fido/CtapAuthenticator.cpp:
+        (WebKit::CtapAuthenticator::continueGetNextAssertionAfterResponseReceived):
+
 2020-03-05  Chris Dumez  <cdumez@apple.com>
 
         Running a single layout test makes 28 WebProcessPools (and launches 6 Network processes)
index 4176208..0170081 100644 (file)
@@ -43,7 +43,7 @@ public:
     const WTF::String& displayName() const { return m_response->displayName(); }
     RefPtr<Data> userHandle() const;
 
-    const WebCore::AuthenticatorAssertionResponse& response() { return m_response.get(); }
+    WebCore::AuthenticatorAssertionResponse* response() { return m_response.ptr(); }
 
 private:
     WebAuthenticationAssertionResponse(Ref<WebCore::AuthenticatorAssertionResponse>&&);
index cd0d6ab..f012039 100644 (file)
@@ -50,7 +50,7 @@ public:
     virtual void updatePanel(WebKit::WebAuthenticationStatus) const { }
     virtual void dismissPanel(WebKit::WebAuthenticationResult) const { }
     virtual void requestPin(uint64_t, CompletionHandler<void(const WTF::String&)>&& completionHandler) const { completionHandler(emptyString()); }
-    virtual void selectAssertionResponse(Vector<Ref<WebCore::AuthenticatorAssertionResponse>>&& responses, CompletionHandler<void(const WebCore::AuthenticatorAssertionResponse&)>&& completionHandler) const { ASSERT(!responses.isEmpty()); completionHandler(responses[0]); }
+    virtual void selectAssertionResponse(Vector<Ref<WebCore::AuthenticatorAssertionResponse>>&& responses, WebKit::WebAuthenticationSource, CompletionHandler<void(WebCore::AuthenticatorAssertionResponse*)>&& completionHandler) const { completionHandler(nullptr); }
     virtual void decidePolicyForLocalAuthenticator(CompletionHandler<void(WebKit::LocalAuthenticatorPolicy)>&& completionHandler) const { completionHandler(WebKit::LocalAuthenticatorPolicy::Disallow); }
 };
 
index 00f4905..2b246ed 100644 (file)
@@ -2083,9 +2083,18 @@ void WKPageSetPageUIClient(WKPageRef pageRef, const WKPageUIClientBase* wkClient
         // The current method is specialized for WebKitTestRunner.
         void runWebAuthenticationPanel(WebPageProxy&, API::WebAuthenticationPanel& panel, WebFrameProxy&, FrameInfoData&&, CompletionHandler<void(WebKit::WebAuthenticationPanelResult)>&& completionHandler) final
         {
-            class PanelClient : public API::WebAuthenticationPanelClient {
+            class PanelClient final : public API::WebAuthenticationPanelClient {
             public:
-                void decidePolicyForLocalAuthenticator(CompletionHandler<void(WebKit::LocalAuthenticatorPolicy)>&& completionHandler) const { completionHandler(WebKit::LocalAuthenticatorPolicy::Allow); }
+                void selectAssertionResponse(Vector<Ref<WebCore::AuthenticatorAssertionResponse>>&& responses, WebKit::WebAuthenticationSource, CompletionHandler<void(WebCore::AuthenticatorAssertionResponse*)>&& completionHandler) const final
+                {
+                    ASSERT(!responses.isEmpty());
+                    completionHandler(responses[0].ptr());
+                }
+
+                void decidePolicyForLocalAuthenticator(CompletionHandler<void(WebKit::LocalAuthenticatorPolicy)>&& completionHandler) const final
+                {
+                    completionHandler(WebKit::LocalAuthenticatorPolicy::Allow);
+                }
             };
 
             if (!m_client.runWebAuthenticationPanel) {
index 883dff4..d5158bf 100644 (file)
@@ -73,6 +73,11 @@ typedef NS_ENUM(NSInteger, _WKLocalAuthenticatorPolicy) {
     _WKLocalAuthenticatorPolicyDisallow,
 } WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 
+typedef NS_ENUM(NSInteger, _WKWebAuthenticationSource) {
+    _WKWebAuthenticationSourceLocal,
+    _WKWebAuthenticationSourceExternal,
+} WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+
 @protocol _WKWebAuthenticationPanelDelegate <NSObject>
 
 @optional
@@ -80,7 +85,7 @@ typedef NS_ENUM(NSInteger, _WKLocalAuthenticatorPolicy) {
 - (void)panel:(_WKWebAuthenticationPanel *)panel updateWebAuthenticationPanel:(_WKWebAuthenticationPanelUpdate)update WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 - (void)panel:(_WKWebAuthenticationPanel *)panel dismissWebAuthenticationPanelWithResult:(_WKWebAuthenticationResult)result WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 - (void)panel:(_WKWebAuthenticationPanel *)panel requestPINWithRemainingRetries:(NSUInteger)retries completionHandler:(void (^)(NSString *))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
-- (void)panel:(_WKWebAuthenticationPanel *)panel selectAssertionResponse:(NSArray < _WKWebAuthenticationAssertionResponse *> *)responses completionHandler:(void (^)(_WKWebAuthenticationAssertionResponse *))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+- (void)panel:(_WKWebAuthenticationPanel *)panel selectAssertionResponse:(NSArray < _WKWebAuthenticationAssertionResponse *> *)responses source:(_WKWebAuthenticationSource)source completionHandler:(void (^)(_WKWebAuthenticationAssertionResponse *))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 - (void)panel:(_WKWebAuthenticationPanel *)panel decidePolicyForLocalAuthenticatorWithCompletionHandler:(void (^)(_WKLocalAuthenticatorPolicy policy))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 
 @end
index 5671aec..78e32fb 100644 (file)
@@ -55,7 +55,7 @@ public:
         virtual void downgrade(Authenticator* id, Ref<Authenticator>&& downgradedAuthenticator) = 0;
         virtual void authenticatorStatusUpdated(WebAuthenticationStatus) = 0;
         virtual void requestPin(uint64_t retries, CompletionHandler<void(const WTF::String&)>&&) = 0;
-        virtual void selectAssertionResponse(const HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>&, CompletionHandler<void(const WebCore::AuthenticatorAssertionResponse&)>&&) = 0;
+        virtual void selectAssertionResponse(const HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>&, WebAuthenticationSource, CompletionHandler<void(WebCore::AuthenticatorAssertionResponse*)>&&) = 0;
         virtual void decidePolicyForLocalAuthenticator(CompletionHandler<void(LocalAuthenticatorPolicy)>&&) = 0;
     };
 
index c391801..9778375 100644 (file)
@@ -283,15 +283,15 @@ void AuthenticatorManager::requestPin(uint64_t retries, CompletionHandler<void(c
     });
 }
 
-void AuthenticatorManager::selectAssertionResponse(const HashSet<Ref<AuthenticatorAssertionResponse>>& responses, CompletionHandler<void(const AuthenticatorAssertionResponse&)>&& completionHandler)
+void AuthenticatorManager::selectAssertionResponse(const HashSet<Ref<AuthenticatorAssertionResponse>>& responses, WebAuthenticationSource source, CompletionHandler<void(AuthenticatorAssertionResponse*)>&& completionHandler)
 {
     Vector<Ref<AuthenticatorAssertionResponse>> responseVector;
     responseVector.reserveInitialCapacity(responses.size());
     for (auto& response : responses)
         responseVector.uncheckedAppend(response.copyRef());
 
-    dispatchPanelClientCall([responses = WTFMove(responseVector), completionHandler = WTFMove(completionHandler)] (const API::WebAuthenticationPanel& panel) mutable {
-        panel.client().selectAssertionResponse(WTFMove(responses), WTFMove(completionHandler));
+    dispatchPanelClientCall([responses = WTFMove(responseVector), source, completionHandler = WTFMove(completionHandler)] (const API::WebAuthenticationPanel& panel) mutable {
+        panel.client().selectAssertionResponse(WTFMove(responses), source, WTFMove(completionHandler));
     });
 }
 
index bd0b96d..9823386 100644 (file)
@@ -82,7 +82,7 @@ private:
     void downgrade(Authenticator* id, Ref<Authenticator>&& downgradedAuthenticator) final;
     void authenticatorStatusUpdated(WebAuthenticationStatus) final;
     void requestPin(uint64_t retries, CompletionHandler<void(const WTF::String&)>&&) final;
-    void selectAssertionResponse(const HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>&, CompletionHandler<void(const WebCore::AuthenticatorAssertionResponse&)>&&) final;
+    void selectAssertionResponse(const HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>&, WebAuthenticationSource, CompletionHandler<void(WebCore::AuthenticatorAssertionResponse*)>&&) final;
     void decidePolicyForLocalAuthenticator(CompletionHandler<void(LocalAuthenticatorPolicy)>&&) final;
 
     // Overriden by MockAuthenticatorManager.
index f1d9445..da8c1b3 100644 (file)
@@ -423,17 +423,17 @@ void LocalAuthenticator::getAssertion()
     m_connection->filterResponses(m_assertionResponses);
 
     if (auto* observer = this->observer()) {
-        auto callback = [this, weakThis = makeWeakPtr(*this)] (const AuthenticatorAssertionResponse& response) {
+        auto callback = [this, weakThis = makeWeakPtr(*this)] (AuthenticatorAssertionResponse* response) {
             ASSERT(RunLoop::isMain());
             if (!weakThis)
                 return;
 
-            auto returnResponse = m_assertionResponses.take(const_cast<AuthenticatorAssertionResponse*>(&response));
+            auto returnResponse = m_assertionResponses.take(response);
             if (!returnResponse)
                 return;
             continueGetAssertionAfterResponseSelected(WTFMove(*returnResponse));
         };
-        observer->selectAssertionResponse(m_assertionResponses, WTFMove(callback));
+        observer->selectAssertionResponse(m_assertionResponses, WebAuthenticationSource::Local, WTFMove(callback));
     }
 }
 
index d2edff6..8270164 100644 (file)
@@ -49,7 +49,7 @@ private:
     void updatePanel(WebAuthenticationStatus) const final;
     void dismissPanel(WebAuthenticationResult) const final;
     void requestPin(uint64_t, CompletionHandler<void(const WTF::String&)>&&) const final;
-    void selectAssertionResponse(Vector<Ref<WebCore::AuthenticatorAssertionResponse>>&&, CompletionHandler<void(const WebCore::AuthenticatorAssertionResponse&)>&&) const final;
+    void selectAssertionResponse(Vector<Ref<WebCore::AuthenticatorAssertionResponse>>&&, WebAuthenticationSource, CompletionHandler<void(WebCore::AuthenticatorAssertionResponse*)>&&) const final;
     void decidePolicyForLocalAuthenticator(CompletionHandler<void(LocalAuthenticatorPolicy)>&&) const final;
 
     _WKWebAuthenticationPanel *m_panel;
@@ -59,7 +59,7 @@ private:
         bool panelUpdateWebAuthenticationPanel : 1;
         bool panelDismissWebAuthenticationPanelWithResult : 1;
         bool panelRequestPinWithRemainingRetriesCompletionHandler : 1;
-        bool panelSelectAssertionResponseCompletionHandler : 1;
+        bool panelSelectAssertionResponseSourceCompletionHandler : 1;
         bool panelDecidePolicyForLocalAuthenticatorCompletionHandler : 1;
     } m_delegateMethods;
 };
index dbdf5ae..c5aa007 100644 (file)
@@ -48,7 +48,7 @@ WebAuthenticationPanelClient::WebAuthenticationPanelClient(_WKWebAuthenticationP
     m_delegateMethods.panelUpdateWebAuthenticationPanel = [delegate respondsToSelector:@selector(panel:updateWebAuthenticationPanel:)];
     m_delegateMethods.panelDismissWebAuthenticationPanelWithResult = [delegate respondsToSelector:@selector(panel:dismissWebAuthenticationPanelWithResult:)];
     m_delegateMethods.panelRequestPinWithRemainingRetriesCompletionHandler = [delegate respondsToSelector:@selector(panel:requestPINWithRemainingRetries:completionHandler:)];
-    m_delegateMethods.panelSelectAssertionResponseCompletionHandler = [delegate respondsToSelector:@selector(panel:selectAssertionResponse:completionHandler:)];
+    m_delegateMethods.panelSelectAssertionResponseSourceCompletionHandler = [delegate respondsToSelector:@selector(panel:selectAssertionResponse:source:completionHandler:)];
     m_delegateMethods.panelDecidePolicyForLocalAuthenticatorCompletionHandler = [delegate respondsToSelector:@selector(panel:decidePolicyForLocalAuthenticatorWithCompletionHandler:)];
 }
 
@@ -137,18 +137,30 @@ void WebAuthenticationPanelClient::requestPin(uint64_t retries, CompletionHandle
     }).get()];
 }
 
-void WebAuthenticationPanelClient::selectAssertionResponse(Vector<Ref<WebCore::AuthenticatorAssertionResponse>>&& responses, CompletionHandler<void(const WebCore::AuthenticatorAssertionResponse&)>&& completionHandler) const
+static _WKWebAuthenticationSource wkWebAuthenticationSource(WebAuthenticationSource result)
+{
+    switch (result) {
+    case WebAuthenticationSource::Local:
+        return _WKWebAuthenticationSourceLocal;
+    case WebAuthenticationSource::External:
+        return _WKWebAuthenticationSourceExternal;
+    }
+    ASSERT_NOT_REACHED();
+    return _WKWebAuthenticationSourceLocal;
+}
+
+void WebAuthenticationPanelClient::selectAssertionResponse(Vector<Ref<WebCore::AuthenticatorAssertionResponse>>&& responses, WebAuthenticationSource source, CompletionHandler<void(WebCore::AuthenticatorAssertionResponse*)>&& completionHandler) const
 {
     ASSERT(!responses.isEmpty());
 
-    if (!m_delegateMethods.panelSelectAssertionResponseCompletionHandler) {
-        completionHandler(responses[0]);
+    if (!m_delegateMethods.panelSelectAssertionResponseSourceCompletionHandler) {
+        completionHandler(nullptr);
         return;
     }
 
     auto delegate = m_delegate.get();
     if (!delegate) {
-        completionHandler(responses[0]);
+        completionHandler(nullptr);
         return;
     }
 
@@ -157,11 +169,16 @@ void WebAuthenticationPanelClient::selectAssertionResponse(Vector<Ref<WebCore::A
     for (auto& response : responses)
         apiResponses.uncheckedAppend(API::WebAuthenticationAssertionResponse::create(response.copyRef()));
 
-    auto checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(panel:selectAssertionResponse:completionHandler:));
-    [delegate panel:m_panel selectAssertionResponse:wrapper(API::Array::create(WTFMove(apiResponses))) completionHandler:makeBlockPtr([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](_WKWebAuthenticationAssertionResponse *response) mutable {
+    auto checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(panel:selectAssertionResponse:source:completionHandler:));
+    [delegate panel:m_panel selectAssertionResponse:wrapper(API::Array::create(WTFMove(apiResponses))) source:wkWebAuthenticationSource(source) completionHandler:makeBlockPtr([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](_WKWebAuthenticationAssertionResponse *response) mutable {
         if (checker->completionHandlerHasBeenCalled())
             return;
         checker->didCallCompletionHandler();
+
+        if (!response) {
+            completionHandler(nullptr);
+            return;
+        }
         completionHandler(static_cast<API::WebAuthenticationAssertionResponse&>([response _apiObject]).response());
     }).get()];
 }
index 658eebc..cb065a9 100644 (file)
@@ -56,6 +56,11 @@ enum class LocalAuthenticatorPolicy : bool {
     Disallow
 };
 
+enum class WebAuthenticationSource : bool {
+    Local,
+    External
+};
+
 } // namespace WebKit
 
 #endif // ENABLE(WEB_AUTHN)
index 7e04acb..41e8d5a 100644 (file)
@@ -197,11 +197,11 @@ void CtapAuthenticator::continueGetNextAssertionAfterResponseReceived(Vector<uin
 
     if (!m_remainingAssertionResponses) {
         if (auto* observer = this->observer()) {
-            observer->selectAssertionResponse(m_assertionResponses, [this, weakThis = makeWeakPtr(*this)] (const AuthenticatorAssertionResponse& response) {
+            observer->selectAssertionResponse(m_assertionResponses, WebAuthenticationSource::External, [this, weakThis = makeWeakPtr(*this)] (AuthenticatorAssertionResponse* response) {
                 ASSERT(RunLoop::isMain());
                 if (!weakThis)
                     return;
-                auto returnResponse = m_assertionResponses.take(const_cast<AuthenticatorAssertionResponse*>(&response));
+                auto returnResponse = m_assertionResponses.take(response);
                 if (!returnResponse)
                     return;
                 receiveRespond(WTFMove(*returnResponse));
index 0761c97..d4e6b34 100644 (file)
@@ -1,3 +1,19 @@
+2020-03-05  Jiewen Tan  <jiewen_tan@apple.com>
+
+        [WebAuthn] Implement SPI -[_WKWebAuthenticationPanelDelegate panel:selectAssertionResponse:source:completionHandler:]
+        https://bugs.webkit.org/show_bug.cgi?id=208626
+        <rdar://problem/60074148>
+
+        Reviewed by Brent Fulgham.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm:
+        (-[TestWebAuthenticationPanelDelegate panel:selectAssertionResponse:source:completionHandler:]):
+        (TestWebKitAPI::TEST):
+        (-[TestWebAuthenticationPanelDelegate panel:selectAssertionResponse:completionHandler:]): Deleted.
+        * TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-hid-multiple-accounts.html:
+        * TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-la.html: Added.
+
 2020-03-05  Antoine Quint  <graouts@apple.com>
 
         Page-specific UserStyleSheets should wait until the initial empty document has been removed to be injected
index 962dbee..618b2bf 100644 (file)
                571F7FD01F2961FB00946648 /* IndexedDBStructuredCloneBackwardCompatibility.sqlite3-wal in Copy Resources */ = {isa = PBXBuildFile; fileRef = 571F7FCF1F2961E100946648 /* IndexedDBStructuredCloneBackwardCompatibility.sqlite3-wal */; };
                572B403421769A88000AD43E /* CtapRequestTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 572B403321769A88000AD43E /* CtapRequestTest.cpp */; };
                572B404421781B43000AD43E /* CtapResponseTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 572B404321781B42000AD43E /* CtapResponseTest.cpp */; };
+               572CEF71240F874700C412A2 /* web-authentication-get-assertion-la.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 572CEF70240F86AE00C412A2 /* web-authentication-get-assertion-la.html */; };
                57303BC9200824D300355965 /* CBORValueTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57303BAC2006C56000355965 /* CBORValueTest.cpp */; };
                57303BCA20082C0100355965 /* CBORWriterTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57303BAB2006C55400355965 /* CBORWriterTest.cpp */; };
                57303BCB2008376500355965 /* CBORReaderTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57303BC220071E2200355965 /* CBORReaderTest.cpp */; };
                                578DA44E23ECD28B00246010 /* web-authentication-get-assertion-hid-pin-invalid-error-retry.html in Copy Resources */,
                                570D26FC23C3F87000D5CF67 /* web-authentication-get-assertion-hid-pin.html in Copy Resources */,
                                57663DEC234F1F9300E85E09 /* web-authentication-get-assertion-hid.html in Copy Resources */,
+                               572CEF71240F874700C412A2 /* web-authentication-get-assertion-la.html in Copy Resources */,
                                579833922368FA37008E5547 /* web-authentication-get-assertion-nfc-multiple-tags.html in Copy Resources */,
                                57663DEA234EA66D00E85E09 /* web-authentication-get-assertion-nfc.html in Copy Resources */,
                                577454D22359BB01008E1ED7 /* web-authentication-get-assertion-u2f-no-credentials.html in Copy Resources */,
                572B403321769A88000AD43E /* CtapRequestTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CtapRequestTest.cpp; sourceTree = "<group>"; };
                572B40352176A029000AD43E /* FidoTestData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FidoTestData.h; sourceTree = "<group>"; };
                572B404321781B42000AD43E /* CtapResponseTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CtapResponseTest.cpp; sourceTree = "<group>"; };
+               572CEF70240F86AE00C412A2 /* web-authentication-get-assertion-la.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "web-authentication-get-assertion-la.html"; sourceTree = "<group>"; };
                57303BAB2006C55400355965 /* CBORWriterTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CBORWriterTest.cpp; sourceTree = "<group>"; };
                57303BAC2006C56000355965 /* CBORValueTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CBORValueTest.cpp; sourceTree = "<group>"; };
                57303BC220071E2200355965 /* CBORReaderTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CBORReaderTest.cpp; sourceTree = "<group>"; };
                                578DA44D23ECD26100246010 /* web-authentication-get-assertion-hid-pin-invalid-error-retry.html */,
                                570D26FB23C3F86500D5CF67 /* web-authentication-get-assertion-hid-pin.html */,
                                57663DEB234F1F8000E85E09 /* web-authentication-get-assertion-hid.html */,
+                               572CEF70240F86AE00C412A2 /* web-authentication-get-assertion-la.html */,
                                5798337B235EB65C008E5547 /* web-authentication-get-assertion-nfc-multiple-tags.html */,
                                57663DE9234EA60B00E85E09 /* web-authentication-get-assertion-nfc.html */,
                                577454D12359BAD5008E1ED7 /* web-authentication-get-assertion-u2f-no-credentials.html */,
index c067420..749c97f 100644 (file)
@@ -132,13 +132,14 @@ static String testUserhandleBase64 = "AAECAwQFBgcICQ==";
     completionHandler(webAuthenticationPanelPin);
 }
 
-- (void)panel:(_WKWebAuthenticationPanel *)panel selectAssertionResponse:(NSArray < _WKWebAuthenticationAssertionResponse *> *)responses completionHandler:(void (^)(_WKWebAuthenticationAssertionResponse *))completionHandler
+- (void)panel:(_WKWebAuthenticationPanel *)panel selectAssertionResponse:(NSArray < _WKWebAuthenticationAssertionResponse *> *)responses source:(_WKWebAuthenticationSource)source completionHandler:(void (^)(_WKWebAuthenticationAssertionResponse *))completionHandler
 {
     if (responses.count == 1) {
         completionHandler(responses[0]);
         return;
     }
 
+    EXPECT_EQ(source, _WKWebAuthenticationSourceExternal);
     EXPECT_EQ(responses.count, 2ul);
     for (_WKWebAuthenticationAssertionResponse *response in responses) {
         EXPECT_TRUE([response.name isEqual:@"johnpsmith@example.com"] || [response.name isEqual:@""]);
@@ -1159,7 +1160,7 @@ TEST(WebAuthenticationPanel, MultipleAccountsNullDelegate)
     [webView setUIDelegate:delegate.get()];
 
     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
-    [webView waitForMessage:@"Succeeded!"];
+    [webView waitForMessage:@"Operation timed out."];
 }
 
 TEST(WebAuthenticationPanel, MultipleAccounts)
@@ -1291,6 +1292,26 @@ TEST(WebAuthenticationPanel, LAMakeCredentialAllowLocalAuthenticator)
     cleanUpKeychain("");
 }
 
+TEST(WebAuthenticationPanel, LAGetAssertion)
+{
+    reset();
+    RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-la" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+
+    auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
+    [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
+    [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationLocalAuthenticatorExperimentalFeature()];
+
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
+    auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
+    [webView setUIDelegate:delegate.get()];
+
+    ASSERT_TRUE(addKeyToKeychain(testES256PrivateKeyBase64, "", testUserhandleBase64));
+    [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
+    [webView waitForMessage:@"Succeeded!"];
+    checkPanel([delegate panel], @"", @[adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportUSB]).get(), adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportInternal]).get()], _WKWebAuthenticationTypeGet);
+    cleanUpKeychain("");
+}
+
 #endif // USE(APPLE_INTERNAL_SDK) || PLATFORM(IOS)
 
 } // namespace TestWebKitAPI
index d637e42..f1c7ac1 100644 (file)
@@ -41,7 +41,7 @@
     const options = {
         publicKey: {
             challenge: new Uint8Array(16),
-            timeout: 1000
+            timeout: 100
         }
     };
 
diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-la.html b/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-la.html
new file mode 100644 (file)
index 0000000..efa3c5b
--- /dev/null
@@ -0,0 +1,22 @@
+<input type="text" id="input">
+<script>
+    if (window.internals) {
+        internals.setMockWebAuthenticationConfiguration({ local: { acceptAuthentication: true, acceptAttestation: false } });
+        internals.withUserGesture(() => { input.focus(); });
+    }
+
+    const options = {
+        publicKey: {
+            challenge: new Uint8Array(16),
+            timeout: 100
+        }
+    };
+
+    navigator.credentials.get(options).then(credential => {
+        // console.log("Succeeded!");
+        window.webkit.messageHandlers.testHandler.postMessage("Succeeded!");
+    }, error => {
+        // console.log(error.message);
+        window.webkit.messageHandlers.testHandler.postMessage(error.message);
+    });
+</script>