Changeset 260970 in webkit
- Timestamp:
- Apr 30, 2020 3:27:02 PM (4 years ago)
- Location:
- trunk
- Files:
-
- 18 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r260969 r260970 1 2020-04-30 Jiewen Tan <jiewen_tan@apple.com> 2 3 [WebAuthn] Optimize LocalAuthenticator 4 https://bugs.webkit.org/show_bug.cgi?id=183534 5 <rdar://problem/43357408> 6 7 Reviewed by Brent Fulgham. 8 9 Covered by new API tests. 10 11 * en.lproj/Localizable.strings: 12 * platform/LocalizedStrings.cpp: 13 (WebCore::getAssertionTouchIDPromptTitle): 14 (WebCore::genericTouchIDPromptTitle): 15 * platform/LocalizedStrings.h: 16 Improving the LocalAuthentication dialog titles for iOS. 17 1 18 2020-04-30 Kate Cheney <katherine_cheney@apple.com> 2 19 -
trunk/Source/WebCore/en.lproj/Localizable.strings
r258961 r260970 233 233 "Continue" = "Continue"; 234 234 235 /* Continue with Touch ID */ 236 "Continue with Touch ID." = "Continue with Touch ID."; 237 235 238 /* Media Controls context menu item */ 236 239 "Controls" = "Controls"; … … 869 872 "This website may try to trick you into installing software that harms your browsing experience, like changing your settings without your permission or showing you unwanted ads. Once installed, it may be difficult to remove." = "This website may try to trick you into installing software that harms your browsing experience, like changing your settings without your permission or showing you unwanted ads. Once installed, it may be difficult to remove."; 870 873 871 /* This website would like to use Touch ID */872 "This website would like to use Touch ID." = "This website would like to use Touch ID.";873 874 874 /* Informative text for requesting cross-site cookie and website data access. */ 875 875 "This will allow “%@” to track your activity." = "This will allow “%@” to track your activity."; … … 890 890 "To view this page, you must log in to this area on %@:" = "To view this page, you must log in to this area on %@:"; 891 891 892 /* Use Touch ID to sign in to this website */893 "Touch ID to sign in to this website." = "Touch ID to sign in to this website.";894 895 892 /* Transformations context sub-menu item */ 896 893 "Transformations" = "Transformations"; -
trunk/Source/WebCore/platform/LocalizedStrings.cpp
r258961 r260970 1211 1211 // On macOS, Touch ID prompt is not guaranteed to show on top of the UI client, and therefore additional 1212 1212 // information is provided to help users to make decisions. 1213 #if PLATFORM(MAC)1214 1213 String makeCredentialTouchIDPromptTitle(const String& bundleName, const String& domain) 1215 1214 { … … 1221 1220 return formatLocalizedString(WEB_UI_CFSTRING("“%@” would like to sign in to “%@”.", "Allow the specified bundle to sign in to the specified website"), bundleName.createCFString().get(), domain.createCFString().get()); 1222 1221 } 1223 #else 1224 String makeCredentialTouchIDPromptTitle(const String&, const String&) 1225 { 1226 return WEB_UI_STRING("This website would like to use Touch ID.", "This website would like to use Touch ID"); 1227 } 1228 1229 String getAssertionTouchIDPromptTitle(const String&, const String&) 1230 { 1231 return WEB_UI_STRING("Touch ID to sign in to this website.", "Use Touch ID to sign in to this website"); 1232 } 1233 #endif // PLATFORM(MAC) 1222 1223 String genericTouchIDPromptTitle() 1224 { 1225 return WEB_UI_STRING("Continue with Touch ID.", "Continue with Touch ID."); 1226 } 1234 1227 #endif // ENABLE(WEB_AUTHN) 1235 1228 -
trunk/Source/WebCore/platform/LocalizedStrings.h
r258961 r260970 343 343 WEBCORE_EXPORT String makeCredentialTouchIDPromptTitle(const String& bundleName, const String& domain); 344 344 WEBCORE_EXPORT String getAssertionTouchIDPromptTitle(const String& bundleName, const String& domain); 345 WEBCORE_EXPORT String genericTouchIDPromptTitle(); 345 346 #endif 346 347 -
trunk/Source/WebKit/ChangeLog
r260968 r260970 1 2020-04-30 Jiewen Tan <jiewen_tan@apple.com> 2 3 [WebAuthn] Optimize LocalAuthenticator 4 https://bugs.webkit.org/show_bug.cgi?id=183534 5 <rdar://problem/43357408> 6 7 Reviewed by Brent Fulgham. 8 9 This patch implements the following small optimizations: 10 1. Replacing local constants with ones from FidoConstants.h; 11 2. Merging m_assertionResponses and m_existingCredentials by replacing HashSet with Vector in Authenticator::Observer::selectAssertionResponse; 12 3. Using Base64 encoded strings as the keys of the HashSet in produceHashSet() instead of the old casting hack; 13 4. Invaliding the LAContext in LocalConnection::~LocalConnection() such that any displaying LocalAuthentication dialogs can be dismissed after the object is destroyed; 14 5. Sorting existing credentials according to LRU before returning to UI clients; 15 6. Improving the LocalAuthentication dialog titles for iOS. 16 17 * UIProcess/WebAuthentication/Authenticator.h: 18 * UIProcess/WebAuthentication/AuthenticatorManager.cpp: 19 (WebKit::AuthenticatorManager::selectAssertionResponse): 20 * UIProcess/WebAuthentication/AuthenticatorManager.h: 21 * UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.h: 22 * UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm: 23 (WebKit::LocalAuthenticatorInternal::produceHashSet): 24 (WebKit::LocalAuthenticatorInternal::toNSData): 25 (WebKit::LocalAuthenticatorInternal::getExistingCredentials): 26 (WebKit::LocalAuthenticator::makeCredential): 27 (WebKit::LocalAuthenticator::continueMakeCredentialAfterUserVerification): 28 (WebKit::LocalAuthenticator::getAssertion): 29 (WebKit::LocalAuthenticator::continueGetAssertionAfterUserVerification): 30 * UIProcess/WebAuthentication/Cocoa/LocalConnection.h: 31 (WebKit::LocalConnection::filterResponses const): 32 * UIProcess/WebAuthentication/Cocoa/LocalConnection.mm: 33 (WebKit::WebCore::bundleName): 34 (WebKit::LocalConnection::~LocalConnection): 35 (WebKit::LocalConnection::verifyUser): 36 (WebKit::LocalConnection::verifyUser const): Deleted. 37 * UIProcess/WebAuthentication/Mock/MockLocalConnection.h: 38 * UIProcess/WebAuthentication/Mock/MockLocalConnection.mm: 39 (WebKit::MockLocalConnection::verifyUser): 40 (WebKit::MockLocalConnection::filterResponses const): 41 (WebKit::MockLocalConnection::verifyUser const): Deleted. 42 * UIProcess/WebAuthentication/fido/CtapAuthenticator.cpp: 43 (WebKit::CtapAuthenticator::continueGetAssertionAfterResponseReceived): 44 (WebKit::CtapAuthenticator::continueGetNextAssertionAfterResponseReceived): 45 * UIProcess/WebAuthentication/fido/CtapAuthenticator.h: 46 1 47 2020-04-30 Kate Cheney <katherine_cheney@apple.com> 2 48 -
trunk/Source/WebKit/UIProcess/WebAuthentication/Authenticator.h
r259680 r260970 56 56 virtual void authenticatorStatusUpdated(WebAuthenticationStatus) = 0; 57 57 virtual void requestPin(uint64_t retries, CompletionHandler<void(const WTF::String&)>&&) = 0; 58 virtual void selectAssertionResponse( const HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>&, WebAuthenticationSource, CompletionHandler<void(WebCore::AuthenticatorAssertionResponse*)>&&) = 0;58 virtual void selectAssertionResponse(Vector<Ref<WebCore::AuthenticatorAssertionResponse>>&&, WebAuthenticationSource, CompletionHandler<void(WebCore::AuthenticatorAssertionResponse*)>&&) = 0; 59 59 virtual void decidePolicyForLocalAuthenticator(CompletionHandler<void(LocalAuthenticatorPolicy)>&&) = 0; 60 60 virtual void cancelRequest() = 0; -
trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp
r260182 r260970 274 274 } 275 275 276 void AuthenticatorManager::selectAssertionResponse(const HashSet<Ref<AuthenticatorAssertionResponse>>& responses, WebAuthenticationSource source, CompletionHandler<void(AuthenticatorAssertionResponse*)>&& completionHandler) 277 { 278 Vector<Ref<AuthenticatorAssertionResponse>> responseVector; 279 responseVector.reserveInitialCapacity(responses.size()); 280 for (auto& response : responses) 281 responseVector.uncheckedAppend(response.copyRef()); 282 283 dispatchPanelClientCall([responses = WTFMove(responseVector), source, completionHandler = WTFMove(completionHandler)] (const API::WebAuthenticationPanel& panel) mutable { 276 void AuthenticatorManager::selectAssertionResponse(Vector<Ref<WebCore::AuthenticatorAssertionResponse>>&& responses, WebAuthenticationSource source, CompletionHandler<void(AuthenticatorAssertionResponse*)>&& completionHandler) 277 { 278 dispatchPanelClientCall([responses = WTFMove(responses), source, completionHandler = WTFMove(completionHandler)] (const API::WebAuthenticationPanel& panel) mutable { 284 279 panel.client().selectAssertionResponse(WTFMove(responses), source, WTFMove(completionHandler)); 285 280 }); -
trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h
r259680 r260970 83 83 void authenticatorStatusUpdated(WebAuthenticationStatus) final; 84 84 void requestPin(uint64_t retries, CompletionHandler<void(const WTF::String&)>&&) final; 85 void selectAssertionResponse( const HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>&, WebAuthenticationSource, CompletionHandler<void(WebCore::AuthenticatorAssertionResponse*)>&&) final;85 void selectAssertionResponse(Vector<Ref<WebCore::AuthenticatorAssertionResponse>>&&, WebAuthenticationSource, CompletionHandler<void(WebCore::AuthenticatorAssertionResponse*)>&&) final; 86 86 void decidePolicyForLocalAuthenticator(CompletionHandler<void(LocalAuthenticatorPolicy)>&&) final; 87 87 void cancelRequest() final; -
trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.h
r259680 r260970 73 73 State m_state { State::Init }; 74 74 UniqueRef<LocalConnection> m_connection; 75 // FIXME(183534): Combine these two.76 HashSet<Ref<WebCore::AuthenticatorAssertionResponse>> m_assertionResponses;77 75 Vector<Ref<WebCore::AuthenticatorAssertionResponse>> m_existingCredentials; 78 76 }; -
trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm
r260366 r260970 35 35 #import <WebCore/CBORWriter.h> 36 36 #import <WebCore/ExceptionData.h> 37 #import <WebCore/FidoConstants.h> 37 38 #import <WebCore/PublicKeyCredentialCreationOptions.h> 38 39 #import <WebCore/PublicKeyCredentialRequestOptions.h> … … 40 41 #import <WebCore/WebAuthenticationUtils.h> 41 42 #import <pal/crypto/CryptoDigest.h> 42 #import <wtf/HashSet.h>43 43 #import <wtf/RetainPtr.h> 44 44 #import <wtf/RunLoop.h> 45 45 #import <wtf/Vector.h> 46 46 #import <wtf/spi/cocoa/SecuritySPI.h> 47 #import <wtf/text/Base64.h> 47 48 #import <wtf/text/StringHash.h> 48 49 … … 58 59 // Credential ID is currently SHA-1 of the corresponding public key. 59 60 const uint16_t credentialIdLength = 20; 60 const char* const userEntityIdKey = "id";61 const char* const userEntityNameKey = "name";62 61 const uint64_t counter = 0; 63 62 … … 67 66 } 68 67 69 // FIXME(183534): Find a better way of comparing credential id. Doing it with array seems fine given the list should be small.68 // A Base64 encoded string of the Credential ID is used as the key of the hash set. 70 69 static inline HashSet<String> produceHashSet(const Vector<PublicKeyCredentialDescriptor>& credentialDescriptors) 71 70 { … … 75 74 && credentialDescriptor.type == PublicKeyCredentialType::PublicKey 76 75 && credentialDescriptor.idVector.size() == credentialIdLength) 77 result.add( String(reinterpret_cast<const char*>(credentialDescriptor.idVector.data()), credentialDescriptor.idVector.size()));76 result.add(base64Encode(credentialDescriptor.idVector.data(), credentialDescriptor.idVector.size())); 78 77 } 79 78 return result; … … 89 88 static inline RetainPtr<NSData> toNSData(const Vector<uint8_t>& data) 90 89 { 91 // FIXME(183534): Consider using initWithBytesNoCopy.92 90 return adoptNS([[NSData alloc] initWithBytes:data.data() length:data.size()]); 93 91 } … … 96 94 { 97 95 ASSERT(buffer); 98 // FIXME(183534): Consider using initWithBytesNoCopy.99 96 return adoptNS([[NSData alloc] initWithBytes:buffer->data() length:buffer->byteLength()]); 100 97 } … … 141 138 return WTF::nullopt; 142 139 auto retainAttributesArray = adoptCF(attributesArrayRef); 143 NSArray *nsAttributesArray = (NSArray *)attributesArrayRef; 140 NSArray *sortedAttributesArray = [(NSArray *)attributesArrayRef sortedArrayUsingComparator:^(NSDictionary *a, NSDictionary *b) { 141 return [b[(id)kSecAttrModificationDate] compare:a[(id)kSecAttrModificationDate]]; 142 }]; 144 143 145 144 Vector<Ref<AuthenticatorAssertionResponse>> result; 146 result.reserveInitialCapacity( nsAttributesArray.count);147 for (NSDictionary *attributes in nsAttributesArray) {145 result.reserveInitialCapacity(sortedAttributesArray.count); 146 for (NSDictionary *attributes in sortedAttributesArray) { 148 147 auto decodedResponse = cbor::CBORReader::read(toVector(attributes[(id)kSecAttrApplicationTag])); 149 148 if (!decodedResponse || !decodedResponse->isMap()) { … … 153 152 auto& responseMap = decodedResponse->getMap(); 154 153 155 auto it = responseMap.find(CBOR( userEntityIdKey));154 auto it = responseMap.find(CBOR(kEntityIdMapKey)); 156 155 if (it == responseMap.end() || !it->second.isByteString()) { 157 156 ASSERT_NOT_REACHED(); … … 160 159 auto& userHandle = it->second.getByteString(); 161 160 162 it = responseMap.find(CBOR( userEntityNameKey));161 it = responseMap.find(CBOR(kEntityNameMapKey)); 163 162 if (it == responseMap.end() || !it->second.isString()) { 164 163 ASSERT_NOT_REACHED(); … … 212 211 auto* rawId = credential->rawId(); 213 212 ASSERT(rawId); 214 return excludeCredentialIds.contains( String(reinterpret_cast<const char*>(rawId->data()), rawId->byteLength()));213 return excludeCredentialIds.contains(base64Encode(rawId->data(), rawId->byteLength())); 215 214 })) { 216 215 receiveException({ NotAllowedError, "At least one credential matches an entry of the excludeCredentials list in the platform attached authenticator."_s }, WebAuthenticationStatus::LAExcludeCredentialsMatched); … … 287 286 288 287 cbor::CBORValue::MapValue userEntityMap; 289 userEntityMap[cbor::CBORValue( userEntityIdKey)] = cbor::CBORValue(creationOptions.user.idVector);290 userEntityMap[cbor::CBORValue( userEntityNameKey)] = cbor::CBORValue(creationOptions.user.name);288 userEntityMap[cbor::CBORValue(kEntityIdMapKey)] = cbor::CBORValue(creationOptions.user.idVector); 289 userEntityMap[cbor::CBORValue(kEntityNameMapKey)] = cbor::CBORValue(creationOptions.user.name); 291 290 auto userEntity = cbor::CBORWriter::write(cbor::CBORValue(WTFMove(userEntityMap))); 292 291 ASSERT(userEntity); … … 436 435 m_existingCredentials = WTFMove(*existingCredentials); 437 436 437 Vector<Ref<WebCore::AuthenticatorAssertionResponse>> assertionResponses; 438 assertionResponses.reserveInitialCapacity(m_existingCredentials.size()); 438 439 for (auto& credential : m_existingCredentials) { 439 440 if (allowCredentialIds.isEmpty()) { 440 auto addResult = m_assertionResponses.add(credential.copyRef()); 441 ASSERT_UNUSED(addResult, addResult.isNewEntry); 441 assertionResponses.uncheckedAppend(credential.copyRef()); 442 442 continue; 443 443 } 444 444 445 445 auto* rawId = credential->rawId(); 446 if (allowCredentialIds.contains(String(reinterpret_cast<const char*>(rawId->data()), rawId->byteLength()))) { 447 auto addResult = m_assertionResponses.add(credential.copyRef()); 448 ASSERT_UNUSED(addResult, addResult.isNewEntry); 449 } 450 } 451 if (m_assertionResponses.isEmpty()) { 446 if (allowCredentialIds.contains(base64Encode(rawId->data(), rawId->byteLength()))) 447 assertionResponses.uncheckedAppend(credential.copyRef()); 448 } 449 if (assertionResponses.isEmpty()) { 452 450 receiveException({ NotAllowedError, "No matched credentials are found in the platform attached authenticator."_s }, WebAuthenticationStatus::LANoCredential); 453 451 return; … … 455 453 456 454 // Step 6-7. User consent is implicitly acquired by selecting responses. 457 m_connection->filterResponses( m_assertionResponses);455 m_connection->filterResponses(assertionResponses); 458 456 459 457 if (auto* observer = this->observer()) { … … 463 461 return; 464 462 465 auto returnResponse = m_assertionResponses.take(response); 466 if (!returnResponse) 463 auto result = m_existingCredentials.findMatching([expectedResponse = response] (auto& response) { 464 return response.ptr() == expectedResponse; 465 }); 466 if (result == notFound) 467 467 return; 468 continueGetAssertionAfterResponseSelected( WTFMove(*returnResponse));468 continueGetAssertionAfterResponseSelected(m_existingCredentials[result].copyRef()); 469 469 }; 470 observer->selectAssertionResponse( m_assertionResponses, WebAuthenticationSource::Local, WTFMove(callback));470 observer->selectAssertionResponse(WTFMove(assertionResponses), WebAuthenticationSource::Local, WTFMove(callback)); 471 471 } 472 472 } … … 503 503 504 504 // Step 10. 505 auto authData = buildAuthData(WTF::get<PublicKeyCredentialRequestOptions>(requestData().options).rpId, getAssertionFlags, counter, { }); 505 auto requestOptions = WTF::get<PublicKeyCredentialRequestOptions>(requestData().options); 506 auto authData = buildAuthData(requestOptions.rpId, getAssertionFlags, counter, { }); 506 507 507 508 // Step 11. 508 509 RetainPtr<CFDataRef> signature; 510 auto nsCredentialId = toNSData(response->rawId()); 509 511 { 510 512 NSDictionary *query = @{ 511 513 (id)kSecClass: (id)kSecClassKey, 512 514 (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate, 513 (id)kSecAttrApplicationLabel: toNSData(response->rawId()).get(),515 (id)kSecAttrApplicationLabel: nsCredentialId.get(), 514 516 (id)kSecUseAuthenticationContext: context, 515 517 (id)kSecReturnRef: @YES, … … 545 547 response->setSignature(toArrayBuffer((NSData *)signature.get())); 546 548 receiveRespond(WTFMove(response)); 549 550 // Extra step: update the Keychain item with the same value to update its modification date such that LRU can be used 551 // for selectAssertionResponse 552 NSDictionary *updateQuery = @{ 553 (id)kSecClass: (id)kSecClassKey, 554 (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate, 555 (id)kSecAttrApplicationLabel: nsCredentialId.get(), 556 #if HAVE(DATA_PROTECTION_KEYCHAIN) 557 (id)kSecUseDataProtectionKeychain: @YES 558 #else 559 (id)kSecAttrNoLegacy: @YES 560 #endif 561 }; 562 NSDictionary *updateParams = @{ 563 (id)kSecAttrLabel: requestOptions.rpId, 564 }; 565 auto status = SecItemUpdate((__bridge CFDictionaryRef)updateQuery, (__bridge CFDictionaryRef)updateParams); 566 if (status) 567 LOG_ERROR("Couldn't update the Keychain item: %d", status); 547 568 } 548 569 -
trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalConnection.h
r259680 r260970 62 62 63 63 LocalConnection() = default; 64 // FIXME(183534): Invalidate the LAContext. 65 virtual ~LocalConnection() = default; 64 virtual ~LocalConnection(); 66 65 67 66 // Overrided by MockLocalConnection. 68 virtual void verifyUser(const String& rpId, WebCore::ClientDataType, SecAccessControlRef, UserVerificationCallback&&) const;67 virtual void verifyUser(const String& rpId, WebCore::ClientDataType, SecAccessControlRef, UserVerificationCallback&&); 69 68 virtual RetainPtr<SecKeyRef> createCredentialPrivateKey(LAContext *, SecAccessControlRef, const String& secAttrLabel, NSData *secAttrApplicationTag) const; 70 69 virtual void getAttestation(SecKeyRef, NSData *authData, NSData *hash, AttestationCallback&&) const; 71 virtual void filterResponses(HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>&) const { }; 70 virtual void filterResponses(Vector<Ref<WebCore::AuthenticatorAssertionResponse>>&) const { }; 71 72 private: 73 RetainPtr<LAContext> m_context; 72 74 }; 73 75 -
trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalConnection.mm
r259680 r260970 43 43 44 44 namespace { 45 static String bundleName() 45 #if PLATFORM(MAC) 46 static inline String bundleName() 46 47 { 47 String bundleName; 48 49 #if PLATFORM(MAC) 50 bundleName = [[NSRunningApplication currentApplication] localizedName]; 48 return [[NSRunningApplication currentApplication] localizedName]; 49 } 51 50 #endif 52 53 return bundleName;54 }55 51 } // namespace 56 52 57 void LocalConnection::verifyUser(const String& rpId, ClientDataType type, SecAccessControlRef accessControl, UserVerificationCallback&& completionHandler) const 53 LocalConnection::~LocalConnection() 58 54 { 59 String title; 55 // Dismiss any showing LocalAuthentication dialogs. 56 [m_context invalidate]; 57 } 58 59 void LocalConnection::verifyUser(const String& rpId, ClientDataType type, SecAccessControlRef accessControl, UserVerificationCallback&& completionHandler) 60 { 61 String title = genericTouchIDPromptTitle(); 62 #if PLATFORM(MAC) 60 63 switch (type) { 61 64 case ClientDataType::Create: … … 68 71 ASSERT_NOT_REACHED(); 69 72 } 73 #endif 70 74 71 auto context = adoptNS([allocLAContextInstance() init]);75 m_context = [allocLAContextInstance() init]; 72 76 73 77 auto options = adoptNS([[NSMutableDictionary alloc] init]); 74 if ([ context biometryType] == LABiometryTypeTouchID) {78 if ([m_context biometryType] == LABiometryTypeTouchID) { 75 79 [options setObject:title forKey:@(LAOptionAuthenticationTitle)]; 76 80 [options setObject:@NO forKey:@(LAOptionFallbackVisible)]; 77 81 } 78 82 79 auto reply = makeBlockPtr([context, completionHandler = WTFMove(completionHandler)] (NSDictionary *, NSError *error) mutable { 80 ASSERT(!RunLoop::isMain()); 81 83 auto reply = makeBlockPtr([context = m_context, completionHandler = WTFMove(completionHandler)] (NSDictionary *, NSError *error) mutable { 82 84 UserVerification verification = UserVerification::Yes; 83 85 if (error) { … … 87 89 verification = UserVerification::Cancel; 88 90 } 91 92 // This block can be executed in another thread. 89 93 RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), verification, context = WTFMove(context)] () mutable { 90 94 completionHandler(verification, context.get()); … … 92 96 }); 93 97 94 [ context evaluateAccessControl:accessControl operation:LAAccessControlOperationUseKeySign options:options.get() reply:reply.get()];98 [m_context evaluateAccessControl:accessControl operation:LAAccessControlOperationUseKeySign options:options.get() reply:reply.get()]; 95 99 } 96 100 -
trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.h
r258961 r260970 38 38 39 39 private: 40 void verifyUser(const String&, WebCore::ClientDataType, SecAccessControlRef, UserVerificationCallback&&) constfinal;40 void verifyUser(const String&, WebCore::ClientDataType, SecAccessControlRef, UserVerificationCallback&&) 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 void filterResponses( HashSet<Ref<WebCore::AuthenticatorAssertionResponse>>&) const final;43 void filterResponses(Vector<Ref<WebCore::AuthenticatorAssertionResponse>>&) const final; 44 44 45 45 WebCore::MockWebAuthenticationConfiguration m_configuration; -
trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.mm
r260182 r260970 32 32 #import <WebCore/AuthenticatorAssertionResponse.h> 33 33 #import <WebCore/ExceptionData.h> 34 #import <wtf/HashSet.h>35 34 #import <wtf/RunLoop.h> 36 35 #import <wtf/spi/cocoa/SecuritySPI.h> … … 48 47 } 49 48 50 void MockLocalConnection::verifyUser(const String&, ClientDataType, SecAccessControlRef, UserVerificationCallback&& callback) const49 void MockLocalConnection::verifyUser(const String&, ClientDataType, SecAccessControlRef, UserVerificationCallback&& callback) 51 50 { 52 51 // Mock async operations. … … 125 124 } 126 125 127 void MockLocalConnection::filterResponses( HashSet<Ref<AuthenticatorAssertionResponse>>& responses) const126 void MockLocalConnection::filterResponses(Vector<Ref<AuthenticatorAssertionResponse>>& responses) const 128 127 { 129 128 const auto& preferredCredentialIdBase64 = m_configuration.local->preferredCredentialIdBase64; … … 139 138 break; 140 139 } 141 auto response = responses.take(itr); 142 ASSERT(response); 140 auto response = itr->copyRef(); 143 141 responses.clear(); 144 responses.a dd(WTFMove(*response));142 responses.append(WTFMove(response)); 145 143 } 146 144 -
trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.cpp
r257954 r260970 174 174 175 175 m_remainingAssertionResponses = response->numberOfCredentials() - 1; 176 auto addResult = m_assertionResponses.add(response.releaseNonNull());177 ASSERT_UNUSED(addResult, addResult.isNewEntry);176 m_assertionResponses.reserveInitialCapacity(response->numberOfCredentials()); 177 m_assertionResponses.uncheckedAppend(response.releaseNonNull()); 178 178 driver().transact(encodeEmptyAuthenticatorRequest(CtapRequestCommand::kAuthenticatorGetNextAssertion), [weakThis = makeWeakPtr(*this)](Vector<uint8_t>&& data) { 179 179 ASSERT(RunLoop::isMain()); … … 193 193 } 194 194 m_remainingAssertionResponses--; 195 auto addResult = m_assertionResponses.add(response.releaseNonNull()); 196 ASSERT_UNUSED(addResult, addResult.isNewEntry); 195 m_assertionResponses.uncheckedAppend(response.releaseNonNull()); 197 196 198 197 if (!m_remainingAssertionResponses) { 199 198 if (auto* observer = this->observer()) { 200 observer->selectAssertionResponse(m_assertionResponses, WebAuthenticationSource::External, [this, weakThis = makeWeakPtr(*this)] (AuthenticatorAssertionResponse* response) { 199 Vector<Ref<AuthenticatorAssertionResponse>> responsesCopy; 200 responsesCopy.reserveInitialCapacity(m_assertionResponses.size()); 201 for (auto& response : m_assertionResponses) 202 responsesCopy.uncheckedAppend(response.copyRef()); 203 204 observer->selectAssertionResponse(WTFMove(responsesCopy), WebAuthenticationSource::External, [this, weakThis = makeWeakPtr(*this)] (AuthenticatorAssertionResponse* response) { 201 205 ASSERT(RunLoop::isMain()); 202 206 if (!weakThis) 203 207 return; 204 auto returnResponse = m_assertionResponses.take(response); 205 if (!returnResponse) 208 auto result = m_assertionResponses.findMatching([expectedResponse = response] (auto& response) { 209 return response.ptr() == expectedResponse; 210 }); 211 if (result == notFound) 206 212 return; 207 receiveRespond( WTFMove(*returnResponse));213 receiveRespond(m_assertionResponses[result].copyRef()); 208 214 }); 209 215 } -
trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.h
r256062 r260970 74 74 bool m_isDowngraded { false }; 75 75 size_t m_remainingAssertionResponses { 0 }; 76 HashSet<Ref<WebCore::AuthenticatorAssertionResponse>> m_assertionResponses;76 Vector<Ref<WebCore::AuthenticatorAssertionResponse>> m_assertionResponses; 77 77 Vector<uint8_t> m_pinAuth; 78 78 }; -
trunk/Tools/ChangeLog
r260968 r260970 1 2020-04-30 Jiewen Tan <jiewen_tan@apple.com> 2 3 [WebAuthn] Optimize LocalAuthenticator 4 https://bugs.webkit.org/show_bug.cgi?id=183534 5 <rdar://problem/43357408> 6 7 Reviewed by Brent Fulgham. 8 9 * TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm: 10 (-[TestWebAuthenticationPanelDelegate panel:selectAssertionResponse:source:completionHandler:]): 11 (TestWebKitAPI::TEST): 12 Adds a new test case for the LRU. 13 1 14 2020-04-30 Kate Cheney <katherine_cheney@apple.com> 2 15 -
trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm
r260554 r260970 63 63 "PH76c0+WFOzZKslPyyFse4goGIW2R7k9VHLPEZl5nfnBgEVFh5zev+/xpHQIvuq6" 64 64 "RQ=="; 65 static String testUserEntityBundleBase64 = "omJpZEoAAQIDBAUGBwgJZG5hbWVwQUFFQ0F3UUZCZ2NJQ1E9PQ=="; 65 static String testUserEntityBundleBase64 = "omJpZEoAAQIDBAUGBwgJZG5hbWVkSm9obg=="; // { "id": h'00010203040506070809', "name": "John" } 66 static String webAuthenticationPanelSelectedCredentialName; 66 67 67 68 @interface TestWebAuthenticationPanelDelegate : NSObject <_WKWebAuthenticationPanelDelegate> … … 137 138 if (responses.count == 1) { 138 139 completionHandler(responses[0]); 140 return; 141 } 142 143 // Responses returned from LocalAuthenticator is in the order of LRU. Therefore, we use the last item to populate it to 144 // the first to test its correctness. 145 if (source == _WKWebAuthenticationSourceLocal) { 146 webAuthenticationPanelSelectedCredentialName = responses.lastObject.name; 147 completionHandler(responses.lastObject); 139 148 return; 140 149 } … … 301 310 webAuthenticationPanelNullUserHandle = NO; 302 311 localAuthenticatorPolicy = _WKLocalAuthenticatorPolicyDisallow; 312 webAuthenticationPanelSelectedCredentialName = emptyString(); 303 313 } 304 314 … … 1295 1305 // Skip the test because of <rdar://problem/59635486>. 1296 1306 #if PLATFORM(MAC) 1307 1297 1308 TEST(WebAuthenticationPanel, LAGetAssertion) 1298 1309 { … … 1314 1325 cleanUpKeychain(""); 1315 1326 } 1327 1328 TEST(WebAuthenticationPanel, LAGetAssertionMultipleOrder) 1329 { 1330 reset(); 1331 RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-la" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; 1332 1333 auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; 1334 [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()]; 1335 [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationLocalAuthenticatorExperimentalFeature()]; 1336 1337 auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]); 1338 auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]); 1339 [webView setUIDelegate:delegate.get()]; 1340 1341 ASSERT_TRUE(addKeyToKeychain(testES256PrivateKeyBase64, "", testUserEntityBundleBase64)); 1342 ASSERT_TRUE(addKeyToKeychain("BBRoi2JbR0IXTeJmvXUp1YIuM4sph/Lu3eGf75F7n+HojHKG70a4R0rB2PQce5/SJle6T7OO5Cqet/LJZVM6NQ8yDDxWvayf71GTDp2yUtuIbqJLFVbpWymlj9WRizgX3A==", "", "omJpZEoAAQIDBAUGBwgJZG5hbWVkSmFuZQ=="/* { "id": h'00010203040506070809', "name": "Jane" } */)); 1343 1344 [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]]; 1345 [webView waitForMessage:@"Succeeded!"]; 1346 EXPECT_WK_STREQ(webAuthenticationPanelSelectedCredentialName, "John"); 1347 1348 [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]]; 1349 [webView waitForMessage:@"Succeeded!"]; 1350 EXPECT_WK_STREQ(webAuthenticationPanelSelectedCredentialName, "Jane"); 1351 1352 cleanUpKeychain(""); 1353 } 1354 1316 1355 #endif 1317 1356
Note: See TracChangeset
for help on using the changeset viewer.