Diff
Modified: trunk/Source/WebKit/ChangeLog (272183 => 272184)
--- trunk/Source/WebKit/ChangeLog 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Source/WebKit/ChangeLog 2021-02-02 02:49:59 UTC (rev 272184)
@@ -1,3 +1,70 @@
+2021-02-01 Jiewen Tan <[email protected]>
+
+ [WebAuthn] Optimize _WKWebAuthenticationPanelDelegate for native API
+ https://bugs.webkit.org/show_bug.cgi?id=221125
+ <rdar://problem/71509141>
+
+ Reviewed by Brent Fulgham.
+
+ This patch mainly does the following few things:
+ 1. It connects the new SPI with the existing mock testing infrastructure such that we can mock test it.
+ 2. It adds a new mode in AuthenticatorManager to connect it to the new _WKWebAuthenticationPanelDelegate object.
+ 3. It adss a new SPI to _WKWebAuthenticationPanelDelegate: -[panel:requestLAContextForUserVerificationWithCompletionHandler:],
+ and adds a new method within _WKWebAuthenticationAssertionResponse to accept an LAContext from the caller to unlock
+ the keychain.
+ 4. It enables -[_WKWebAuthenticationPanel cancel] to use the new cancel method.
+
+ Covered by API tests.
+
+ * UIProcess/API/APIWebAuthenticationAssertionResponse.h:
+ Accepts a LAContext object.
+
+ * UIProcess/API/APIWebAuthenticationPanel.cpp:
+ (API::WebAuthenticationPanel::WebAuthenticationPanel):
+ (API::WebAuthenticationPanel::handleRequest):
+ (API::WebAuthenticationPanel::cancel const):
+ (API::WebAuthenticationPanel::setMockConfiguration):
+ * UIProcess/API/APIWebAuthenticationPanel.h:
+ * UIProcess/API/APIWebAuthenticationPanelClient.h:
+ (API::WebAuthenticationPanelClient::requestLAContextForUserVerification const):
+ Adds new SPI and mocking.
+
+ * UIProcess/API/Cocoa/_WKWebAuthenticationAssertionResponse.h:
+ * UIProcess/API/Cocoa/_WKWebAuthenticationAssertionResponse.mm:
+ (-[_WKWebAuthenticationAssertionResponse setLAContext:]):
+ Accepts a LAContext object.
+
+ * UIProcess/API/Cocoa/_WKWebAuthenticationPanel.h:
+ * UIProcess/API/Cocoa/_WKWebAuthenticationPanel.mm:
+ (-[_WKWebAuthenticationPanel setMockConfiguration:]):
+ * UIProcess/API/Cocoa/_WKWebAuthenticationPanelForTesting.h:
+ Adds new SPI and mocking.
+
+ * UIProcess/WebAuthentication/AuthenticatorManager.cpp:
+ (WebKit::AuthenticatorManager::handleRequest):
+ (WebKit::AuthenticatorManager::enableModernWebAuthentication):
+ (WebKit::AuthenticatorManager::enableNativeSupport):
+ (WebKit::AuthenticatorManager::authenticatorAdded):
+ (WebKit::AuthenticatorManager::requestLAContextForUserVerification):
+ (WebKit::AuthenticatorManager::runPresenter):
+ (WebKit::AuthenticatorManager::dispatchPanelClientCall const):
+ * UIProcess/WebAuthentication/AuthenticatorManager.h:
+ Adds a new mode to power the native API.
+
+ * UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.h:
+ * UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm:
+ (WebKit::WebAuthenticationPanelClient::WebAuthenticationPanelClient):
+ (WebKit::WebAuthenticationPanelClient::requestLAContextForUserVerification const):
+ Accepts a LAContext object.
+
+ * UIProcess/WebAuthentication/Mock/MockLocalConnection.h:
+ * UIProcess/WebAuthentication/Mock/MockLocalConnection.mm:
+ (WebKit::MockLocalConnection::verifyUser):
+ Adds new mocking functions.
+
+ * UIProcess/WebAuthentication/WebAuthenticationRequestData.h:
+ Adds the new weak panel.
+
2021-02-01 Michael Catanzaro <[email protected]>
[WPE][GTK] flatpak-spawn subsandbox clears environment variables, breaks EphyPermissionsManager
Modified: trunk/Source/WebKit/UIProcess/API/APIWebAuthenticationAssertionResponse.h (272183 => 272184)
--- trunk/Source/WebKit/UIProcess/API/APIWebAuthenticationAssertionResponse.h 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Source/WebKit/UIProcess/API/APIWebAuthenticationAssertionResponse.h 2021-02-02 02:49:59 UTC (rev 272184)
@@ -43,6 +43,8 @@
const WTF::String& displayName() const { return m_response->displayName(); }
RefPtr<Data> userHandle() const;
+ void setLAContext(LAContext *context) { m_response->setLAContext(context); }
+
WebCore::AuthenticatorAssertionResponse* response() { return m_response.ptr(); }
private:
Modified: trunk/Source/WebKit/UIProcess/API/APIWebAuthenticationPanel.cpp (272183 => 272184)
--- trunk/Source/WebKit/UIProcess/API/APIWebAuthenticationPanel.cpp 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Source/WebKit/UIProcess/API/APIWebAuthenticationPanel.cpp 2021-02-02 02:49:59 UTC (rev 272184)
@@ -30,6 +30,7 @@
#include "APIWebAuthenticationPanelClient.h"
#include "AuthenticatorManager.h"
+#include "MockAuthenticatorManager.h"
#include <WebCore/WebAuthenticationConstants.h>
namespace API {
@@ -45,6 +46,7 @@
: m_manager(makeUnique<AuthenticatorManager>())
, m_client(makeUniqueRef<WebAuthenticationPanelClient>())
{
+ m_manager->enableNativeSupport();
}
WebAuthenticationPanel::WebAuthenticationPanel(const AuthenticatorManager& manager, const WTF::String& rpId, const TransportSet& transports, ClientDataType type)
@@ -68,15 +70,32 @@
void WebAuthenticationPanel::handleRequest(WebAuthenticationRequestData&& request, Callback&& callback)
{
ASSERT(m_manager);
+ request.weakPanel = makeWeakPtr(*this);
m_manager->handleRequest(WTFMove(request), WTFMove(callback));
}
void WebAuthenticationPanel::cancel() const
{
- if (m_weakManager)
+ if (m_weakManager) {
m_weakManager->cancelRequest(*this);
+ return;
+ }
+
+ m_manager->cancel();
}
+void WebAuthenticationPanel::setMockConfiguration(WebCore::MockWebAuthenticationConfiguration&& configuration)
+{
+ ASSERT(m_manager);
+
+ if (!m_manager->isMock()) {
+ m_manager = makeUnique<MockAuthenticatorManager>(WTFMove(configuration));
+ m_manager->enableNativeSupport();
+ return;
+ }
+ static_cast<MockAuthenticatorManager*>(m_manager.get())->setTestConfiguration(WTFMove(configuration));
+}
+
void WebAuthenticationPanel::setClient(UniqueRef<WebAuthenticationPanelClient>&& client)
{
m_client = WTFMove(client);
Modified: trunk/Source/WebKit/UIProcess/API/APIWebAuthenticationPanel.h (272183 => 272184)
--- trunk/Source/WebKit/UIProcess/API/APIWebAuthenticationPanel.h 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Source/WebKit/UIProcess/API/APIWebAuthenticationPanel.h 2021-02-02 02:49:59 UTC (rev 272184)
@@ -39,6 +39,7 @@
class AuthenticatorResponse;
struct ExceptionData;
+struct MockWebAuthenticationConfiguration;
}
namespace WebKit {
@@ -61,6 +62,7 @@
void handleRequest(WebKit::WebAuthenticationRequestData&&, Callback&&);
void cancel() const;
+ void setMockConfiguration(WebCore::MockWebAuthenticationConfiguration&&);
const WebAuthenticationPanelClient& client() const { return m_client.get(); }
void setClient(UniqueRef<WebAuthenticationPanelClient>&&);
Modified: trunk/Source/WebKit/UIProcess/API/APIWebAuthenticationPanelClient.h (272183 => 272184)
--- trunk/Source/WebKit/UIProcess/API/APIWebAuthenticationPanelClient.h 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Source/WebKit/UIProcess/API/APIWebAuthenticationPanelClient.h 2021-02-02 02:49:59 UTC (rev 272184)
@@ -52,6 +52,7 @@
virtual void requestPin(uint64_t, CompletionHandler<void(const WTF::String&)>&& completionHandler) const { completionHandler(WTF::String()); }
virtual void selectAssertionResponse(Vector<Ref<WebCore::AuthenticatorAssertionResponse>>&&, WebKit::WebAuthenticationSource, CompletionHandler<void(WebCore::AuthenticatorAssertionResponse*)>&& completionHandler) const { completionHandler(nullptr); }
virtual void decidePolicyForLocalAuthenticator(CompletionHandler<void(WebKit::LocalAuthenticatorPolicy)>&& completionHandler) const { completionHandler(WebKit::LocalAuthenticatorPolicy::Disallow); }
+ virtual void requestLAContextForUserVerification(CompletionHandler<void(LAContext *)>&& completionHandler) const { completionHandler(nullptr); }
};
} // namespace API
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationAssertionResponse.h (272183 => 272184)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationAssertionResponse.h 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationAssertionResponse.h 2021-02-02 02:49:59 UTC (rev 272184)
@@ -28,6 +28,8 @@
NS_ASSUME_NONNULL_BEGIN
+@class LAContext;
+
WK_CLASS_AVAILABLE(macos(11.0), ios(14.0))
@interface _WKWebAuthenticationAssertionResponse : NSObject
@@ -35,6 +37,8 @@
@property (nonatomic, readonly, copy) NSString *displayName;
@property (nonatomic, readonly, copy) NSData *userHandle;
+- (void)setLAContext:(LAContext *)context WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+
@end
NS_ASSUME_NONNULL_END
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationAssertionResponse.mm (272183 => 272184)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationAssertionResponse.mm 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationAssertionResponse.mm 2021-02-02 02:49:59 UTC (rev 272184)
@@ -54,6 +54,16 @@
return wrapper(_response->userHandle());
}
+#endif // ENABLE(WEB_AUTHN)
+
+- (void)setLAContext:(LAContext *)context
+{
+#if ENABLE(WEB_AUTHN)
+ _response->setLAContext(context);
+#endif
+}
+
+#if ENABLE(WEB_AUTHN)
#pragma mark WKObject protocol implementation
- (API::Object&)_apiObject
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationPanel.h (272183 => 272184)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationPanel.h 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationPanel.h 2021-02-02 02:49:59 UTC (rev 272184)
@@ -34,6 +34,7 @@
@class _WKPublicKeyCredentialRequestOptions;
@class _WKWebAuthenticationAssertionResponse;
@class _WKWebAuthenticationPanel;
+@class LAContext;
typedef NS_ENUM(NSInteger, _WKWebAuthenticationPanelResult) {
_WKWebAuthenticationPanelResultUnavailable,
@@ -78,17 +79,18 @@
_WKWebAuthenticationSourceExternal,
} WK_API_AVAILABLE(macos(11.0), ios(14.0));
-// FIXME: <rdar://problem/71509141> Optimize the delegate for the AuthenticationService.framework.
@protocol _WKWebAuthenticationPanelDelegate <NSObject>
@optional
-- (void)panel:(_WKWebAuthenticationPanel *)panel updateWebAuthenticationPanel:(_WKWebAuthenticationPanelUpdate)update WK_API_AVAILABLE(macos(10.15.4), ios(13.4));
-- (void)panel:(_WKWebAuthenticationPanel *)panel dismissWebAuthenticationPanelWithResult:(_WKWebAuthenticationResult)result WK_API_AVAILABLE(macos(10.15.4), ios(13.4));
-- (void)panel:(_WKWebAuthenticationPanel *)panel requestPINWithRemainingRetries:(NSUInteger)retries completionHandler:(void (^)(NSString *))completionHandler WK_API_AVAILABLE(macos(10.15.4), ios(13.4));
+- (void)panel:(_WKWebAuthenticationPanel *)panel updateWebAuthenticationPanel:(_WKWebAuthenticationPanelUpdate)update WK_API_AVAILABLE(macos(11.0), ios(14.0));
+- (void)panel:(_WKWebAuthenticationPanel *)panel requestPINWithRemainingRetries:(NSUInteger)retries completionHandler:(void (^)(NSString *))completionHandler WK_API_AVAILABLE(macos(11.0), ios(14.0));
- (void)panel:(_WKWebAuthenticationPanel *)panel selectAssertionResponse:(NSArray < _WKWebAuthenticationAssertionResponse *> *)responses source:(_WKWebAuthenticationSource)source completionHandler:(void (^)(_WKWebAuthenticationAssertionResponse *))completionHandler WK_API_AVAILABLE(macos(11.0), ios(14.0));
+- (void)panel:(_WKWebAuthenticationPanel *)panel requestLAContextForUserVerificationWithCompletionHandler:(void (^)(LAContext *context))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+
+// FIXME: <rdar://problem/71509848> Deprecate the following delegates.
- (void)panel:(_WKWebAuthenticationPanel *)panel decidePolicyForLocalAuthenticatorWithCompletionHandler:(void (^)(_WKLocalAuthenticatorPolicy policy))completionHandler WK_API_AVAILABLE(macos(11.0), ios(14.0));
-
+- (void)panel:(_WKWebAuthenticationPanel *)panel dismissWebAuthenticationPanelWithResult:(_WKWebAuthenticationResult)result WK_API_AVAILABLE(macos(11.0), ios(14.0));
@end
WK_CLASS_AVAILABLE(macos(10.15.4), ios(13.4))
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationPanel.mm (272183 => 272184)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationPanel.mm 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationPanel.mm 2021-02-02 02:49:59 UTC (rev 272184)
@@ -44,6 +44,7 @@
#import "_WKPublicKeyCredentialUserEntity.h"
#import <WebCore/AuthenticatorResponse.h>
#import <WebCore/AuthenticatorResponseData.h>
+#import <WebCore/MockWebAuthenticationConfiguration.h>
#import <WebCore/PublicKeyCredentialCreationOptions.h>
#import <WebCore/PublicKeyCredentialRequestOptions.h>
#import <WebCore/WebAuthenticationConstants.h>
@@ -347,7 +348,7 @@
handler(nil, [NSError errorWithDomain:WKErrorDomain code:WKErrorUnknown userInfo:nil]);
});
};
- _panel->handleRequest({ vectorFromNSData(hash), [_WKWebAuthenticationPanel convertToCoreCreationOptionsWithOptions:options], nullptr, WebKit::WebAuthenticationPanelResult::Unavailable, nullptr, WTF::nullopt, { }, true, String() }, WTFMove(callback));
+ _panel->handleRequest({ vectorFromNSData(hash), [_WKWebAuthenticationPanel convertToCoreCreationOptionsWithOptions:options], nullptr, WebKit::WebAuthenticationPanelResult::Unavailable, nullptr, WTF::nullopt, { }, true, String(), nullptr }, WTFMove(callback));
#endif
}
@@ -394,7 +395,7 @@
handler(nil, [NSError errorWithDomain:WKErrorDomain code:WKErrorUnknown userInfo:nil]);
});
};
- _panel->handleRequest({ vectorFromNSData(hash), [_WKWebAuthenticationPanel convertToCoreRequestOptionsWithOptions:options], nullptr, WebKit::WebAuthenticationPanelResult::Unavailable, nullptr, WTF::nullopt, { }, true, String() }, WTFMove(callback));
+ _panel->handleRequest({ vectorFromNSData(hash), [_WKWebAuthenticationPanel convertToCoreRequestOptionsWithOptions:options], nullptr, WebKit::WebAuthenticationPanelResult::Unavailable, nullptr, WTF::nullopt, { }, true, String(), nullptr }, WTFMove(callback));
#endif
}
@@ -407,7 +408,22 @@
#endif
}
+- (void)setMockConfiguration:(NSDictionary *)configuration
+{
#if ENABLE(WEB_AUTHN)
+ WebCore::MockWebAuthenticationConfiguration::LocalConfiguration localConfiguration;
+ localConfiguration.userVerification = WebCore::MockWebAuthenticationConfiguration::UserVerification::Yes;
+ if (configuration[@"privateKeyBase64"])
+ localConfiguration.privateKeyBase64 = configuration[@"privateKeyBase64"];
+
+ WebCore::MockWebAuthenticationConfiguration mockConfiguration;
+ mockConfiguration.local = WTFMove(localConfiguration);
+
+ _panel->setMockConfiguration(WTFMove(mockConfiguration));
+#endif
+}
+
+#if ENABLE(WEB_AUTHN)
#pragma mark WKObject protocol implementation
- (API::Object&)_apiObject
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationPanelForTesting.h (272183 => 272184)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationPanelForTesting.h 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationPanelForTesting.h 2021-02-02 02:49:59 UTC (rev 272184)
@@ -35,8 +35,10 @@
WK_CLASS_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA))
@interface _WKWebAuthenticationPanel (WKTesting)
-// FIXME: <rdar://problem/71509714> Introduces mock testing.
+ (WebCore::PublicKeyCredentialCreationOptions)convertToCoreCreationOptionsWithOptions:(_WKPublicKeyCredentialCreationOptions *)options WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+ (WebCore::PublicKeyCredentialRequestOptions)convertToCoreRequestOptionsWithOptions:(_WKPublicKeyCredentialRequestOptions *)options WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+// For details of configuration, refer to MockWebAuthenticationConfiguration.h.
+@property (nonatomic, copy) NSDictionary *mockConfiguration;
+
@end
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp (272183 => 272184)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp 2021-02-02 02:49:59 UTC (rev 272184)
@@ -165,10 +165,9 @@
// 2. Ask clients to show appropriate UI if any and then start the request.
initTimeOutTimer();
- // FIXME<rdar://problem/70822834>: The m_webAuthenticationModernEnabled is used to determine
- // whether or not we are in the UIProcess.
+ // FIXME<rdar://problem/70822834>: The m_mode is used to determine whether or not we are in the UIProcess.
// If so, continue to the old route. Otherwise, use the modern WebAuthn process way.
- if (!m_webAuthenticationModernEnabled) {
+ if (m_mode == Mode::Compatible) {
runPanel();
return;
}
@@ -209,9 +208,14 @@
void AuthenticatorManager::enableModernWebAuthentication()
{
- m_webAuthenticationModernEnabled = true;
+ m_mode = Mode::Modern;
}
+void AuthenticatorManager::enableNativeSupport()
+{
+ m_mode = Mode::Native;
+}
+
void AuthenticatorManager::clearStateAsync()
{
RunLoop::main().dispatch([weakThis = makeWeakPtr(*this)] {
@@ -236,7 +240,7 @@
ASSERT(RunLoop::isMain());
authenticator->setObserver(*this);
authenticator->handleRequest(m_pendingRequestData);
- authenticator->setWebAuthenticationModernEnabled(m_webAuthenticationModernEnabled);
+ authenticator->setWebAuthenticationModernEnabled(m_mode != Mode::Compatible);
auto addResult = m_authenticators.add(WTFMove(authenticator));
ASSERT_UNUSED(addResult, addResult.isNewEntry);
}
@@ -354,12 +358,14 @@
void AuthenticatorManager::requestLAContextForUserVerification(CompletionHandler<void(LAContext *)>&& completionHandler)
{
- if (!m_presenter) {
- completionHandler(nullptr);
+ if (m_presenter) {
+ m_presenter->requestLAContextForUserVerification(WTFMove(completionHandler));
return;
}
- m_presenter->requestLAContextForUserVerification(WTFMove(completionHandler));
+ dispatchPanelClientCall([completionHandler = WTFMove(completionHandler)] (const API::WebAuthenticationPanel& panel) mutable {
+ panel.client().requestLAContextForUserVerification(WTFMove(completionHandler));
+ });
}
void AuthenticatorManager::cancelRequest()
@@ -444,10 +450,14 @@
void AuthenticatorManager::runPresenter()
{
// Get available transports and start discovering authenticators on them.
- auto& options = m_pendingRequestData.options;
auto transports = getTransports();
startDiscovery(transports);
+ // For native API support, we skip the UI part. The native API will handle that.
+ if (m_mode == Mode::Native)
+ return;
+
+ auto& options = m_pendingRequestData.options;
m_presenter = makeUnique<AuthenticatorPresenterCoordinator>(*this, getRpId(options), transports, getClientDataType(options));
}
@@ -488,15 +498,19 @@
void AuthenticatorManager::dispatchPanelClientCall(Function<void(const API::WebAuthenticationPanel&)>&& call) const
{
- if (auto* panel = m_pendingRequestData.panel.get()) {
- // Call delegates in the next run loop to prevent clients' reentrance that would potentially modify the state
- // of the current run loop in unexpected ways.
- RunLoop::main().dispatch([weakPanel = makeWeakPtr(*panel), call = WTFMove(call)] () {
- if (!weakPanel)
- return;
- call(*weakPanel);
- });
- }
+ auto weakPanel = m_pendingRequestData.weakPanel;
+ if (!weakPanel)
+ weakPanel = makeWeakPtr(*m_pendingRequestData.panel.get());
+ if (!weakPanel)
+ return;
+
+ // Call delegates in the next run loop to prevent clients' reentrance that would potentially modify the state
+ // of the current run loop in unexpected ways.
+ RunLoop::main().dispatch([weakPanel = WTFMove(weakPanel), call = WTFMove(call)] () {
+ if (!weakPanel)
+ return;
+ call(*weakPanel);
+ });
}
} // namespace WebKit
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h (272183 => 272184)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h 2021-02-02 02:49:59 UTC (rev 272184)
@@ -71,6 +71,7 @@
virtual bool isMock() const { return false; }
void enableModernWebAuthentication();
+ void enableNativeSupport();
protected:
RunLoop::Timer<AuthenticatorManager>& requestTimeOutTimer() { return m_requestTimeOutTimer; }
@@ -79,6 +80,12 @@
void invokePendingCompletionHandler(Respond&&);
private:
+ enum class Mode {
+ Compatible,
+ Modern,
+ Native,
+ };
+
// AuthenticatorTransportService::Observer
void authenticatorAdded(Ref<Authenticator>&&) final;
void serviceStatusUpdated(WebAuthenticationStatus) final;
@@ -117,7 +124,7 @@
Vector<UniqueRef<AuthenticatorTransportService>> m_services;
HashSet<Ref<Authenticator>> m_authenticators;
- bool m_webAuthenticationModernEnabled { false };
+ Mode m_mode { Mode::Compatible };
};
} // namespace WebKit
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.h (272183 => 272184)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.h 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.h 2021-02-02 02:49:59 UTC (rev 272184)
@@ -52,6 +52,7 @@
void requestPin(uint64_t, CompletionHandler<void(const WTF::String&)>&&) const final;
void selectAssertionResponse(Vector<Ref<WebCore::AuthenticatorAssertionResponse>>&&, WebAuthenticationSource, CompletionHandler<void(WebCore::AuthenticatorAssertionResponse*)>&&) const final;
void decidePolicyForLocalAuthenticator(CompletionHandler<void(LocalAuthenticatorPolicy)>&&) const final;
+ void requestLAContextForUserVerification(CompletionHandler<void(LAContext *)>&&) const final;
_WKWebAuthenticationPanel *m_panel;
WeakObjCPtr<id <_WKWebAuthenticationPanelDelegate> > m_delegate;
@@ -62,6 +63,7 @@
bool panelRequestPinWithRemainingRetriesCompletionHandler : 1;
bool panelSelectAssertionResponseSourceCompletionHandler : 1;
bool panelDecidePolicyForLocalAuthenticatorCompletionHandler : 1;
+ bool panelRequestLAContextForUserVerificationCompletionHandler : 1;
} m_delegateMethods;
};
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm (272183 => 272184)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm 2021-02-02 02:49:59 UTC (rev 272184)
@@ -50,6 +50,7 @@
m_delegateMethods.panelRequestPinWithRemainingRetriesCompletionHandler = [delegate respondsToSelector:@selector(panel:requestPINWithRemainingRetries:completionHandler:)];
m_delegateMethods.panelSelectAssertionResponseSourceCompletionHandler = [delegate respondsToSelector:@selector(panel:selectAssertionResponse:source:completionHandler:)];
m_delegateMethods.panelDecidePolicyForLocalAuthenticatorCompletionHandler = [delegate respondsToSelector:@selector(panel:decidePolicyForLocalAuthenticatorWithCompletionHandler:)];
+ m_delegateMethods.panelRequestLAContextForUserVerificationCompletionHandler = [delegate respondsToSelector:@selector(panel:requestLAContextForUserVerificationWithCompletionHandler:)];
}
RetainPtr<id <_WKWebAuthenticationPanelDelegate> > WebAuthenticationPanelClient::delegate()
@@ -217,6 +218,28 @@
}).get()];
}
+void WebAuthenticationPanelClient::requestLAContextForUserVerification(CompletionHandler<void(LAContext *)>&& completionHandler) const
+{
+ if (!m_delegateMethods.panelRequestLAContextForUserVerificationCompletionHandler) {
+ completionHandler(nullptr);
+ return;
+ }
+
+ auto delegate = m_delegate.get();
+ if (!delegate) {
+ completionHandler(nullptr);
+ return;
+ }
+
+ auto checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(panel:requestLAContextForUserVerificationWithCompletionHandler:));
+ [delegate panel:m_panel requestLAContextForUserVerificationWithCompletionHandler:makeBlockPtr([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](LAContext *context) mutable {
+ if (checker->completionHandlerHasBeenCalled())
+ return;
+ checker->didCallCompletionHandler();
+ completionHandler(context);
+ }).get()];
+}
+
} // namespace WebKit
#endif // ENABLE(WEB_AUTHN)
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.h (272183 => 272184)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.h 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.h 2021-02-02 02:49:59 UTC (rev 272184)
@@ -38,6 +38,7 @@
private:
void verifyUser(const String&, WebCore::ClientDataType, SecAccessControlRef, UserVerificationCallback&&) final;
+ void verifyUser(SecAccessControlRef, LAContext *, CompletionHandler<void(UserVerification)>&&) final;
RetainPtr<SecKeyRef> createCredentialPrivateKey(LAContext *, SecAccessControlRef, const String& secAttrLabel, NSData *secAttrApplicationTag) const final;
void getAttestation(SecKeyRef, NSData *authData, NSData *hash, AttestationCallback&&) const final;
void filterResponses(Vector<Ref<WebCore::AuthenticatorAssertionResponse>>&) const final;
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.mm (272183 => 272184)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.mm 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.mm 2021-02-02 02:49:59 UTC (rev 272184)
@@ -67,6 +67,27 @@
});
}
+void MockLocalConnection::verifyUser(SecAccessControlRef, LAContext *, CompletionHandler<void(UserVerification)>&& callback)
+{
+ // Mock async operations.
+ RunLoop::main().dispatch([configuration = m_configuration, callback = WTFMove(callback)]() mutable {
+ ASSERT(configuration.local);
+
+ UserVerification userVerification = UserVerification::No;
+ switch (configuration.local->userVerification) {
+ case MockWebAuthenticationConfiguration::UserVerification::No:
+ break;
+ case MockWebAuthenticationConfiguration::UserVerification::Yes:
+ userVerification = UserVerification::Yes;
+ break;
+ case MockWebAuthenticationConfiguration::UserVerification::Cancel:
+ userVerification = UserVerification::Cancel;
+ }
+
+ callback(userVerification);
+ });
+}
+
RetainPtr<SecKeyRef> MockLocalConnection::createCredentialPrivateKey(LAContext *, SecAccessControlRef, const String& secAttrLabel, NSData *secAttrApplicationTag) const
{
ASSERT(m_configuration.local);
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticationRequestData.h (272183 => 272184)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticationRequestData.h 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticationRequestData.h 2021-02-02 02:49:59 UTC (rev 272184)
@@ -55,6 +55,7 @@
bool processingUserGesture;
String cachedPin; // Only used to improve NFC Client PIN experience.
+ WeakPtr<API::WebAuthenticationPanel> weakPanel;
};
WebCore::ClientDataType getClientDataType(const Variant<WebCore::PublicKeyCredentialCreationOptions, WebCore::PublicKeyCredentialRequestOptions>&);
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.cpp (272183 => 272184)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.cpp 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.cpp 2021-02-02 02:49:59 UTC (rev 272184)
@@ -57,12 +57,12 @@
void WebAuthenticatorCoordinatorProxy::makeCredential(FrameIdentifier frameId, FrameInfoData&& frameInfo, Vector<uint8_t>&& hash, PublicKeyCredentialCreationOptions&& options, bool processingUserGesture, RequestCompletionHandler&& handler)
{
- handleRequest({ WTFMove(hash), WTFMove(options), makeWeakPtr(m_webPageProxy), WebAuthenticationPanelResult::Unavailable, nullptr, GlobalFrameIdentifier { m_webPageProxy.webPageID(), frameId }, WTFMove(frameInfo), processingUserGesture, String() }, WTFMove(handler));
+ handleRequest({ WTFMove(hash), WTFMove(options), makeWeakPtr(m_webPageProxy), WebAuthenticationPanelResult::Unavailable, nullptr, GlobalFrameIdentifier { m_webPageProxy.webPageID(), frameId }, WTFMove(frameInfo), processingUserGesture, String(), nullptr }, WTFMove(handler));
}
void WebAuthenticatorCoordinatorProxy::getAssertion(FrameIdentifier frameId, FrameInfoData&& frameInfo, Vector<uint8_t>&& hash, PublicKeyCredentialRequestOptions&& options, bool processingUserGesture, RequestCompletionHandler&& handler)
{
- handleRequest({ WTFMove(hash), WTFMove(options), makeWeakPtr(m_webPageProxy), WebAuthenticationPanelResult::Unavailable, nullptr, GlobalFrameIdentifier { m_webPageProxy.webPageID(), frameId }, WTFMove(frameInfo), processingUserGesture, String() }, WTFMove(handler));
+ handleRequest({ WTFMove(hash), WTFMove(options), makeWeakPtr(m_webPageProxy), WebAuthenticationPanelResult::Unavailable, nullptr, GlobalFrameIdentifier { m_webPageProxy.webPageID(), frameId }, WTFMove(frameInfo), processingUserGesture, String(), nullptr }, WTFMove(handler));
}
void WebAuthenticatorCoordinatorProxy::handleRequest(WebAuthenticationRequestData&& data, RequestCompletionHandler&& handler)
Modified: trunk/Source/WebKit/WebAuthnProcess/WebAuthnConnectionToWebProcess.cpp (272183 => 272184)
--- trunk/Source/WebKit/WebAuthnProcess/WebAuthnConnectionToWebProcess.cpp 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Source/WebKit/WebAuthnProcess/WebAuthnConnectionToWebProcess.cpp 2021-02-02 02:49:59 UTC (rev 272184)
@@ -69,12 +69,12 @@
void WebAuthnConnectionToWebProcess::makeCredential(Vector<uint8_t>&& hash, PublicKeyCredentialCreationOptions&& options, bool processingUserGesture, RequestCompletionHandler&& handler)
{
- handleRequest({ WTFMove(hash), WTFMove(options), nullptr, WebAuthenticationPanelResult::Unavailable, nullptr, WTF::nullopt, { }, processingUserGesture, String() }, WTFMove(handler));
+ handleRequest({ WTFMove(hash), WTFMove(options), nullptr, WebAuthenticationPanelResult::Unavailable, nullptr, WTF::nullopt, { }, processingUserGesture, String(), nullptr }, WTFMove(handler));
}
void WebAuthnConnectionToWebProcess::getAssertion(Vector<uint8_t>&& hash, PublicKeyCredentialRequestOptions&& options, bool processingUserGesture, RequestCompletionHandler&& handler)
{
- handleRequest({ WTFMove(hash), WTFMove(options), nullptr, WebAuthenticationPanelResult::Unavailable, nullptr, WTF::nullopt, { }, processingUserGesture, String() }, WTFMove(handler));
+ handleRequest({ WTFMove(hash), WTFMove(options), nullptr, WebAuthenticationPanelResult::Unavailable, nullptr, WTF::nullopt, { }, processingUserGesture, String(), nullptr }, WTFMove(handler));
}
void WebAuthnConnectionToWebProcess::handleRequest(WebAuthenticationRequestData&& data, RequestCompletionHandler&& handler)
Modified: trunk/Tools/ChangeLog (272183 => 272184)
--- trunk/Tools/ChangeLog 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Tools/ChangeLog 2021-02-02 02:49:59 UTC (rev 272184)
@@ -1,3 +1,17 @@
+2021-02-01 Jiewen Tan <[email protected]>
+
+ [WebAuthn] Optimize _WKWebAuthenticationPanelDelegate for native API
+ https://bugs.webkit.org/show_bug.cgi?id=221125
+ <rdar://problem/71509141>
+
+ Reviewed by Brent Fulgham.
+
+ * TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm:
+ (-[TestWebAuthenticationPanelDelegate panel:selectAssertionResponse:source:completionHandler:]):
+ (-[TestWebAuthenticationPanelDelegate panel:requestLAContextForUserVerificationWithCompletionHandler:]):
+ (TestWebKitAPI::WebCore::reset):
+ (TestWebKitAPI::TEST):
+
2021-02-01 Don Olmstead <[email protected]>
[webkitscmpy] Use shutil to find scm executable paths
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm (272183 => 272184)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm 2021-02-02 02:14:23 UTC (rev 272183)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm 2021-02-02 02:49:59 UTC (rev 272184)
@@ -78,6 +78,7 @@
"RQ==";
static String testUserEntityBundleBase64 = "omJpZEoAAQIDBAUGBwgJZG5hbWVkSm9obg=="; // { "id": h'00010203040506070809', "name": "John" }
static String webAuthenticationPanelSelectedCredentialName;
+static bool laContextRequested = false;
@interface TestWebAuthenticationPanelDelegate : NSObject <_WKWebAuthenticationPanelDelegate>
@end
@@ -150,7 +151,10 @@
- (void)panel:(_WKWebAuthenticationPanel *)panel selectAssertionResponse:(NSArray < _WKWebAuthenticationAssertionResponse *> *)responses source:(_WKWebAuthenticationSource)source completionHandler:(void (^)(_WKWebAuthenticationAssertionResponse *))completionHandler
{
if (responses.count == 1) {
- completionHandler(responses[0]);
+ auto laContext = adoptNS([[LAContext alloc] init]);
+ [responses.firstObject setLAContext:laContext.get()];
+
+ completionHandler(responses.firstObject);
return;
}
@@ -157,8 +161,13 @@
// Responses returned from LocalAuthenticator is in the order of LRU. Therefore, we use the last item to populate it to
// the first to test its correctness.
if (source == _WKWebAuthenticationSourceLocal) {
- webAuthenticationPanelSelectedCredentialName = responses.lastObject.name;
- completionHandler(responses.lastObject);
+ auto *object = responses.lastObject;
+
+ auto laContext = adoptNS([[LAContext alloc] init]);
+ [object setLAContext:laContext.get()];
+
+ webAuthenticationPanelSelectedCredentialName = object.name;
+ completionHandler(object);
return;
}
@@ -180,6 +189,12 @@
completionHandler(localAuthenticatorPolicy);
}
+- (void)panel:(_WKWebAuthenticationPanel *)panel requestLAContextForUserVerificationWithCompletionHandler:(void (^)(LAContext *context))completionHandler
+{
+ laContextRequested = true;
+ completionHandler(nil);
+}
+
@end
@interface TestWebAuthenticationPanelFakeDelegate : NSObject <_WKWebAuthenticationPanelDelegate>
@@ -323,6 +338,7 @@
webAuthenticationPanelNullUserHandle = NO;
localAuthenticatorPolicy = _WKLocalAuthenticatorPolicyDisallow;
webAuthenticationPanelSelectedCredentialName = emptyString();
+ laContextRequested = false;
}
static void checkPanel(_WKWebAuthenticationPanel *panel, NSString *relyingPartyID, NSArray *transports, _WKWebAuthenticationType type)
@@ -1760,7 +1776,7 @@
auto user = adoptNS([[_WKPublicKeyCredentialUserEntity alloc] initWithName:@"[email protected]" identifier:nsIdentifier displayName:@"J Appleseed"]);
NSArray<_WKPublicKeyCredentialParameters *> *publicKeyCredentialParamaters = @[ parameters.get() ];
auto options = adoptNS([[_WKPublicKeyCredentialCreationOptions alloc] initWithRelyingParty:rp.get() user:user.get() publicKeyCredentialParamaters:publicKeyCredentialParamaters]);
- [options setTimeout:@120];
+ [options setTimeout:@10];
auto panel = adoptNS([[_WKWebAuthenticationPanel alloc] init]);
[panel makeCredentialWithHash:nsHash options:options.get() completionHandler:^(_WKAuthenticatorAttestationResponse *response, NSError *error) {
@@ -1773,6 +1789,46 @@
Util::run(&webAuthenticationPanelRan);
}
+// For macOS, only internal builds can sign keychain entitlemnets
+// which are required to run local authenticator tests.
+#if USE(APPLE_INTERNAL_SDK) || PLATFORM(IOS)
+TEST(WebAuthenticationPanel, MakeCredentialLA)
+{
+ reset();
+
+ uint8_t identifier[] = { 0x01, 0x02, 0x03, 0x04 };
+ uint8_t hash[] = { 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04 };
+ NSData *nsIdentifier = [NSData dataWithBytes:identifier length:sizeof(identifier)];
+ NSData *nsHash = [NSData dataWithBytes:hash length:sizeof(hash)];
+ auto parameters = adoptNS([[_WKPublicKeyCredentialParameters alloc] initWithAlgorithm:@-7]);
+
+ auto rp = adoptNS([[_WKPublicKeyCredentialRelyingPartyEntity alloc] initWithName:@"example.com"]);
+ [rp setIdentifier:@"example.com"];
+ auto user = adoptNS([[_WKPublicKeyCredentialUserEntity alloc] initWithName:@"[email protected]" identifier:nsIdentifier displayName:@"J Appleseed"]);
+ NSArray<_WKPublicKeyCredentialParameters *> *publicKeyCredentialParamaters = @[ parameters.get() ];
+ auto options = adoptNS([[_WKPublicKeyCredentialCreationOptions alloc] initWithRelyingParty:rp.get() user:user.get() publicKeyCredentialParamaters:publicKeyCredentialParamaters]);
+
+ auto panel = adoptNS([[_WKWebAuthenticationPanel alloc] init]);
+ [panel setMockConfiguration:@{ @"privateKeyBase64": testES256PrivateKeyBase64 }];
+ auto delegate = adoptNS([[TestWebAuthenticationPanelDelegate alloc] init]);
+ [panel setDelegate:delegate.get()];
+
+ [panel makeCredentialWithHash:nsHash options:options.get() completionHandler:^(_WKAuthenticatorAttestationResponse *response, NSError *error) {
+ webAuthenticationPanelRan = true;
+ cleanUpKeychain("example.com");
+
+ EXPECT_TRUE(laContextRequested);
+ EXPECT_NULL(error);
+
+ EXPECT_NOT_NULL(response);
+ EXPECT_WK_STREQ([response.rawId base64EncodedStringWithOptions:0], "SMSXHngF7hEOsElA73C3RY+8bR4=");
+ EXPECT_NULL(response.extensions);
+ EXPECT_WK_STREQ([response.attestationObject base64EncodedStringWithOptions:0], "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViYo3mm9u6vuaVeN4wRgDTidR5oL6ufLTCrE9ISVYbOGUdFAAAAAAAAAAAAAAAAAAAAAAAAAAAAFEjElx54Be4RDrBJQO9wt0WPvG0epQECAyYgASFYIDj/zxSkzKgaBuS3cdWDF558of8AaIpgFpsjF/Qm1749IlggVBJPgqUIwfhWHJ91nb7UPH76c0+WFOzZKslPyyFse4g=");
+ }];
+ Util::run(&webAuthenticationPanelRan);
+}
+#endif
+
TEST(WebAuthenticationPanel, PublicKeyCredentialRequestOptionsMinimun)
{
auto options = adoptNS([[_WKPublicKeyCredentialRequestOptions alloc] init]);
@@ -1870,6 +1926,43 @@
Util::run(&webAuthenticationPanelRan);
}
+// For macOS, only internal builds can sign keychain entitlemnets
+// which are required to run local authenticator tests.
+#if USE(APPLE_INTERNAL_SDK) || PLATFORM(IOS)
+TEST(WebAuthenticationPanel, GetAssertionLA)
+{
+ reset();
+
+ ASSERT_TRUE(addKeyToKeychain(testES256PrivateKeyBase64, "", testUserEntityBundleBase64));
+
+ uint8_t hash[] = { 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04 };
+ NSData *nsHash = [NSData dataWithBytes:hash length:sizeof(hash)];
+
+ auto options = adoptNS([[_WKPublicKeyCredentialRequestOptions alloc] init]);
+ [options setRelyingPartyIdentifier:@""];
+
+ auto panel = adoptNS([[_WKWebAuthenticationPanel alloc] init]);
+ [panel setMockConfiguration:@{ }];
+ auto delegate = adoptNS([[TestWebAuthenticationPanelDelegate alloc] init]);
+ [panel setDelegate:delegate.get()];
+
+ [panel getAssertionWithHash:nsHash options:options.get() completionHandler:^(_WKAuthenticatorAssertionResponse *response, NSError *error) {
+ webAuthenticationPanelRan = true;
+ cleanUpKeychain("");
+
+ EXPECT_NULL(error);
+
+ EXPECT_NOT_NULL(response);
+ EXPECT_WK_STREQ([response.rawId base64EncodedStringWithOptions:0], "SMSXHngF7hEOsElA73C3RY+8bR4=");
+ EXPECT_NULL(response.extensions);
+ EXPECT_WK_STREQ([response.authenticatorData base64EncodedStringWithOptions:0], "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFUFAAAAAA==");
+ EXPECT_NOT_NULL(response.signature);
+ EXPECT_WK_STREQ([response.userHandle base64EncodedStringWithOptions:0], "AAECAwQFBgcICQ==");
+ }];
+ Util::run(&webAuthenticationPanelRan);
+}
+#endif
+
} // namespace TestWebKitAPI
#endif // ENABLE(WEB_AUTHN)