Changeset 257269 in webkit
- Timestamp:
- Feb 24, 2020 3:51:17 PM (4 years ago)
- Location:
- trunk
- Files:
-
- 4 added
- 27 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r257268 r257269 1 2020-02-24 Jiewen Tan <jiewen_tan@apple.com> 2 3 [WebAuthn] Implement SPI for the platform authenticator 4 https://bugs.webkit.org/show_bug.cgi?id=208087 5 <rdar://problem/59369305> 6 7 Reviewed by Brent Fulgham. 8 9 Enhances AuthenticatorAssertionResponse to accommondate responses 10 returned from the platform authenticator. 11 12 Covered by API tests. 13 14 * Modules/webauthn/AuthenticatorAssertionResponse.cpp: 15 (WebCore::AuthenticatorAssertionResponse::create): 16 (WebCore::AuthenticatorAssertionResponse::setAuthenticatorData): 17 (WebCore::AuthenticatorAssertionResponse::AuthenticatorAssertionResponse): 18 * Modules/webauthn/AuthenticatorAssertionResponse.h: 19 (WebCore::AuthenticatorAssertionResponse::authenticatorData const): 20 (WebCore::AuthenticatorAssertionResponse::signature const): 21 (WebCore::AuthenticatorAssertionResponse::name const): 22 (WebCore::AuthenticatorAssertionResponse::displayName const): 23 (WebCore::AuthenticatorAssertionResponse::numberOfCredentials const): 24 (WebCore::AuthenticatorAssertionResponse::accessControl const): 25 (WebCore::AuthenticatorAssertionResponse::setSignature): 26 (WebCore::AuthenticatorAssertionResponse::setName): 27 (WebCore::AuthenticatorAssertionResponse::setDisplayName): 28 (WebCore::AuthenticatorAssertionResponse::setNumberOfCredentials): 29 1 30 2020-02-24 Andres Gonzalez <andresg_22@apple.com> 2 31 -
trunk/Source/WebCore/Modules/webauthn/AuthenticatorAssertionResponse.cpp
r253398 r257269 41 41 } 42 42 43 Ref<AuthenticatorAssertionResponse> AuthenticatorAssertionResponse::create(const Vector<uint8_t>& rawId, const Vector<uint8_t>& authenticatorData, const Vector<uint8_t>& signature, 43 Ref<AuthenticatorAssertionResponse> AuthenticatorAssertionResponse::create(const Vector<uint8_t>& rawId, const Vector<uint8_t>& authenticatorData, const Vector<uint8_t>& signature, const Vector<uint8_t>& userHandle) 44 44 { 45 45 RefPtr<ArrayBuffer> userhandleBuffer; … … 49 49 } 50 50 51 Ref<AuthenticatorAssertionResponse> AuthenticatorAssertionResponse::create(Ref<ArrayBuffer>&& rawId, Ref<ArrayBuffer>&& userHandle, SecAccessControlRef accessControl) 52 { 53 return adoptRef(*new AuthenticatorAssertionResponse(WTFMove(rawId), WTFMove(userHandle), accessControl)); 54 } 55 56 void AuthenticatorAssertionResponse::setAuthenticatorData(Vector<uint8_t>&& authenticatorData) 57 { 58 m_authenticatorData = ArrayBuffer::create(authenticatorData.data(), authenticatorData.size()); 59 } 60 51 61 AuthenticatorAssertionResponse::AuthenticatorAssertionResponse(Ref<ArrayBuffer>&& rawId, Ref<ArrayBuffer>&& authenticatorData, Ref<ArrayBuffer>&& signature, RefPtr<ArrayBuffer>&& userHandle) 52 62 : AuthenticatorResponse(WTFMove(rawId)) … … 54 64 , m_signature(WTFMove(signature)) 55 65 , m_userHandle(WTFMove(userHandle)) 66 { 67 } 68 69 AuthenticatorAssertionResponse::AuthenticatorAssertionResponse(Ref<ArrayBuffer>&& rawId, Ref<ArrayBuffer>&& userHandle, SecAccessControlRef accessControl) 70 : AuthenticatorResponse(WTFMove(rawId)) 71 , m_userHandle(WTFMove(userHandle)) 72 , m_accessControl(accessControl) 56 73 { 57 74 } -
trunk/Source/WebCore/Modules/webauthn/AuthenticatorAssertionResponse.h
r254554 r257269 29 29 30 30 #include "AuthenticatorResponse.h" 31 #include <wtf/RetainPtr.h> 32 #include <wtf/spi/cocoa/SecuritySPI.h> 31 33 32 34 namespace WebCore { … … 36 38 static Ref<AuthenticatorAssertionResponse> create(Ref<ArrayBuffer>&& rawId, Ref<ArrayBuffer>&& authenticatorData, Ref<ArrayBuffer>&& signature, RefPtr<ArrayBuffer>&& userHandle, Optional<AuthenticationExtensionsClientOutputs>&&); 37 39 WEBCORE_EXPORT static Ref<AuthenticatorAssertionResponse> create(const Vector<uint8_t>& rawId, const Vector<uint8_t>& authenticatorData, const Vector<uint8_t>& signature, const Vector<uint8_t>& userHandle); 40 WEBCORE_EXPORT static Ref<AuthenticatorAssertionResponse> create(Ref<ArrayBuffer>&& rawId, Ref<ArrayBuffer>&& userHandle, SecAccessControlRef); 38 41 virtual ~AuthenticatorAssertionResponse() = default; 39 42 40 ArrayBuffer* authenticatorData() const { return m_authenticatorData. ptr(); }41 ArrayBuffer* signature() const { return m_signature. ptr(); }43 ArrayBuffer* authenticatorData() const { return m_authenticatorData.get(); } 44 ArrayBuffer* signature() const { return m_signature.get(); } 42 45 ArrayBuffer* userHandle() const { return m_userHandle.get(); } 46 const String& name() const { return m_name; } 47 const String& displayName() const { return m_displayName; } 48 size_t numberOfCredentials() const { return m_numberOfCredentials; } 49 SecAccessControlRef accessControl() const { return m_accessControl.get(); } 43 50 51 WEBCORE_EXPORT void setAuthenticatorData(Vector<uint8_t>&&); 52 void setSignature(Ref<ArrayBuffer>&& signature) { m_signature = WTFMove(signature); } 44 53 void setName(const String& name) { m_name = name; } 45 const String& name() const { return m_name; }46 54 void setDisplayName(const String& displayName) { m_displayName = displayName; } 47 const String& displayName() const { return m_displayName; }48 55 void setNumberOfCredentials(size_t numberOfCredentials) { m_numberOfCredentials = numberOfCredentials; } 49 size_t numberOfCredentials() const { return m_numberOfCredentials; }50 56 51 57 private: 52 58 AuthenticatorAssertionResponse(Ref<ArrayBuffer>&&, Ref<ArrayBuffer>&&, Ref<ArrayBuffer>&&, RefPtr<ArrayBuffer>&&); 59 AuthenticatorAssertionResponse(Ref<ArrayBuffer>&&, Ref<ArrayBuffer>&&, SecAccessControlRef); 53 60 54 61 Type type() const final { return Type::Assertion; } 55 62 AuthenticatorResponseData data() const final; 56 63 57 Ref <ArrayBuffer> m_authenticatorData;58 Ref <ArrayBuffer> m_signature;64 RefPtr<ArrayBuffer> m_authenticatorData; 65 RefPtr<ArrayBuffer> m_signature; 59 66 RefPtr<ArrayBuffer> m_userHandle; 60 67 … … 62 69 String m_displayName; 63 70 size_t m_numberOfCredentials { 0 }; 71 RetainPtr<SecAccessControlRef> m_accessControl; 64 72 }; 65 73 -
trunk/Source/WebKit/ChangeLog
r257268 r257269 1 2020-02-24 Jiewen Tan <jiewen_tan@apple.com> 2 3 [WebAuthn] Implement SPI for the platform authenticator 4 https://bugs.webkit.org/show_bug.cgi?id=208087 5 <rdar://problem/59369305> 6 7 Reviewed by Brent Fulgham. 8 9 Here is the newly added SPI: 10 typedef NS_ENUM(NSInteger, _WKWebAuthenticationPanelUpdate) { 11 ... 12 _WKWebAuthenticationPanelUpdateLAError, 13 _WKWebAuthenticationPanelUpdateLADuplicateCredential, 14 _WKWebAuthenticationPanelUpdateLANoCredential, 15 }; 16 17 typedef NS_ENUM(NSInteger, _WKWebAuthenticationTransport) { 18 ... 19 _WKWebAuthenticationTransportInternal, 20 }; 21 22 @protocol _WKWebAuthenticationPanelDelegate <NSObject> 23 @optional 24 ... 25 - (void)panel:(_WKWebAuthenticationPanel *)panel verifyUserWithAccessControl:(SecAccessControlRef)accessControl completionHandler:(void (^)(LAContext *))completionHandler; 26 @end 27 28 Illustrations: 29 1) _WKWebAuthenticationPanelUpdate: Three errors are added to help clients present meaningful error messages to users. 30 a) WKWebAuthenticationPanelUpdateLAError: An internal error, clients should inform users and terminate the platform 31 authentication process. This error can be returned at any time. 32 b) _WKWebAuthenticationPanelUpdateLADuplicateCredential: It means a credential is found to match an entry in the 33 excludeList. Clients should inform users and terminate the platform authentication process. This error will only be 34 returned during makeCredential and before verifyUserWithAccessControl delegate. 35 c) _WKWebAuthenticationPanelUpdateLANoCredential: It means no credentials are found. Clients should inform users and 36 terminate the platform authentication process. This error will only be returned during getAssertion and before 37 verifyUserWithAccessControl delegate. 38 39 2) _WKWebAuthenticationTransport: _WKWebAuthenticationTransportInternal is added such that clients can learn platform 40 authenticator will be used from _WKWebAuthenticationPanel.transports. 41 42 3) verifyUserWithAccessControl: A delegate that will be called during makeCredential or getAssertion when the platform 43 authenticator is involved. This delegate is used to obtain user verification from a LAContext. In addition, the LAContext 44 should evaluate the passed accessControl, such that the SEP protected credential private key can be used. A typical 45 example will be [LAContext evaluateAccessControl:accessControl operation:LAAccessControlOperationUseKeySign localizedReason:reply:]. 46 Noted, for getAssertion, selectAssertionResponse will be called before verifyUserWithAccessControl. So users need to be 47 prompted to select a credential before the user verification. 48 49 In the scenario when both the platform authenticator and external authenticators are requested. Clients are advised to 50 wait until verifyUserWithAccessControl to show the combined UI. If any of the LAError states are received before 51 verifyUserWithAccessControl, clients should then only show the external authenticator UI. Also, platform authenticator and 52 external authenticators are being discovered at the same time, which means a user can plug in a security key at anytime. 53 If a valid response is received from the security key, the whole ceremony will be terminated. 54 55 Besides introducing the SPI, and all the necessary plumbing to make it happen. This patch also: 56 1) adds LocalAuthenticationSPI, which is used to check whether a given LAContext is unlocked or not; 57 2) improves MockLocalConnection such that mock testing can still be ran. 58 59 * Platform/spi/Cocoa/LocalAuthenticationSPI.h: Copied from Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticationSoftLink.h. 60 * UIProcess/API/APIWebAuthenticationPanel.cpp: 61 (API::WebAuthenticationPanel::WebAuthenticationPanel): 62 * UIProcess/API/APIWebAuthenticationPanelClient.h: 63 (API::WebAuthenticationPanelClient::verifyUser const): 64 * UIProcess/API/Cocoa/_WKWebAuthenticationPanel.h: 65 * UIProcess/API/Cocoa/_WKWebAuthenticationPanel.mm: 66 (wkWebAuthenticationTransport): 67 * UIProcess/WebAuthentication/Authenticator.h: 68 * UIProcess/WebAuthentication/AuthenticatorManager.cpp: 69 (WebKit::AuthenticatorManager::verifyUser): 70 * UIProcess/WebAuthentication/AuthenticatorManager.h: 71 * UIProcess/WebAuthentication/Cocoa/LocalAuthenticationSoftLink.h: 72 * UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.h: 73 * UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm: 74 (WebKit::LocalAuthenticatorInternal::toNSData): 75 (WebKit::LocalAuthenticatorInternal::toArrayBuffer): 76 (WebKit::LocalAuthenticator::makeCredential): 77 (WebKit::LocalAuthenticator::continueMakeCredentialAfterUserConsented): 78 (WebKit::LocalAuthenticator::continueMakeCredentialAfterAttested): 79 (WebKit::LocalAuthenticator::getAssertion): 80 (WebKit::LocalAuthenticator::continueGetAssertionAfterResponseSelected): 81 (WebKit::LocalAuthenticator::continueGetAssertionAfterUserConsented): 82 (WebKit::LocalAuthenticator::receiveException const): 83 * UIProcess/WebAuthentication/Cocoa/LocalConnection.h: 84 (WebKit::LocalConnection::filterResponses const): 85 * UIProcess/WebAuthentication/Cocoa/LocalConnection.mm: 86 (WebKit::LocalConnection::isUnlocked const): 87 (WebKit::LocalConnection::getUserConsent const): Deleted. 88 (WebKit::LocalConnection::selectCredential const): Deleted. 89 * UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.h: 90 * UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm: 91 (WebKit::WebAuthenticationPanelClient::WebAuthenticationPanelClient): 92 (WebKit::wkWebAuthenticationPanelUpdate): 93 (WebKit::WebAuthenticationPanelClient::selectAssertionResponse const): 94 (WebKit::WebAuthenticationPanelClient::verifyUser const): 95 * UIProcess/WebAuthentication/Mock/MockLocalConnection.h: 96 * UIProcess/WebAuthentication/Mock/MockLocalConnection.mm: 97 (WebKit::MockLocalConnection::isUnlocked const): 98 (WebKit::MockLocalConnection::filterResponses const): 99 (WebKit::MockLocalConnection::getUserConsent const): Deleted. 100 (WebKit::MockLocalConnection::selectCredential const): Deleted. 101 * UIProcess/WebAuthentication/WebAuthenticationFlags.h: 102 * WebKit.xcodeproj/project.pbxproj: 103 1 104 2020-02-24 Per Arne Vollan <pvollan@apple.com> 2 105 -
trunk/Source/WebKit/Platform/spi/Cocoa/LocalAuthenticationSPI.h
r257268 r257269 1 1 /* 2 * Copyright (C) 20 18-2019Apple Inc. All rights reserved.2 * Copyright (C) 2020 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 27 27 28 28 #import <LocalAuthentication/LocalAuthentication.h> 29 #import <wtf/SoftLinking.h>30 29 31 SOFT_LINK_FRAMEWORK_FOR_HEADER(WebKit, LocalAuthentication); 30 #if USE(APPLE_INTERNAL_SDK) 32 31 33 SOFT_LINK_CLASS_FOR_HEADER(WebKit, LAContext); 32 #import <LocalAuthentication/LocalAuthentication_Private.h> 33 34 #else 35 36 typedef NS_ENUM(NSInteger, LAOption) { 37 LAOptionNotInteractive, 38 }; 39 40 @interface LAContext(Private) <NSSecureCoding> 41 42 - (NSDictionary *)evaluatePolicy:(LAPolicy)policy options:(NSDictionary *)options error:(NSError **)error; 43 44 @end 45 46 #endif // USE(APPLE_INTERNAL_SDK) -
trunk/Source/WebKit/UIProcess/API/APIWebAuthenticationPanel.cpp
r251762 r257269 54 54 if (transports.contains(AuthenticatorTransport::Nfc)) 55 55 m_transports.uncheckedAppend(AuthenticatorTransport::Nfc); 56 if (transports.contains(AuthenticatorTransport::Internal)) 57 m_transports.uncheckedAppend(AuthenticatorTransport::Internal); 56 58 } 57 59 -
trunk/Source/WebKit/UIProcess/API/APIWebAuthenticationPanelClient.h
r256238 r257269 31 31 #include <wtf/HashSet.h> 32 32 #include <wtf/RefCounted.h> 33 #include <wtf/spi/cocoa/SecuritySPI.h> 33 34 #include <wtf/text/WTFString.h> 35 36 OBJC_CLASS LAContext; 34 37 35 38 namespace WebCore { … … 53 56 virtual void requestPin(uint64_t, CompletionHandler<void(const WTF::String&)>&& completionHandler) const { completionHandler(emptyString()); } 54 57 virtual void selectAssertionResponse(Vector<Ref<WebCore::AuthenticatorAssertionResponse>>&& responses, CompletionHandler<void(const WebCore::AuthenticatorAssertionResponse&)>&& completionHandler) const { ASSERT(!responses.isEmpty()); completionHandler(responses[0]); } 58 virtual void verifyUser(SecAccessControlRef, CompletionHandler<void(LAContext *)>&& completionHandler) const { completionHandler(nullptr); } 55 59 }; 56 60 -
trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationPanel.h
r254554 r257269 32 32 NS_ASSUME_NONNULL_BEGIN 33 33 34 @class LAContext; 34 35 @class _WKWebAuthenticationAssertionResponse; 35 36 @class _WKWebAuthenticationPanel; … … 47 48 _WKWebAuthenticationPanelUpdatePINAuthBlocked, 48 49 _WKWebAuthenticationPanelUpdatePINInvalid, 50 _WKWebAuthenticationPanelUpdateLAError, 51 _WKWebAuthenticationPanelUpdateLAExcludeCredentialsMatched, 52 _WKWebAuthenticationPanelUpdateLANoCredential, 49 53 } WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA)); 50 54 … … 57 61 _WKWebAuthenticationTransportUSB, 58 62 _WKWebAuthenticationTransportNFC, 63 _WKWebAuthenticationTransportInternal, 59 64 } WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA)); 60 65 … … 72 77 - (void)panel:(_WKWebAuthenticationPanel *)panel requestPINWithRemainingRetries:(NSUInteger)retries completionHandler:(void (^)(NSString *))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA)); 73 78 - (void)panel:(_WKWebAuthenticationPanel *)panel selectAssertionResponse:(NSArray < _WKWebAuthenticationAssertionResponse *> *)responses completionHandler:(void (^)(_WKWebAuthenticationAssertionResponse *))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA)); 79 - (void)panel:(_WKWebAuthenticationPanel *)panel verifyUserWithAccessControl:(SecAccessControlRef)accessControl completionHandler:(void (^)(LAContext *))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA)); 74 80 75 81 @end -
trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebAuthenticationPanel.mm
r254554 r257269 74 74 case WebCore::AuthenticatorTransport::Nfc: 75 75 return _WKWebAuthenticationTransportNFC; 76 case WebCore::AuthenticatorTransport::Internal: 77 return _WKWebAuthenticationTransportInternal; 76 78 default: 77 79 ASSERT_NOT_REACHED(); -
trunk/Source/WebKit/UIProcess/WebAuthentication/Authenticator.h
r254554 r257269 35 35 #include <wtf/RefCounted.h> 36 36 #include <wtf/WeakPtr.h> 37 #include <wtf/spi/cocoa/SecuritySPI.h> 38 39 OBJC_CLASS LAContext; 37 40 38 41 namespace WebCore { … … 54 57 virtual void requestPin(uint64_t retries, CompletionHandler<void(const WTF::String&)>&&) = 0; 55 58 virtual void selectAssertionResponse(const HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>&, CompletionHandler<void(const WebCore::AuthenticatorAssertionResponse&)>&&) = 0; 59 virtual void verifyUser(SecAccessControlRef, CompletionHandler<void(LAContext *)>&&) = 0; 56 60 }; 57 61 -
trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp
r256238 r257269 296 296 } 297 297 298 void AuthenticatorManager::verifyUser(SecAccessControlRef accessControlRef, CompletionHandler<void(LAContext *)>&& completionHandler) 299 { 300 RetainPtr<SecAccessControlRef> accessControl = accessControlRef; 301 dispatchPanelClientCall([accessControl = WTFMove(accessControl), completionHandler = WTFMove(completionHandler)] (const API::WebAuthenticationPanel& panel) mutable { 302 panel.client().verifyUser(accessControl.get(), WTFMove(completionHandler)); 303 }); 304 } 305 298 306 UniqueRef<AuthenticatorTransportService> AuthenticatorManager::createService(AuthenticatorTransport transport, AuthenticatorTransportService::Observer& observer) const 299 307 { -
trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h
r256238 r257269 84 84 void requestPin(uint64_t retries, CompletionHandler<void(const WTF::String&)>&&) final; 85 85 void selectAssertionResponse(const HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>&, CompletionHandler<void(const WebCore::AuthenticatorAssertionResponse&)>&&) final; 86 void verifyUser(SecAccessControlRef, CompletionHandler<void(LAContext *)>&&) final; 86 87 87 88 // Overriden by MockAuthenticatorManager. -
trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticationSoftLink.h
r240631 r257269 26 26 #pragma once 27 27 28 #import <LocalAuthentication/LocalAuthentication.h>28 #import "LocalAuthenticationSPI.h" 29 29 #import <wtf/SoftLinking.h> 30 30 -
trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.h
r257085 r257269 40 40 // Here is the FSM. 41 41 // MakeCredential: Init => RequestReceived => UserConsented => Attested => End 42 // GetAssertion: Init => RequestReceived => UserConsented => End42 // GetAssertion: Init => RequestReceived => ResponseSelected => UserConsented => End 43 43 enum class State { 44 44 Init, … … 46 46 UserConsented, 47 47 Attested, 48 ResponseSelected 48 49 }; 49 50 … … 57 58 58 59 void makeCredential() final; 59 void continueMakeCredentialAfterUserConsented(SecAccessControlRef, L ocalConnection::UserConsent, LAContext *);60 void continueMakeCredentialAfterUserConsented(SecAccessControlRef, LAContext *); 60 61 void continueMakeCredentialAfterAttested(SecKeyRef, Vector<uint8_t>&& credentialId, Vector<uint8_t>&& authData, NSArray *certificates, NSError *); 61 62 62 63 void getAssertion() final; 63 void continueGetAssertionAfterUserConsented(LocalConnection::UserConsent, LAContext *, const Vector<uint8_t>& credentialId, const Vector<uint8_t>& userhandle); 64 void continueGetAssertionAfterResponseSelected(Ref<WebCore::AuthenticatorAssertionResponse>&&); 65 void continueGetAssertionAfterUserConsented(LAContext *, Ref<WebCore::AuthenticatorAssertionResponse>&&); 66 67 void receiveException(WebCore::ExceptionData&&, WebAuthenticationStatus = WebAuthenticationStatus::LAError) const; 64 68 65 69 State m_state { State::Init }; 66 70 UniqueRef<LocalConnection> m_connection; 71 HashSet<Ref<WebCore::AuthenticatorAssertionResponse>> m_assertionResponses; 67 72 }; 68 73 -
trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm
r257085 r257269 87 87 } 88 88 89 static inline RetainPtr<NSData> toNSData(ArrayBuffer* buffer) 90 { 91 ASSERT(buffer); 92 // FIXME(183534): Consider using initWithBytesNoCopy. 93 return adoptNS([[NSData alloc] initWithBytes:buffer->data() length:buffer->byteLength()]); 94 } 95 96 static inline Ref<ArrayBuffer> toArrayBuffer(NSData *data) 97 { 98 return ArrayBuffer::create(reinterpret_cast<const uint8_t*>(data.bytes), data.length); 99 } 100 89 101 } // LocalAuthenticatorInternal 90 102 … … 109 121 return pubKeyCredParam.type == PublicKeyCredentialType::PublicKey && pubKeyCredParam.alg == COSE::ES256; 110 122 })) { 111 receive Respond(ExceptionData{ NotSupportedError, "The platform attached authenticator doesn't support any provided PublicKeyCredentialParameters."_s });123 receiveException({ NotSupportedError, "The platform attached authenticator doesn't support any provided PublicKeyCredentialParameters."_s }); 112 124 return; 113 125 } … … 132 144 OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &attributesArrayRef); 133 145 if (status && status != errSecItemNotFound) { 134 LOG_ERROR("Couldn't query Keychain: %d", status); 135 receiveRespond(ExceptionData { UnknownError, makeString("Couldn't query Keychain: ", status) }); 146 receiveException({ UnknownError, makeString("Couldn't query Keychain: ", status) }); 136 147 return; 137 148 } 138 149 auto retainAttributesArray = adoptCF(attributesArrayRef); 139 150 140 // FIXME (rdar://problem/35900593): Need to obtain user consent and then return different error according to the result.151 // FIXME: Need to obtain user consent and then return different error according to the result. 141 152 for (NSDictionary *nsAttributes in (NSArray *)attributesArrayRef) { 142 153 NSData *nsCredentialId = nsAttributes[(id)kSecAttrApplicationLabel]; 143 154 if (excludeCredentialIds.contains(String(reinterpret_cast<const char*>(nsCredentialId.bytes), nsCredentialId.length))) { 144 receive Respond(ExceptionData { NotAllowedError, "At least one credential matches an entry of the excludeCredentials list in the platform attached authenticator."_s });155 receiveException({ NotAllowedError, "At least one credential matches an entry of the excludeCredentials list in the platform attached authenticator."_s }, WebAuthenticationStatus::LAExcludeCredentialsMatched); 145 156 return; 146 157 } … … 149 160 150 161 // Step 6. 151 // FIXME(rdar://problem/35900593): Update to a formal UI.152 162 // Get user consent. 153 163 RetainPtr<SecAccessControlRef> accessControl; … … 157 167 auto retainError = adoptCF(errorRef); 158 168 if (errorRef) { 159 LOG_ERROR("Couldn't create access control: %@", (NSError *)errorRef); 160 receiveRespond(ExceptionData { UnknownError, makeString("Couldn't create access control: ", String(((NSError*)errorRef).localizedDescription)) }); 169 receiveException({ UnknownError, makeString("Couldn't create access control: ", String(((NSError*)errorRef).localizedDescription)) }); 161 170 return; 162 171 } 163 172 } 164 173 165 SecAccessControlRef accessControlRef = accessControl.get(); 166 auto callback = [accessControl = WTFMove(accessControl), weakThis = makeWeakPtr(*this)] (LocalConnection::UserConsent consent, LAContext *context) { 167 ASSERT(RunLoop::isMain()); 168 if (!weakThis) 169 return; 170 171 weakThis->continueMakeCredentialAfterUserConsented(accessControl.get(), consent, context); 172 }; 173 m_connection->getUserConsent( 174 makeString("allow "_s, creationOptions.rp.id, " to create a public key credential for "_s, creationOptions.user.name), 175 accessControlRef, 176 WTFMove(callback)); 177 } 178 179 void LocalAuthenticator::continueMakeCredentialAfterUserConsented(SecAccessControlRef accessControlRef, LocalConnection::UserConsent consent, LAContext *context) 174 if (auto* observer = this->observer()) { 175 SecAccessControlRef accessControlRef = accessControl.get(); 176 auto callback = [accessControl = WTFMove(accessControl), weakThis = makeWeakPtr(*this)] (LAContext *context) { 177 ASSERT(RunLoop::isMain()); 178 if (!weakThis) 179 return; 180 181 weakThis->continueMakeCredentialAfterUserConsented(accessControl.get(), context); 182 }; 183 observer->verifyUser(accessControlRef, WTFMove(callback)); 184 } 185 } 186 187 void LocalAuthenticator::continueMakeCredentialAfterUserConsented(SecAccessControlRef accessControlRef, LAContext *context) 180 188 { 181 189 using namespace LocalAuthenticatorInternal; … … 185 193 auto& creationOptions = WTF::get<PublicKeyCredentialCreationOptions>(requestData().options); 186 194 187 if ( consent == LocalConnection::UserConsent::No) {195 if (!m_connection->isUnlocked(context)) { 188 196 receiveRespond(ExceptionData { NotAllowedError, "Couldn't get user consent."_s }); 189 197 return; … … 214 222 OSStatus status = SecItemDelete((__bridge CFDictionaryRef)deleteQuery); 215 223 if (status && status != errSecItemNotFound) { 216 LOG_ERROR("Couldn't delete older credential: %d", status); 217 receiveRespond(ExceptionData { UnknownError, makeString("Couldn't delete older credential: ", status) }); 224 receiveException({ UnknownError, makeString("Couldn't delete older credential: ", status) }); 218 225 return; 219 226 } … … 223 230 auto privateKey = m_connection->createCredentialPrivateKey(context, accessControlRef, secAttrLabel, secAttrApplicationTag.get()); 224 231 if (!privateKey) { 225 receive Respond(ExceptionData{ UnknownError, "Couldn't create private key."_s });232 receiveException({ UnknownError, "Couldn't create private key."_s }); 226 233 return; 227 234 } … … 244 251 OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)credentialIdQuery, &attributesRef); 245 252 if (status) { 246 LOG_ERROR("Couldn't get Credential ID: %d", status); 247 receiveRespond(ExceptionData { UnknownError, makeString("Couldn't get Credential ID: ", status) }); 253 receiveException({ UnknownError, makeString("Couldn't get Credential ID: ", status) }); 248 254 return; 249 255 } … … 269 275 auto retainError = adoptCF(errorRef); 270 276 if (errorRef) { 271 LOG_ERROR("Couldn't export the public key: %@", (NSError*)errorRef); 272 receiveRespond(ExceptionData { UnknownError, makeString("Couldn't export the public key: ", String(((NSError*)errorRef).localizedDescription)) }); 277 receiveException({ UnknownError, makeString("Couldn't export the public key: ", String(((NSError*)errorRef).localizedDescription)) }); 273 278 return; 274 279 } … … 310 315 311 316 if (error) { 312 LOG_ERROR("Couldn't attest: %@", error); 313 receiveRespond(ExceptionData { UnknownError, makeString("Couldn't attest: ", String(error.localizedDescription)) }); 317 receiveException({ UnknownError, makeString("Couldn't attest: ", String(error.localizedDescription)) }); 314 318 return; 315 319 } … … 345 349 // Step 12 is implicitly captured by all UnknownError exception callbacks. 346 350 // Step 3-5. Unlike the spec, if an allow list is provided and there is no intersection between existing ones and the allow list, we always return NotAllowedError. 347 // FIXME(rdar://problem/35900593): Need to inform users.348 351 auto allowCredentialIds = produceHashSet(requestOptions.allowCredentials); 349 352 if (!requestOptions.allowCredentials.isEmpty() && allowCredentialIds.isEmpty()) { 350 receive Respond(ExceptionData { NotAllowedError, "No matched credentials are found in the platform attached authenticator."_s });353 receiveException({ NotAllowedError, "No matched credentials are found in the platform attached authenticator."_s }, WebAuthenticationStatus::LANoCredential); 351 354 return; 352 355 } … … 368 371 OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &attributesArrayRef); 369 372 if (status && status != errSecItemNotFound) { 370 LOG_ERROR("Couldn't query Keychain: %d", status); 371 receiveRespond(ExceptionData { UnknownError, makeString("Couldn't query Keychain: ", status) }); 373 receiveException({ UnknownError, makeString("Couldn't query Keychain: ", status) }); 372 374 return; 373 375 } … … 387 389 } 388 390 if (!intersectedCredentialsAttributes.count) { 389 receive Respond(ExceptionData { NotAllowedError, "No matched credentials are found in the platform attached authenticator."_s });391 receiveException({ NotAllowedError, "No matched credentials are found in the platform attached authenticator."_s }, WebAuthenticationStatus::LANoCredential); 390 392 return; 391 393 } 392 394 393 395 // Step 6. 394 auto *selectedCredentialAttributes = m_connection->selectCredential(intersectedCredentialsAttributes); 396 for (NSDictionary *attribute : intersectedCredentialsAttributes) { 397 auto addResult = m_assertionResponses.add(AuthenticatorAssertionResponse::create( 398 toArrayBuffer(attribute[(id)kSecAttrApplicationLabel]), 399 toArrayBuffer(attribute[(id)kSecAttrApplicationTag]), 400 (__bridge SecAccessControlRef)attribute[(id)kSecAttrAccessControl])); 401 ASSERT_UNUSED(addResult, addResult.isNewEntry); 402 } 403 m_connection->filterResponses(m_assertionResponses); 404 405 if (auto* observer = this->observer()) { 406 auto callback = [this, weakThis = makeWeakPtr(*this)] (const AuthenticatorAssertionResponse& response) { 407 ASSERT(RunLoop::isMain()); 408 if (!weakThis) 409 return; 410 411 auto returnResponse = m_assertionResponses.take(const_cast<AuthenticatorAssertionResponse*>(&response)); 412 if (!returnResponse) 413 return; 414 continueGetAssertionAfterResponseSelected(WTFMove(*returnResponse)); 415 }; 416 observer->selectAssertionResponse(m_assertionResponses, WTFMove(callback)); 417 } 418 } 419 420 void LocalAuthenticator::continueGetAssertionAfterResponseSelected(Ref<WebCore::AuthenticatorAssertionResponse>&& response) 421 { 422 ASSERT(m_state == State::RequestReceived); 423 m_state = State::ResponseSelected; 395 424 396 425 // Step 7. Get user consent. 397 // FIXME(rdar://problem/35900593): Update to a formal UI. 398 auto callback = [ 399 weakThis = makeWeakPtr(*this), 400 credentialId = toVector(selectedCredentialAttributes[(id)kSecAttrApplicationLabel]), 401 userhandle = toVector(selectedCredentialAttributes[(id)kSecAttrApplicationTag]) 402 ](LocalConnection::UserConsent consent, LAContext *context) { 403 ASSERT(RunLoop::isMain()); 404 if (!weakThis) 405 return; 406 407 weakThis->continueGetAssertionAfterUserConsented(consent, context, credentialId, userhandle); 408 }; 409 NSData *idData = selectedCredentialAttributes[(id)kSecAttrApplicationTag]; 410 StringView idStringView { static_cast<const UChar*>([idData bytes]), static_cast<unsigned>([idData length]) }; 411 m_connection->getUserConsent( 412 makeString("log into ", requestOptions.rpId, " with ", idStringView), 413 (__bridge SecAccessControlRef)selectedCredentialAttributes[(id)kSecAttrAccessControl], 414 WTFMove(callback)); 415 } 416 417 void LocalAuthenticator::continueGetAssertionAfterUserConsented(LocalConnection::UserConsent consent, LAContext *context, const Vector<uint8_t>& credentialId, const Vector<uint8_t>& userhandle) 426 if (auto* observer = this->observer()) { 427 auto accessControlRef = response->accessControl(); 428 auto callback = [weakThis = makeWeakPtr(*this), response = WTFMove(response)] (LAContext *context) mutable { 429 ASSERT(RunLoop::isMain()); 430 if (!weakThis) 431 return; 432 433 weakThis->continueGetAssertionAfterUserConsented(context, WTFMove(response)); 434 }; 435 observer->verifyUser(accessControlRef, WTFMove(callback)); 436 } 437 } 438 439 void LocalAuthenticator::continueGetAssertionAfterUserConsented(LAContext *context, Ref<WebCore::AuthenticatorAssertionResponse>&& response) 418 440 { 419 441 using namespace LocalAuthenticatorInternal; 420 ASSERT(m_state == State::Re questReceived);442 ASSERT(m_state == State::ResponseSelected); 421 443 m_state = State::UserConsented; 422 444 423 if ( consent == LocalConnection::UserConsent::No) {445 if (!m_connection->isUnlocked(context)) { 424 446 receiveRespond(ExceptionData { NotAllowedError, "Couldn't get user consent."_s }); 425 447 return; … … 433 455 434 456 // Step 11. 435 Vector<uint8_t> signature;457 RetainPtr<CFDataRef> signature; 436 458 { 437 NSDictionary *query = @{ 459 auto query = adoptNS([[NSMutableDictionary alloc] init]); 460 [query addEntriesFromDictionary:@{ 438 461 (id)kSecClass: (id)kSecClassKey, 439 462 (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate, 440 (id)kSecAttrApplicationLabel: toNSData(credentialId).get(), 441 (id)kSecUseAuthenticationContext: context, 463 (id)kSecAttrApplicationLabel: toNSData(response->rawId()).get(), 442 464 (id)kSecReturnRef: @YES, 443 465 #if HAVE(DATA_PROTECTION_KEYCHAIN) … … 446 468 (id)kSecAttrNoLegacy: @YES 447 469 #endif 448 }; 470 }]; 471 // context is nullptr in mock testing. 472 if (context) 473 [query setObject:context forKey:(id)kSecUseAuthenticationContext]; 449 474 CFTypeRef privateKeyRef = nullptr; 450 OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query , &privateKeyRef);475 OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query.get(), &privateKeyRef); 451 476 if (status) { 452 LOG_ERROR("Couldn't get the private key reference: %d", status); 453 receiveRespond(ExceptionData { UnknownError, makeString("Couldn't get the private key reference: ", status) }); 477 receiveException({ UnknownError, makeString("Couldn't get the private key reference: ", status) }); 454 478 return; 455 479 } … … 461 485 CFErrorRef errorRef = nullptr; 462 486 // FIXME: Converting CFTypeRef to SecKeyRef is quite subtle here. 463 auto signatureRef= adoptCF(SecKeyCreateSignature((__bridge SecKeyRef)((id)privateKeyRef), kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef)dataToSign, &errorRef));487 signature = adoptCF(SecKeyCreateSignature((__bridge SecKeyRef)((id)privateKeyRef), kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef)dataToSign, &errorRef)); 464 488 auto retainError = adoptCF(errorRef); 465 489 if (errorRef) { 466 LOG_ERROR("Couldn't generate the signature: %@", (NSError*)errorRef); 467 receiveRespond(ExceptionData { UnknownError, makeString("Couldn't generate the signature: ", String(((NSError*)errorRef).localizedDescription)) }); 490 receiveException({ UnknownError, makeString("Couldn't generate the signature: ", String(((NSError*)errorRef).localizedDescription)) }); 468 491 return; 469 492 } 470 signature = toVector((NSData *)signatureRef.get());471 493 } 472 494 473 495 // Step 13. 474 receiveRespond(AuthenticatorAssertionResponse::create(credentialId, authData, signature, userhandle)); 496 response->setAuthenticatorData(WTFMove(authData)); 497 response->setSignature(toArrayBuffer((NSData *)signature.get())); 498 receiveRespond(WTFMove(response)); 499 } 500 501 void LocalAuthenticator::receiveException(ExceptionData&& exception, WebAuthenticationStatus status) const 502 { 503 LOG_ERROR(exception.message.utf8().data()); 504 if (auto* observer = this->observer()) 505 observer->authenticatorStatusUpdated(status); 506 receiveRespond(WTFMove(exception)); 507 return; 475 508 } 476 509 -
trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalConnection.h
r257085 r257269 47 47 WTF_MAKE_NONCOPYABLE(LocalConnection); 48 48 public: 49 enum class UserConsent {50 No,51 Yes52 };53 54 49 using AttestationCallback = CompletionHandler<void(NSArray *, NSError *)>; 55 using UserConsentCallback = CompletionHandler<void(UserConsent)>;56 using UserConsentContextCallback = CompletionHandler<void(UserConsent, LAContext *)>;57 50 58 51 LocalConnection() = default; … … 60 53 61 54 // Overrided by MockLocalConnection. 62 virtual void getUserConsent(const String& reason, SecAccessControlRef, UserConsentContextCallback&&) const;55 virtual bool isUnlocked(LAContext *) const; 63 56 virtual RetainPtr<SecKeyRef> createCredentialPrivateKey(LAContext *, SecAccessControlRef, const String& secAttrLabel, NSData *secAttrApplicationTag) const; 64 57 virtual void getAttestation(SecKeyRef, NSData *authData, NSData *hash, AttestationCallback&&) const; 65 virtual NSDictionary *selectCredential(const NSArray *) const;58 virtual void filterResponses(HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>&) const { }; 66 59 }; 67 60 -
trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalConnection.mm
r257085 r257269 40 40 namespace WebKit { 41 41 42 void LocalConnection::getUserConsent(const String& reason, SecAccessControlRef accessControl, UserConsentContextCallback&& completionHandler) const42 bool LocalConnection::isUnlocked(LAContext *context) const 43 43 { 44 auto context = adoptNS([allocLAContextInstance() init]); 45 auto reply = makeBlockPtr([context, completionHandler = WTFMove(completionHandler)] (BOOL success, NSError *error) mutable { 46 ASSERT(!RunLoop::isMain()); 47 48 UserConsent consent = UserConsent::Yes; 49 if (!success || error) { 50 LOG_ERROR("Couldn't authenticate with biometrics: %@", error); 51 consent = UserConsent::No; 52 } 53 RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), consent, context = WTFMove(context)]() mutable { 54 completionHandler(consent, context.get()); 55 }); 56 }); 57 [context evaluateAccessControl:accessControl operation:LAAccessControlOperationUseKeySign localizedReason:reason reply:reply.get()]; 44 NSError *error = nil; 45 auto result = [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics options:@{ @(LAOptionNotInteractive): @YES } error:&error]; 46 if (!result) 47 LOG_ERROR("Couldn't get user consent: %@", error); 48 return !!result; 58 49 } 59 50 … … 89 80 } 90 81 91 NSDictionary *LocalConnection::selectCredential(const NSArray *credentials) const92 {93 // FIXME(rdar://problem/35900534): We don't have an UI to prompt users for selecting intersectedCredentials, and therefore we always use the first one for now.94 return credentials[0];95 }96 97 82 } // namespace WebKit 98 83 -
trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.h
r256238 r257269 51 51 void requestPin(uint64_t, CompletionHandler<void(const WTF::String&)>&&) const final; 52 52 void selectAssertionResponse(Vector<Ref<WebCore::AuthenticatorAssertionResponse>>&&, CompletionHandler<void(const WebCore::AuthenticatorAssertionResponse&)>&&) const final; 53 void verifyUser(SecAccessControlRef, CompletionHandler<void(LAContext *)>&&) const final; 53 54 54 55 _WKWebAuthenticationPanel *m_panel; … … 59 60 bool panelDismissWebAuthenticationPanelWithResult : 1; 60 61 bool panelRequestPinWithRemainingRetriesCompletionHandler : 1; 61 bool panelselectAssertionResponseCompletionHandler : 1; 62 bool panelSelectAssertionResponseCompletionHandler : 1; 63 bool panelVerifyUserWithAccessControlCompletionHandler : 1; 62 64 } m_delegateMethods; 63 65 }; -
trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm
r256238 r257269 39 39 #import <wtf/RunLoop.h> 40 40 41 #import "LocalAuthenticationSoftLink.h" 42 41 43 namespace WebKit { 42 44 … … 48 50 m_delegateMethods.panelDismissWebAuthenticationPanelWithResult = [delegate respondsToSelector:@selector(panel:dismissWebAuthenticationPanelWithResult:)]; 49 51 m_delegateMethods.panelRequestPinWithRemainingRetriesCompletionHandler = [delegate respondsToSelector:@selector(panel:requestPINWithRemainingRetries:completionHandler:)]; 50 m_delegateMethods.panelselectAssertionResponseCompletionHandler = [delegate respondsToSelector:@selector(panel:selectAssertionResponse:completionHandler:)]; 52 m_delegateMethods.panelSelectAssertionResponseCompletionHandler = [delegate respondsToSelector:@selector(panel:selectAssertionResponse:completionHandler:)]; 53 m_delegateMethods.panelVerifyUserWithAccessControlCompletionHandler = [delegate respondsToSelector:@selector(panel:verifyUserWithAccessControl:completionHandler:)]; 51 54 } 52 55 … … 68 71 if (status == WebAuthenticationStatus::PinInvalid) 69 72 return _WKWebAuthenticationPanelUpdatePINInvalid; 73 if (status == WebAuthenticationStatus::LAError) 74 return _WKWebAuthenticationPanelUpdateLAError; 75 if (status == WebAuthenticationStatus::LAExcludeCredentialsMatched) 76 return _WKWebAuthenticationPanelUpdateLAExcludeCredentialsMatched; 77 if (status == WebAuthenticationStatus::LANoCredential) 78 return _WKWebAuthenticationPanelUpdateLANoCredential; 70 79 ASSERT_NOT_REACHED(); 71 80 return _WKWebAuthenticationPanelUpdateMultipleNFCTagsPresent; … … 134 143 ASSERT(!responses.isEmpty()); 135 144 136 if (!m_delegateMethods.panel selectAssertionResponseCompletionHandler) {145 if (!m_delegateMethods.panelSelectAssertionResponseCompletionHandler) { 137 146 completionHandler(responses[0]); 138 147 return; … … 159 168 } 160 169 170 void WebAuthenticationPanelClient::verifyUser(SecAccessControlRef accessControl, CompletionHandler<void(LAContext *)>&& completionHandler) const 171 { 172 if (!m_delegateMethods.panelVerifyUserWithAccessControlCompletionHandler) { 173 completionHandler(adoptNS([allocLAContextInstance() init]).get()); 174 return; 175 } 176 177 auto delegate = m_delegate.get(); 178 if (!delegate) { 179 completionHandler(adoptNS([allocLAContextInstance() init]).get()); 180 return; 181 } 182 183 auto checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(panel:verifyUserWithAccessControl:completionHandler:)); 184 [delegate panel:m_panel verifyUserWithAccessControl:accessControl completionHandler:makeBlockPtr([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](LAContext *context) mutable { 185 if (checker->completionHandlerHasBeenCalled()) 186 return; 187 checker->didCallCompletionHandler(); 188 completionHandler(context); 189 }).get()]; 190 } 191 161 192 } // namespace WebKit 162 193 -
trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.h
r257085 r257269 38 38 39 39 private: 40 void getUserConsent(const String& reason, SecAccessControlRef, UserConsentContextCallback&&) const final;40 bool isUnlocked(LAContext *) const final; 41 41 RetainPtr<SecKeyRef> createCredentialPrivateKey(LAContext *, SecAccessControlRef, const String& secAttrLabel, NSData *secAttrApplicationTag) const final; 42 42 void getAttestation(SecKeyRef, NSData *authData, NSData *hash, AttestationCallback&&) const final; 43 NSDictionary *selectCredential(const NSArray *) const final;43 void filterResponses(HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>&) const final; 44 44 45 45 WebCore::MockWebAuthenticationConfiguration m_configuration; -
trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.mm
r257085 r257269 33 33 #import <wtf/RunLoop.h> 34 34 #import <wtf/spi/cocoa/SecuritySPI.h> 35 #import <wtf/text/Base64.h> 35 36 #import <wtf/text/WTFString.h> 36 37 … … 44 45 } 45 46 46 void MockLocalConnection::getUserConsent(const String&, SecAccessControlRef, UserConsentContextCallback&& callback) const47 bool MockLocalConnection::isUnlocked(LAContext *context) const 47 48 { 48 // Mock async operations. 49 RunLoop::main().dispatch([configuration = m_configuration, callback = WTFMove(callback)]() mutable { 50 ASSERT(configuration.local); 51 if (!configuration.local->acceptAuthentication) { 52 callback(UserConsent::No, nil); 53 return; 54 } 55 callback(UserConsent::Yes, adoptNS([allocLAContextInstance() init]).get()); 56 }); 49 return m_configuration.local->acceptAuthentication; 57 50 } 58 51 … … 113 106 } 114 107 115 NSDictionary *MockLocalConnection::selectCredential(const NSArray *credentials) const108 void MockLocalConnection::filterResponses(HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>& responses) const 116 109 { 117 auto preferredUserhandle = adoptNS([[NSData alloc] initWithBase64EncodedString:m_configuration.local->preferredUserhandleBase64 options:0]); 118 for (NSDictionary *credential : credentials) { 119 if ([credential[(id)kSecAttrApplicationTag] isEqualToData:preferredUserhandle.get()]) 120 return credential; 110 const auto& preferredUserhandleBase64 = m_configuration.local->preferredUserhandleBase64; 111 if (preferredUserhandleBase64.isEmpty()) 112 return; 113 114 auto itr = responses.begin(); 115 for (; itr != responses.end(); ++itr) { 116 auto* userHandle = itr->get().userHandle(); 117 ASSERT(userHandle); 118 auto userhandleBase64 = base64Encode(userHandle->data(), userHandle->byteLength()); 119 if (userhandleBase64 == preferredUserhandleBase64) 120 break; 121 121 } 122 ASSERT_NOT_REACHED(); 123 return nil; 122 auto response = responses.take(itr); 123 ASSERT(response); 124 responses.clear(); 125 responses.add(WTFMove(*response)); 124 126 } 125 127 -
trunk/Source/WebKit/UIProcess/WebAuthentication/WebAuthenticationFlags.h
r256062 r257269 46 46 PinBlocked, 47 47 PinAuthBlocked, 48 PinInvalid 48 PinInvalid, 49 LAError, 50 LAExcludeCredentialsMatched, 51 LANoCredential, 49 52 }; 50 53 -
trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj
r257127 r257269 1097 1097 570DAACA230385FD00E8FC04 /* CtapNfcDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 570DAAC8230385FD00E8FC04 /* CtapNfcDriver.h */; }; 1098 1098 572FD44322265CE200A1ECC3 /* WebViewDidMoveToWindowObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 572FD44122265CE200A1ECC3 /* WebViewDidMoveToWindowObserver.h */; }; 1099 574217922400E286002B303D /* LocalAuthenticationSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 574217912400E098002B303D /* LocalAuthenticationSPI.h */; }; 1099 1100 574728D123456E98001700AF /* _WKWebAuthenticationPanel.h in Headers */ = {isa = PBXBuildFile; fileRef = 574728CF23456E98001700AF /* _WKWebAuthenticationPanel.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1100 1101 574728D4234570AE001700AF /* _WKWebAuthenticationPanelInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 574728D3234570AE001700AF /* _WKWebAuthenticationPanelInternal.h */; }; … … 3812 3813 570DAAC9230385FD00E8FC04 /* CtapNfcDriver.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CtapNfcDriver.cpp; sourceTree = "<group>"; }; 3813 3814 572FD44122265CE200A1ECC3 /* WebViewDidMoveToWindowObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebViewDidMoveToWindowObserver.h; sourceTree = "<group>"; }; 3815 574217912400E098002B303D /* LocalAuthenticationSPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocalAuthenticationSPI.h; sourceTree = "<group>"; }; 3814 3816 574728CF23456E98001700AF /* _WKWebAuthenticationPanel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _WKWebAuthenticationPanel.h; sourceTree = "<group>"; }; 3815 3817 574728D023456E98001700AF /* _WKWebAuthenticationPanel.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = _WKWebAuthenticationPanel.mm; sourceTree = "<group>"; }; … … 6840 6842 37C21CAD1E994C0C0029D5F9 /* CorePredictionSPI.h */, 6841 6843 2DAADA8E2298C21000E36B0C /* DeviceManagementSPI.h */, 6844 574217912400E098002B303D /* LocalAuthenticationSPI.h */, 6842 6845 57B826402304EB3E00B72EB0 /* NearFieldSPI.h */, 6843 6846 3754D5441B3A29FD003A4C7F /* NSInvocationSPI.h */, … … 10363 10366 2D1087611D2C573E00B85F82 /* LoadParameters.h in Headers */, 10364 10367 578DC2982155A0020074E815 /* LocalAuthenticationSoftLink.h in Headers */, 10368 574217922400E286002B303D /* LocalAuthenticationSPI.h in Headers */, 10365 10369 57DCEDAC214C60270016B847 /* LocalAuthenticator.h in Headers */, 10366 10370 57DCEDAD214C602C0016B847 /* LocalConnection.h in Headers */, -
trunk/Tools/ChangeLog
r257257 r257269 1 2020-02-24 Jiewen Tan <jiewen_tan@apple.com> 2 3 [WebAuthn] Implement SPI for the platform authenticator 4 https://bugs.webkit.org/show_bug.cgi?id=208087 5 <rdar://problem/59369305> 6 7 Reviewed by Brent Fulgham. 8 9 Besides adding API tests, this patch also teaches TestWebKitAPI to use restricted entitlements. 10 11 * TestWebKitAPI/Configurations/TestWebKitAPI-macOS.entitlements: 12 * TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig: 13 * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: 14 * TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm: 15 (-[TestWebAuthenticationPanelDelegate panel:updateWebAuthenticationPanel:]): 16 (-[TestWebAuthenticationPanelDelegate panel:selectAssertionResponse:completionHandler:]): 17 (-[TestWebAuthenticationPanelDelegate panel:verifyUserWithAccessControl:completionHandler:]): 18 (TestWebKitAPI::TEST): 19 * TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-la.html: Copied from Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion.html. 20 * TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-la-duplicate-credential.html: Added. 21 * TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-la-error.html: Added. 22 * TestWebKitAPI/Tests/WebKitCocoa/web-authentication-make-credential-la.html: Added. 23 1 24 2020-02-24 Yusuke Suzuki <ysuzuki@apple.com> 2 25 -
trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI-macOS.entitlements
r256777 r257269 3 3 <plist version="1.0"> 4 4 <dict> 5 <key>keychain-access-groups</key> 6 <array> 7 <string>com.apple.TestWebKitAPI</string> 8 </array> 5 9 <key>com.apple.security.temporary-exception.sbpl</key> 6 10 <array> -
trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig
r256777 r257269 70 70 71 71 STRIP_STYLE = debugging; 72 73 CODE_SIGN_IDENTITY[sdk=macosx*] = $(CODE_SIGN_IDENTITY_$(CONFIGURATION)); 74 CODE_SIGN_IDENTITY_Debug = $(CODE_SIGN_IDENTITY_$(USE_INTERNAL_SDK)); 75 CODE_SIGN_IDENTITY_Release = $(CODE_SIGN_IDENTITY_$(USE_INTERNAL_SDK)); 76 CODE_SIGN_IDENTITY_YES = $(WK_ENGINEERING_CODE_SIGN_IDENTITY); 77 CODE_SIGN_IDENTITY_Production = $(CODE_SIGN_IDENTITY_Production_$(USE_INTERNAL_SDK)); 78 CODE_SIGN_IDENTITY_Production_YES = -; -
trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
r257225 r257269 350 350 573255A622139BC700396AE8 /* load-web-archive-1.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 573255A222139B8F00396AE8 /* load-web-archive-1.html */; }; 351 351 573255A722139BC700396AE8 /* load-web-archive-2.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 573255A322139B9000396AE8 /* load-web-archive-2.html */; }; 352 574217882400AC25002B303D /* web-authentication-make-credential-la-error.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 574217872400ABFD002B303D /* web-authentication-make-credential-la-error.html */; }; 353 5742178A2400AED8002B303D /* web-authentication-make-credential-la-duplicate-credential.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 574217892400AED0002B303D /* web-authentication-make-credential-la-duplicate-credential.html */; }; 354 5742178C2400CD47002B303D /* web-authentication-get-assertion-la.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5742178B2400CD2D002B303D /* web-authentication-get-assertion-la.html */; }; 355 5742178E2400D2DF002B303D /* web-authentication-make-credential-la.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5742178D2400D26C002B303D /* web-authentication-make-credential-la.html */; }; 352 356 574F55D2204D47F0002948C6 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 574F55D0204D471C002948C6 /* Security.framework */; }; 353 357 5758597F23A2527A00C74572 /* CtapPinTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5758597E23A2527A00C74572 /* CtapPinTest.cpp */; }; … … 1519 1523 570D26FC23C3F87000D5CF67 /* web-authentication-get-assertion-hid-pin.html in Copy Resources */, 1520 1524 57663DEC234F1F9300E85E09 /* web-authentication-get-assertion-hid.html in Copy Resources */, 1525 5742178C2400CD47002B303D /* web-authentication-get-assertion-la.html in Copy Resources */, 1521 1526 579833922368FA37008E5547 /* web-authentication-get-assertion-nfc-multiple-tags.html in Copy Resources */, 1522 1527 57663DEA234EA66D00E85E09 /* web-authentication-get-assertion-nfc.html in Copy Resources */, … … 1533 1538 570D26F623C3D33000D5CF67 /* web-authentication-make-credential-hid-pin.html in Copy Resources */, 1534 1539 5798337E236019A4008E5547 /* web-authentication-make-credential-hid.html in Copy Resources */, 1540 5742178A2400AED8002B303D /* web-authentication-make-credential-la-duplicate-credential.html in Copy Resources */, 1541 574217882400AC25002B303D /* web-authentication-make-credential-la-error.html in Copy Resources */, 1542 5742178E2400D2DF002B303D /* web-authentication-make-credential-la.html in Copy Resources */, 1535 1543 1C2B81861C89259D00A5529F /* webfont.html in Copy Resources */, 1536 1544 51714EB41CF8C78C004723C4 /* WebProcessKillIDBCleanup-1.html in Copy Resources */, … … 1963 1971 573255A422139B9000396AE8 /* helloworld.webarchive */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = helloworld.webarchive; sourceTree = "<group>"; }; 1964 1972 5735F0251F3A4EA6000EE801 /* TestWebKitAPI-iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "TestWebKitAPI-iOS.entitlements"; sourceTree = "<group>"; }; 1973 574217872400ABFD002B303D /* web-authentication-make-credential-la-error.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "web-authentication-make-credential-la-error.html"; sourceTree = "<group>"; }; 1974 574217892400AED0002B303D /* web-authentication-make-credential-la-duplicate-credential.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "web-authentication-make-credential-la-duplicate-credential.html"; sourceTree = "<group>"; }; 1975 5742178B2400CD2D002B303D /* web-authentication-get-assertion-la.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "web-authentication-get-assertion-la.html"; sourceTree = "<group>"; }; 1976 5742178D2400D26C002B303D /* web-authentication-make-credential-la.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "web-authentication-make-credential-la.html"; sourceTree = "<group>"; }; 1977 5742178F2400D54D002B303D /* web-authentication-make-credential.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "web-authentication-make-credential.html"; sourceTree = "<group>"; }; 1965 1978 574F55D0204D471C002948C6 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 1966 1979 5758597D23A2527A00C74572 /* CtapPinTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CtapPinTest.h; sourceTree = "<group>"; }; … … 3583 3596 570D26FB23C3F86500D5CF67 /* web-authentication-get-assertion-hid-pin.html */, 3584 3597 57663DEB234F1F8000E85E09 /* web-authentication-get-assertion-hid.html */, 3598 5742178B2400CD2D002B303D /* web-authentication-get-assertion-la.html */, 3585 3599 5798337B235EB65C008E5547 /* web-authentication-get-assertion-nfc-multiple-tags.html */, 3586 3600 57663DE9234EA60B00E85E09 /* web-authentication-get-assertion-nfc.html */, … … 3597 3611 570D26F523C3D32700D5CF67 /* web-authentication-make-credential-hid-pin.html */, 3598 3612 5798337D2360196D008E5547 /* web-authentication-make-credential-hid.html */, 3613 574217892400AED0002B303D /* web-authentication-make-credential-la-duplicate-credential.html */, 3614 574217872400ABFD002B303D /* web-authentication-make-credential-la-error.html */, 3615 5742178D2400D26C002B303D /* web-authentication-make-credential-la.html */, 3616 5742178F2400D54D002B303D /* web-authentication-make-credential.html */, 3599 3617 51714EB21CF8C761004723C4 /* WebProcessKillIDBCleanup-1.html */, 3600 3618 51714EB31CF8C761004723C4 /* WebProcessKillIDBCleanup-2.html */, -
trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm
r256062 r257269 33 33 #import "TestWKWebView.h" 34 34 #import "WKWebViewConfigurationExtras.h" 35 #import <LocalAuthentication/LocalAuthentication.h> 35 36 #import <WebKit/WKPreferencesPrivate.h> 36 37 #import <WebKit/WKUIDelegatePrivate.h> … … 40 41 #import <wtf/BlockPtr.h> 41 42 #import <wtf/RandomNumber.h> 43 #import <wtf/spi/cocoa/SecuritySPI.h> 42 44 #import <wtf/text/StringConcatenateNumbers.h> 43 45 … … 50 52 static bool webAuthenticationPanelUpdatePINAuthBlocked = false; 51 53 static bool webAuthenticationPanelUpdatePINInvalid = false; 54 static bool webAuthenticationPanelUpdateLAError = false; 55 static bool webAuthenticationPanelUpdateLAExcludeCredentialsMatched = false; 56 static bool webAuthenticationPanelUpdateLANoCredential = false; 52 57 static bool webAuthenticationPanelCancelImmediately = false; 58 static bool webAuthenticationPanelVerifyUser = false; 53 59 static String webAuthenticationPanelPin; 54 60 static BOOL webAuthenticationPanelNullUserHandle = NO; 61 static String testES256PrivateKeyBase64 = 62 "BDj/zxSkzKgaBuS3cdWDF558of8AaIpgFpsjF/Qm1749VBJPgqUIwfhWHJ91nb7U" 63 "PH76c0+WFOzZKslPyyFse4goGIW2R7k9VHLPEZl5nfnBgEVFh5zev+/xpHQIvuq6" 64 "RQ=="; 65 static String testUserhandleBase64 = "AAECAwQFBgcICQ=="; 55 66 56 67 @interface TestWebAuthenticationPanelDelegate : NSObject <_WKWebAuthenticationPanelDelegate> … … 85 96 return; 86 97 } 98 if (update == _WKWebAuthenticationPanelUpdateLAError) { 99 webAuthenticationPanelUpdateLAError = true; 100 return; 101 } 102 if (update == _WKWebAuthenticationPanelUpdateLAExcludeCredentialsMatched) { 103 webAuthenticationPanelUpdateLAExcludeCredentialsMatched = true; 104 return; 105 } 106 if (update == _WKWebAuthenticationPanelUpdateLANoCredential) { 107 webAuthenticationPanelUpdateLANoCredential = true; 108 return; 109 } 87 110 } 88 111 … … 112 135 - (void)panel:(_WKWebAuthenticationPanel *)panel selectAssertionResponse:(NSArray < _WKWebAuthenticationAssertionResponse *> *)responses completionHandler:(void (^)(_WKWebAuthenticationAssertionResponse *))completionHandler 113 136 { 137 if (responses.count == 1) { 138 completionHandler(responses[0]); 139 return; 140 } 141 114 142 EXPECT_EQ(responses.count, 2ul); 115 143 for (_WKWebAuthenticationAssertionResponse *response in responses) { … … 122 150 webAuthenticationPanelNullUserHandle = responses[index].userHandle ? NO : YES; 123 151 completionHandler(responses[index]); 152 } 153 154 - (void)panel:(_WKWebAuthenticationPanel *)panel verifyUserWithAccessControl:(SecAccessControlRef)accessControl completionHandler:(void (^)(LAContext *))completionHandler 155 { 156 webAuthenticationPanelVerifyUser = true; 157 auto context = adoptNS([[LAContext alloc] init]); 158 completionHandler(context.get()); 124 159 } 125 160 … … 232 267 } 233 268 269 #if USE(APPLE_INTERNAL_SDK) || PLATFORM(IOS) 270 static _WKExperimentalFeature *webAuthenticationLocalAuthenticatorExperimentalFeature() 271 { 272 static RetainPtr<_WKExperimentalFeature> theFeature; 273 if (theFeature) 274 return theFeature.get(); 275 276 NSArray *features = [WKPreferences _experimentalFeatures]; 277 for (_WKExperimentalFeature *feature in features) { 278 if ([feature.key isEqual:@"WebAuthenticationLocalAuthenticatorEnabled"]) { 279 theFeature = feature; 280 break; 281 } 282 } 283 return theFeature.get(); 284 } 285 #endif // USE(APPLE_INTERNAL_SDK) || PLATFORM(IOS) 286 234 287 static void reset() 235 288 { … … 242 295 webAuthenticationPanelUpdatePINAuthBlocked = false; 243 296 webAuthenticationPanelUpdatePINInvalid = false; 297 webAuthenticationPanelUpdateLAError = false; 298 webAuthenticationPanelUpdateLAExcludeCredentialsMatched = false; 299 webAuthenticationPanelUpdateLANoCredential = false; 244 300 webAuthenticationPanelCancelImmediately = false; 245 301 webAuthenticationPanelPin = emptyString(); 246 302 webAuthenticationPanelNullUserHandle = NO; 303 webAuthenticationPanelVerifyUser = false; 247 304 } 248 305 … … 277 334 EXPECT_EQ(frame.webView, webView); 278 335 } 336 337 #if USE(APPLE_INTERNAL_SDK) || PLATFORM(IOS) 338 339 bool addKeyToKeychain(const String& privateKeyBase64, const String& rpId, const String& userHandleBase64) 340 { 341 NSDictionary* options = @{ 342 (id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, 343 (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate, 344 (id)kSecAttrKeySizeInBits: @256, 345 }; 346 CFErrorRef errorRef = nullptr; 347 auto key = adoptCF(SecKeyCreateWithData( 348 (__bridge CFDataRef)adoptNS([[NSData alloc] initWithBase64EncodedString:privateKeyBase64 options:NSDataBase64DecodingIgnoreUnknownCharacters]).get(), 349 (__bridge CFDictionaryRef)options, 350 &errorRef 351 )); 352 if (errorRef) 353 return false; 354 355 NSDictionary* addQuery = @{ 356 (id)kSecValueRef: (id)key.get(), 357 (id)kSecClass: (id)kSecClassKey, 358 (id)kSecAttrLabel: rpId, 359 (id)kSecAttrApplicationTag: adoptNS([[NSData alloc] initWithBase64EncodedString:userHandleBase64 options:NSDataBase64DecodingIgnoreUnknownCharacters]).get(), 360 (id)kSecAttrAccessible: (id)kSecAttrAccessibleAfterFirstUnlock, 361 #if HAVE(DATA_PROTECTION_KEYCHAIN) 362 (id)kSecUseDataProtectionKeychain: @YES 363 #else 364 (id)kSecAttrNoLegacy: @YES 365 #endif 366 }; 367 OSStatus status = SecItemAdd((__bridge CFDictionaryRef)addQuery, NULL); 368 if (status) 369 return false; 370 371 return true; 372 } 373 374 void cleanUpKeychain(const String& rpId) 375 { 376 NSDictionary* deleteQuery = @{ 377 (id)kSecClass: (id)kSecClassKey, 378 (id)kSecAttrLabel: rpId, 379 (id)kSecAttrAccessible: (id)kSecAttrAccessibleAfterFirstUnlock, 380 #if HAVE(DATA_PROTECTION_KEYCHAIN) 381 (id)kSecUseDataProtectionKeychain: @YES 382 #else 383 (id)kSecAttrNoLegacy: @YES 384 #endif 385 }; 386 SecItemDelete((__bridge CFDictionaryRef)deleteQuery); 387 } 388 389 #endif // USE(APPLE_INTERNAL_SDK) || PLATFORM(IOS) 279 390 280 391 } // namesapce; … … 1077 1188 } 1078 1189 1190 // For macOS, only internal builds can sign keychain entitlemnets 1191 // which are required to run local authenticator tests. 1192 #if USE(APPLE_INTERNAL_SDK) || PLATFORM(IOS) 1193 1194 TEST(WebAuthenticationPanel, LAError) 1195 { 1196 reset(); 1197 RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-la-error" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; 1198 1199 auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; 1200 [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()]; 1201 [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationLocalAuthenticatorExperimentalFeature()]; 1202 1203 auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]); 1204 auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]); 1205 [webView setUIDelegate:delegate.get()]; 1206 1207 [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]]; 1208 Util::run(&webAuthenticationPanelUpdateLAError); 1209 } 1210 1211 TEST(WebAuthenticationPanel, LADuplicateCredential) 1212 { 1213 reset(); 1214 RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-la-duplicate-credential" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; 1215 1216 auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; 1217 [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()]; 1218 [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationLocalAuthenticatorExperimentalFeature()]; 1219 1220 auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]); 1221 auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]); 1222 [webView setUIDelegate:delegate.get()]; 1223 1224 ASSERT_TRUE(addKeyToKeychain(testES256PrivateKeyBase64, "", testUserhandleBase64)); 1225 [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]]; 1226 Util::run(&webAuthenticationPanelUpdateLAExcludeCredentialsMatched); 1227 cleanUpKeychain(""); 1228 } 1229 1230 TEST(WebAuthenticationPanel, LANoCredential) 1231 { 1232 reset(); 1233 RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-la" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; 1234 1235 auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; 1236 [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()]; 1237 [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationLocalAuthenticatorExperimentalFeature()]; 1238 1239 auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]); 1240 auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]); 1241 [webView setUIDelegate:delegate.get()]; 1242 1243 [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]]; 1244 Util::run(&webAuthenticationPanelUpdateLANoCredential); 1245 } 1246 1247 TEST(WebAuthenticationPanel, LAMakeCredentialNullDelegate) 1248 { 1249 reset(); 1250 RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-la" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; 1251 1252 auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; 1253 [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()]; 1254 [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationLocalAuthenticatorExperimentalFeature()]; 1255 1256 auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]); 1257 auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]); 1258 [delegate setIsNull:true]; 1259 [webView setUIDelegate:delegate.get()]; 1260 1261 [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]]; 1262 [webView waitForMessage:@"Succeeded!"]; 1263 cleanUpKeychain(""); 1264 } 1265 1266 TEST(WebAuthenticationPanel, LAMakeCredential) 1267 { 1268 reset(); 1269 RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-la" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; 1270 1271 auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; 1272 [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()]; 1273 [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationLocalAuthenticatorExperimentalFeature()]; 1274 1275 auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]); 1276 auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]); 1277 [webView setUIDelegate:delegate.get()]; 1278 1279 [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]]; 1280 Util::run(&webAuthenticationPanelVerifyUser); 1281 checkPanel([delegate panel], @"", @[adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportUSB]).get(), adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportInternal]).get()], _WKWebAuthenticationTypeCreate); 1282 [webView waitForMessage:@"Succeeded!"]; 1283 } 1284 1285 TEST(WebAuthenticationPanel, LAGetAssertion) 1286 { 1287 reset(); 1288 RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-la" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; 1289 1290 auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; 1291 [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()]; 1292 [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationLocalAuthenticatorExperimentalFeature()]; 1293 1294 auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]); 1295 auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]); 1296 [webView setUIDelegate:delegate.get()]; 1297 1298 ASSERT_TRUE(addKeyToKeychain(testES256PrivateKeyBase64, "", testUserhandleBase64)); 1299 [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]]; 1300 Util::run(&webAuthenticationPanelVerifyUser); 1301 checkPanel([delegate panel], @"", @[adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportUSB]).get(), adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportInternal]).get()], _WKWebAuthenticationTypeGet); 1302 [webView waitForMessage:@"Succeeded!"]; 1303 cleanUpKeychain(""); 1304 } 1305 1306 #endif // USE(APPLE_INTERNAL_SDK) || PLATFORM(IOS) 1307 1079 1308 } // namespace TestWebKitAPI 1080 1309
Note: See TracChangeset
for help on using the changeset viewer.