[WebAuthn] Provide a _WKWebAuthenticationPanelUpdatePINInvalid update to UI clients...
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebKitCocoa / _WKWebAuthenticationPanel.mm
1 /*
2  * Copyright (C) 2019 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "Test.h"
28
29 #if ENABLE(WEB_AUTHN)
30
31 #import "PlatformUtilities.h"
32 #import "TCPServer.h"
33 #import "TestWKWebView.h"
34 #import "WKWebViewConfigurationExtras.h"
35 #import <LocalAuthentication/LocalAuthentication.h>
36 #import <WebKit/WKPreferencesPrivate.h>
37 #import <WebKit/WKUIDelegatePrivate.h>
38 #import <WebKit/_WKExperimentalFeature.h>
39 #import <WebKit/_WKWebAuthenticationAssertionResponse.h>
40 #import <WebKit/_WKWebAuthenticationPanel.h>
41 #import <wtf/BlockPtr.h>
42 #import <wtf/RandomNumber.h>
43 #import <wtf/spi/cocoa/SecuritySPI.h>
44 #import <wtf/text/StringConcatenateNumbers.h>
45
46 static bool webAuthenticationPanelRan = false;
47 static bool webAuthenticationPanelFailed = false;
48 static bool webAuthenticationPanelSucceded = false;
49 static bool webAuthenticationPanelUpdateMultipleNFCTagsPresent = false;
50 static bool webAuthenticationPanelUpdateNoCredentialsFound = false;
51 static bool webAuthenticationPanelUpdatePINBlocked = false;
52 static bool webAuthenticationPanelUpdatePINAuthBlocked = false;
53 static bool webAuthenticationPanelUpdatePINInvalid = false;
54 static bool webAuthenticationPanelUpdateLAError = false;
55 static bool webAuthenticationPanelUpdateLAExcludeCredentialsMatched = false;
56 static bool webAuthenticationPanelUpdateLANoCredential = false;
57 static bool webAuthenticationPanelCancelImmediately = false;
58 static _WKLocalAuthenticatorPolicy localAuthenticatorPolicy = _WKLocalAuthenticatorPolicyDisallow;
59 static String webAuthenticationPanelPin;
60 static BOOL webAuthenticationPanelNullUserHandle = NO;
61 static String testES256PrivateKeyBase64 =
62     "BDj/zxSkzKgaBuS3cdWDF558of8AaIpgFpsjF/Qm1749VBJPgqUIwfhWHJ91nb7U"
63     "PH76c0+WFOzZKslPyyFse4goGIW2R7k9VHLPEZl5nfnBgEVFh5zev+/xpHQIvuq6"
64     "RQ==";
65 static String testUserEntityBundleBase64 = "omJpZEoAAQIDBAUGBwgJZG5hbWVkSm9obg=="; // { "id": h'00010203040506070809', "name": "John" }
66 static String webAuthenticationPanelSelectedCredentialName;
67
68 @interface TestWebAuthenticationPanelDelegate : NSObject <_WKWebAuthenticationPanelDelegate>
69 @end
70
71 @implementation TestWebAuthenticationPanelDelegate
72
73 - (void)panel:(_WKWebAuthenticationPanel *)panel updateWebAuthenticationPanel:(_WKWebAuthenticationPanelUpdate)update
74 {
75     ASSERT_NE(panel, nil);
76     if (webAuthenticationPanelCancelImmediately)
77         [panel cancel];
78
79     if (update == _WKWebAuthenticationPanelUpdateMultipleNFCTagsPresent) {
80         webAuthenticationPanelUpdateMultipleNFCTagsPresent = true;
81         return;
82     }
83     if (update == _WKWebAuthenticationPanelUpdateNoCredentialsFound) {
84         webAuthenticationPanelUpdateNoCredentialsFound = true;
85         return;
86     }
87     if (update == _WKWebAuthenticationPanelUpdatePINBlocked) {
88         webAuthenticationPanelUpdatePINBlocked = true;
89         return;
90     }
91     if (update == _WKWebAuthenticationPanelUpdatePINAuthBlocked) {
92         webAuthenticationPanelUpdatePINAuthBlocked = true;
93         return;
94     }
95     if (update == _WKWebAuthenticationPanelUpdatePINInvalid) {
96         webAuthenticationPanelUpdatePINInvalid = true;
97         return;
98     }
99     if (update == _WKWebAuthenticationPanelUpdateLAError) {
100         webAuthenticationPanelUpdateLAError = true;
101         return;
102     }
103     if (update == _WKWebAuthenticationPanelUpdateLAExcludeCredentialsMatched) {
104         webAuthenticationPanelUpdateLAExcludeCredentialsMatched = true;
105         return;
106     }
107     if (update == _WKWebAuthenticationPanelUpdateLANoCredential) {
108         webAuthenticationPanelUpdateLANoCredential = true;
109         return;
110     }
111 }
112
113 - (void)panel:(_WKWebAuthenticationPanel *)panel dismissWebAuthenticationPanelWithResult:(_WKWebAuthenticationResult)result
114 {
115     ASSERT_NE(panel, nil);
116     if (webAuthenticationPanelCancelImmediately)
117         [panel cancel];
118
119     if (result == _WKWebAuthenticationResultFailed) {
120         webAuthenticationPanelFailed = true;
121         return;
122     }
123     if (result == _WKWebAuthenticationResultSucceeded) {
124         webAuthenticationPanelSucceded = true;
125         return;
126     }
127 }
128
129 - (void)panel:(_WKWebAuthenticationPanel *)panel requestPINWithRemainingRetries:(NSUInteger)retries completionHandler:(void (^)(NSString *))completionHandler
130 {
131     ASSERT_NE(panel, nil);
132     EXPECT_EQ(retries, 8ul);
133     completionHandler(webAuthenticationPanelPin);
134 }
135
136 - (void)panel:(_WKWebAuthenticationPanel *)panel selectAssertionResponse:(NSArray < _WKWebAuthenticationAssertionResponse *> *)responses source:(_WKWebAuthenticationSource)source completionHandler:(void (^)(_WKWebAuthenticationAssertionResponse *))completionHandler
137 {
138     if (responses.count == 1) {
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);
148         return;
149     }
150
151     EXPECT_EQ(source, _WKWebAuthenticationSourceExternal);
152     EXPECT_EQ(responses.count, 2ul);
153     for (_WKWebAuthenticationAssertionResponse *response in responses) {
154         EXPECT_TRUE([response.name isEqual:@"johnpsmith@example.com"] || [response.name isEqual:@""]);
155         EXPECT_TRUE([response.displayName isEqual:@"John P. Smith"] || [response.displayName isEqual:@""]);
156         EXPECT_TRUE([[response.userHandle base64EncodedStringWithOptions:0] isEqual:@"MIIBkzCCATigAwIBAjCCAZMwggE4oAMCAQIwggGTMII="] || !response.userHandle);
157     }
158
159     auto index = weakRandomUint32() % 2;
160     webAuthenticationPanelNullUserHandle = responses[index].userHandle ? NO : YES;
161     completionHandler(responses[index]);
162 }
163
164 - (void)panel:(_WKWebAuthenticationPanel *)panel decidePolicyForLocalAuthenticatorWithCompletionHandler:(void (^)(_WKLocalAuthenticatorPolicy policy))completionHandler
165 {
166     completionHandler(localAuthenticatorPolicy);
167 }
168
169 @end
170
171 @interface TestWebAuthenticationPanelFakeDelegate : NSObject <_WKWebAuthenticationPanelDelegate>
172 @end
173
174 @implementation TestWebAuthenticationPanelFakeDelegate
175 @end
176
177 @interface TestWebAuthenticationPanelUIDelegate : NSObject <WKUIDelegatePrivate>
178 @property bool isRacy;
179 @property bool isFake;
180 @property bool isNull;
181
182 - (instancetype)init;
183 @end
184
185 @implementation TestWebAuthenticationPanelUIDelegate {
186     RetainPtr<NSObject<_WKWebAuthenticationPanelDelegate>> _delegate;
187     BlockPtr<void(_WKWebAuthenticationPanelResult)> _callback;
188     RetainPtr<WKFrameInfo> _frameInfo;
189     RetainPtr<_WKWebAuthenticationPanel> _panel;
190 }
191
192 - (instancetype)init
193 {
194     if (self = [super init]) {
195         self.isRacy = false;
196         self.isFake = false;
197         self.isNull = false;
198     }
199     return self;
200 }
201
202 - (void)_webView:(WKWebView *)webView runWebAuthenticationPanel:(_WKWebAuthenticationPanel *)panel initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(_WKWebAuthenticationPanelResult))completionHandler
203 {
204     webAuthenticationPanelRan = true;
205     _frameInfo = frame;
206
207     if (!_isNull) {
208         if (!_isFake)
209             _delegate = adoptNS([[TestWebAuthenticationPanelDelegate alloc] init]);
210         else
211             _delegate = adoptNS([[TestWebAuthenticationPanelFakeDelegate alloc] init]);
212     }
213     ASSERT_NE(panel, nil);
214     _panel = panel;
215     [_panel setDelegate:_delegate.get()];
216
217     if (_isRacy) {
218         if (!_callback) {
219             _callback = makeBlockPtr(completionHandler);
220             return;
221         }
222         _callback(_WKWebAuthenticationPanelResultUnavailable);
223     }
224     completionHandler(_WKWebAuthenticationPanelResultPresented);
225 }
226
227 - (WKFrameInfo *)frame
228 {
229     return _frameInfo.get();
230 }
231
232 - (_WKWebAuthenticationPanel *)panel
233 {
234     return _panel.get();
235 }
236
237 @end
238
239 namespace TestWebKitAPI {
240
241 namespace {
242
243 const char parentFrame[] = "<html><iframe id='theFrame' src='iFrame.html'></iframe></html>";
244 const char subFrame[] =
245 "<html>"
246 "<input type='text' id='input'>"
247 "<script>"
248 "    if (window.internals) {"
249 "        internals.setMockWebAuthenticationConfiguration({ hid: { expectCancel: true } });"
250 "        internals.withUserGesture(() => { input.focus(); });"
251 "    }"
252 "    const options = {"
253 "        publicKey: {"
254 "            challenge: new Uint8Array(16)"
255 "        }"
256 "    };"
257 "    navigator.credentials.get(options);"
258 "</script>"
259 "</html>";
260
261 static _WKExperimentalFeature *webAuthenticationExperimentalFeature()
262 {
263     static RetainPtr<_WKExperimentalFeature> theFeature;
264     if (theFeature)
265         return theFeature.get();
266
267     NSArray *features = [WKPreferences _experimentalFeatures];
268     for (_WKExperimentalFeature *feature in features) {
269         if ([feature.key isEqual:@"WebAuthenticationEnabled"]) {
270             theFeature = feature;
271             break;
272         }
273     }
274     return theFeature.get();
275 }
276
277 #if USE(APPLE_INTERNAL_SDK) || PLATFORM(IOS)
278 static _WKExperimentalFeature *webAuthenticationLocalAuthenticatorExperimentalFeature()
279 {
280     static RetainPtr<_WKExperimentalFeature> theFeature;
281     if (theFeature)
282         return theFeature.get();
283
284     NSArray *features = [WKPreferences _experimentalFeatures];
285     for (_WKExperimentalFeature *feature in features) {
286         if ([feature.key isEqual:@"WebAuthenticationLocalAuthenticatorEnabled"]) {
287             theFeature = feature;
288             break;
289         }
290     }
291     return theFeature.get();
292 }
293 #endif // USE(APPLE_INTERNAL_SDK) || PLATFORM(IOS)
294
295 static void reset()
296 {
297     webAuthenticationPanelRan = false;
298     webAuthenticationPanelFailed = false;
299     webAuthenticationPanelSucceded = false;
300     webAuthenticationPanelUpdateMultipleNFCTagsPresent = false;
301     webAuthenticationPanelUpdateNoCredentialsFound = false;
302     webAuthenticationPanelUpdatePINBlocked = false;
303     webAuthenticationPanelUpdatePINAuthBlocked = false;
304     webAuthenticationPanelUpdatePINInvalid = false;
305     webAuthenticationPanelUpdateLAError = false;
306     webAuthenticationPanelUpdateLAExcludeCredentialsMatched = false;
307     webAuthenticationPanelUpdateLANoCredential = false;
308     webAuthenticationPanelCancelImmediately = false;
309     webAuthenticationPanelPin = emptyString();
310     webAuthenticationPanelNullUserHandle = NO;
311     localAuthenticatorPolicy = _WKLocalAuthenticatorPolicyDisallow;
312     webAuthenticationPanelSelectedCredentialName = emptyString();
313 }
314
315 static void checkPanel(_WKWebAuthenticationPanel *panel, NSString *relyingPartyID, NSArray *transports, _WKWebAuthenticationType type)
316 {
317     EXPECT_WK_STREQ(panel.relyingPartyID, relyingPartyID);
318
319     EXPECT_EQ(panel.transports.count, transports.count);
320     size_t count = 0;
321     for (NSNumber *transport : transports) {
322         if ([panel.transports containsObject:transport])
323             count++;
324     }
325     EXPECT_EQ(count, transports.count);
326
327     EXPECT_EQ(panel.type, type);
328 }
329
330 static void checkFrameInfo(WKFrameInfo *frame, bool isMainFrame, NSString *url, NSString *protocol, NSString *host, int port, WKWebView *webView)
331 {
332     EXPECT_EQ(frame.mainFrame, isMainFrame);
333     EXPECT_TRUE([frame.request.URL.absoluteString isEqual:url]);
334     EXPECT_WK_STREQ(frame.securityOrigin.protocol, protocol);
335     EXPECT_WK_STREQ(frame.securityOrigin.host, host);
336     EXPECT_EQ(frame.securityOrigin.port, port);
337     EXPECT_EQ(frame.webView, webView);
338 }
339
340 #if USE(APPLE_INTERNAL_SDK) || PLATFORM(IOS)
341
342 bool addKeyToKeychain(const String& privateKeyBase64, const String& rpId, const String& userHandleBase64)
343 {
344     NSDictionary* options = @{
345         (id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom,
346         (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
347         (id)kSecAttrKeySizeInBits: @256,
348     };
349     CFErrorRef errorRef = nullptr;
350     auto key = adoptCF(SecKeyCreateWithData(
351         (__bridge CFDataRef)adoptNS([[NSData alloc] initWithBase64EncodedString:privateKeyBase64 options:NSDataBase64DecodingIgnoreUnknownCharacters]).get(),
352         (__bridge CFDictionaryRef)options,
353         &errorRef
354     ));
355     if (errorRef)
356         return false;
357
358     NSDictionary* addQuery = @{
359         (id)kSecValueRef: (id)key.get(),
360         (id)kSecClass: (id)kSecClassKey,
361         (id)kSecAttrLabel: rpId,
362         (id)kSecAttrApplicationTag: adoptNS([[NSData alloc] initWithBase64EncodedString:userHandleBase64 options:NSDataBase64DecodingIgnoreUnknownCharacters]).get(),
363         (id)kSecAttrAccessible: (id)kSecAttrAccessibleAfterFirstUnlock,
364 #if HAVE(DATA_PROTECTION_KEYCHAIN)
365         (id)kSecUseDataProtectionKeychain: @YES
366 #else
367         (id)kSecAttrNoLegacy: @YES
368 #endif
369     };
370     OSStatus status = SecItemAdd((__bridge CFDictionaryRef)addQuery, NULL);
371     if (status)
372         return false;
373
374     return true;
375 }
376
377 void cleanUpKeychain(const String& rpId)
378 {
379     NSDictionary* deleteQuery = @{
380         (id)kSecClass: (id)kSecClassKey,
381         (id)kSecAttrLabel: rpId,
382         (id)kSecAttrAccessible: (id)kSecAttrAccessibleAfterFirstUnlock,
383 #if HAVE(DATA_PROTECTION_KEYCHAIN)
384         (id)kSecUseDataProtectionKeychain: @YES
385 #else
386         (id)kSecAttrNoLegacy: @YES
387 #endif
388     };
389     SecItemDelete((__bridge CFDictionaryRef)deleteQuery);
390 }
391
392 #endif // USE(APPLE_INTERNAL_SDK) || PLATFORM(IOS)
393
394 } // namesapce;
395
396 TEST(WebAuthenticationPanel, NoPanelTimeout)
397 {
398     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-nfc" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
399
400     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
401     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
402
403     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
404
405     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
406     [webView waitForMessage:@"Operation timed out."];
407 }
408
409 TEST(WebAuthenticationPanel, NoPanelHidSuccess)
410 {
411     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
412
413     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
414     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
415
416     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
417
418     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
419     [webView waitForMessage:@"Succeeded!"];
420 }
421
422 TEST(WebAuthenticationPanel, PanelTimeout)
423 {
424     reset();
425     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
426
427     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
428     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
429
430     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
431     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
432     [webView setUIDelegate:delegate.get()];
433
434     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
435     Util::run(&webAuthenticationPanelRan);
436     Util::run(&webAuthenticationPanelFailed);
437 }
438
439 TEST(WebAuthenticationPanel, PanelHidSuccess1)
440 {
441     reset();
442     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
443
444     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
445     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
446
447     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
448     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
449     [webView setUIDelegate:delegate.get()];
450
451     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
452     Util::run(&webAuthenticationPanelRan);
453     Util::run(&webAuthenticationPanelSucceded);
454
455     // A bit of extra checks.
456     checkFrameInfo([delegate frame], true, [testURL absoluteString], @"file", @"", 0, webView.get());
457     checkPanel([delegate panel], @"", @[adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportUSB]).get()], _WKWebAuthenticationTypeGet);
458 }
459
460 TEST(WebAuthenticationPanel, PanelHidSuccess2)
461 {
462     reset();
463     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
464
465     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
466     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
467
468     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
469     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
470     [webView setUIDelegate:delegate.get()];
471
472     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
473     Util::run(&webAuthenticationPanelRan);
474     Util::run(&webAuthenticationPanelSucceded);
475
476     // A bit of extra checks.
477     checkPanel([delegate panel], @"", @[adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportUSB]).get()], _WKWebAuthenticationTypeCreate);
478 }
479
480 #if HAVE(NEAR_FIELD)
481 // This test aims to see if the callback for the first ceremony could affect the second one.
482 // Therefore, the first callback will be held to return at the time when the second arrives.
483 // The first callback will return _WKWebAuthenticationPanelResultUnavailable which leads to timeout for NFC.
484 // The second callback will return _WKWebAuthenticationPanelResultPresented which leads to success.
485 TEST(WebAuthenticationPanel, PanelRacy1)
486 {
487     reset();
488     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-nfc" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
489
490     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
491     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
492
493     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
494     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
495     [delegate setIsRacy:true];
496     [webView setUIDelegate:delegate.get()];
497
498     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
499     Util::run(&webAuthenticationPanelRan);
500     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
501     [webView waitForMessage:@"Succeeded!"];
502
503     // A bit of extra checks.
504     checkPanel([delegate panel], @"", @[adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportNFC]).get()], _WKWebAuthenticationTypeGet);
505 }
506
507 // Unlike the previous one, this one focuses on the order of the delegate callbacks.
508 TEST(WebAuthenticationPanel, PanelRacy2)
509 {
510     reset();
511     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-nfc" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
512
513     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
514     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
515
516     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
517     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
518     [delegate setIsRacy:true];
519     [webView setUIDelegate:delegate.get()];
520
521     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
522     Util::run(&webAuthenticationPanelRan);
523     webAuthenticationPanelRan = false;
524     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
525     Util::run(&webAuthenticationPanelFailed);
526     Util::run(&webAuthenticationPanelRan);
527     Util::run(&webAuthenticationPanelSucceded);
528 }
529 #endif // HAVE(NEAR_FIELD)
530
531 TEST(WebAuthenticationPanel, PanelTwice)
532 {
533     reset();
534     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
535
536     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
537     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
538
539     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
540     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
541     [webView setUIDelegate:delegate.get()];
542
543     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
544     Util::run(&webAuthenticationPanelRan);
545     Util::run(&webAuthenticationPanelSucceded);
546
547     reset();
548     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
549     Util::run(&webAuthenticationPanelRan);
550     Util::run(&webAuthenticationPanelSucceded);
551 }
552
553 TEST(WebAuthenticationPanel, ReloadHidCancel)
554 {
555     reset();
556     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-cancel" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
557
558     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
559     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
560
561     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
562     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
563     [webView setUIDelegate:delegate.get()];
564
565     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
566     Util::run(&webAuthenticationPanelRan);
567     [webView reload];
568     Util::run(&webAuthenticationPanelFailed);
569 }
570
571 TEST(WebAuthenticationPanel, LocationChangeHidCancel)
572 {
573     reset();
574     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-cancel" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
575     RetainPtr<NSURL> otherURL = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
576
577     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
578     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
579
580     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
581     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
582     [webView setUIDelegate:delegate.get()];
583
584     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
585     Util::run(&webAuthenticationPanelRan);
586     [webView evaluateJavaScript: [NSString stringWithFormat:@"location = '%@'", [otherURL absoluteString]] completionHandler:nil];
587     Util::run(&webAuthenticationPanelFailed);
588 }
589
590 TEST(WebAuthenticationPanel, NewLoadHidCancel)
591 {
592     reset();
593     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-cancel" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
594     RetainPtr<NSURL> otherURL = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
595
596     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
597     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
598
599     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
600     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
601     [webView setUIDelegate:delegate.get()];
602
603     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
604     Util::run(&webAuthenticationPanelRan);
605     [webView loadRequest:[NSURLRequest requestWithURL:otherURL.get()]];
606     Util::run(&webAuthenticationPanelFailed);
607 }
608
609 TEST(WebAuthenticationPanel, CloseHidCancel)
610 {
611     reset();
612     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-cancel" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
613
614     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
615     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
616
617     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
618     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
619     [webView setUIDelegate:delegate.get()];
620
621     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
622     Util::run(&webAuthenticationPanelRan);
623     [webView _close];
624     Util::run(&webAuthenticationPanelFailed);
625 }
626
627 TEST(WebAuthenticationPanel, SubFrameChangeLocationHidCancel)
628 {
629     TCPServer server([parentFrame = String(parentFrame), subFrame = String(subFrame)] (int socket) {
630         NSString *firstResponse = [NSString stringWithFormat:
631             @"HTTP/1.1 200 OK\r\n"
632             "Content-Length: %d\r\n\r\n"
633             "%@",
634             parentFrame.length(),
635             (id)parentFrame
636         ];
637         NSString *secondResponse = [NSString stringWithFormat:
638             @"HTTP/1.1 200 OK\r\n"
639             "Content-Length: %d\r\n\r\n"
640             "%@",
641             subFrame.length(),
642             (id)subFrame
643         ];
644
645         TCPServer::read(socket);
646         TCPServer::write(socket, firstResponse.UTF8String, firstResponse.length);
647         TCPServer::read(socket);
648         TCPServer::write(socket, secondResponse.UTF8String, secondResponse.length);
649     });
650
651     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
652     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
653
654     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
655     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
656     [webView setUIDelegate:delegate.get()];
657
658     auto port = static_cast<unsigned>(server.port());
659     auto url = makeString("http://localhost:", port);
660     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:(id)url]]];
661     Util::run(&webAuthenticationPanelRan);
662     [webView evaluateJavaScript:@"theFrame.src = 'simple.html'" completionHandler:nil];
663     Util::run(&webAuthenticationPanelFailed);
664
665     // A bit of extra checks.
666     checkFrameInfo([delegate frame], false, (id)makeString(url, "/iFrame.html"), @"http", @"localhost", port, webView.get());
667     checkPanel([delegate panel], @"localhost", @[adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportUSB]).get()], _WKWebAuthenticationTypeGet);
668 }
669
670 TEST(WebAuthenticationPanel, SubFrameDestructionHidCancel)
671 {
672     TCPServer server([parentFrame = String(parentFrame), subFrame = String(subFrame)] (int socket) {
673         NSString *firstResponse = [NSString stringWithFormat:
674             @"HTTP/1.1 200 OK\r\n"
675             "Content-Length: %d\r\n\r\n"
676             "%@",
677             parentFrame.length(),
678             (id)parentFrame
679         ];
680         NSString *secondResponse = [NSString stringWithFormat:
681             @"HTTP/1.1 200 OK\r\n"
682             "Content-Length: %d\r\n\r\n"
683             "%@",
684             subFrame.length(),
685             (id)subFrame
686         ];
687
688         TCPServer::read(socket);
689         TCPServer::write(socket, firstResponse.UTF8String, firstResponse.length);
690         TCPServer::read(socket);
691         TCPServer::write(socket, secondResponse.UTF8String, secondResponse.length);
692     });
693
694     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
695     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
696
697     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
698     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
699     [webView setUIDelegate:delegate.get()];
700
701     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:(id)makeString("http://localhost:", server.port())]]];
702     Util::run(&webAuthenticationPanelRan);
703     [webView evaluateJavaScript:@"theFrame.parentNode.removeChild(theFrame)" completionHandler:nil];
704     Util::run(&webAuthenticationPanelFailed);
705 }
706
707 TEST(WebAuthenticationPanel, PanelHidCancel)
708 {
709     reset();
710     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-cancel" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
711
712     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
713     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
714
715     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
716     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
717     [webView setUIDelegate:delegate.get()];
718
719     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
720     Util::run(&webAuthenticationPanelRan);
721     [[delegate panel] cancel];
722     [webView waitForMessage:@"This request has been cancelled by the user."];
723     EXPECT_TRUE(webAuthenticationPanelFailed);
724 }
725
726 TEST(WebAuthenticationPanel, PanelHidCtapNoCredentialsFound)
727 {
728     reset();
729     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-no-credentials" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
730
731     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
732     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
733
734     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
735     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
736     [webView setUIDelegate:delegate.get()];
737
738     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
739     Util::run(&webAuthenticationPanelRan);
740     Util::run(&webAuthenticationPanelUpdateNoCredentialsFound);
741 }
742
743 TEST(WebAuthenticationPanel, PanelU2fCtapNoCredentialsFound)
744 {
745     reset();
746     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-u2f-no-credentials" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
747
748     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
749     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
750
751     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
752     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
753     [webView setUIDelegate:delegate.get()];
754
755     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
756     Util::run(&webAuthenticationPanelRan);
757     Util::run(&webAuthenticationPanelUpdateNoCredentialsFound);
758 }
759
760 TEST(WebAuthenticationPanel, FakePanelHidSuccess)
761 {
762     reset();
763     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
764
765     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
766     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
767
768     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
769     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
770     [delegate setIsFake:true];
771     [webView setUIDelegate:delegate.get()];
772
773     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
774     Util::run(&webAuthenticationPanelRan);
775     [webView waitForMessage:@"Succeeded!"];
776 }
777
778 TEST(WebAuthenticationPanel, FakePanelHidCtapNoCredentialsFound)
779 {
780     reset();
781     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-no-credentials" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
782
783     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
784     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
785
786     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
787     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
788     [delegate setIsFake:true];
789     [webView setUIDelegate:delegate.get()];
790
791     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
792     Util::run(&webAuthenticationPanelRan);
793     [webView waitForMessage:@"Operation timed out."];
794 }
795
796 TEST(WebAuthenticationPanel, NullPanelHidSuccess)
797 {
798     reset();
799     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
800
801     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
802     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
803
804     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
805     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
806     [delegate setIsNull:true];
807     [webView setUIDelegate:delegate.get()];
808
809     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
810     Util::run(&webAuthenticationPanelRan);
811     [webView waitForMessage:@"Succeeded!"];
812 }
813
814 TEST(WebAuthenticationPanel, NullPanelHidCtapNoCredentialsFound)
815 {
816     reset();
817     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-no-credentials" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
818
819     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
820     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
821
822     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
823     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
824     [delegate setIsNull:true];
825     [webView setUIDelegate:delegate.get()];
826
827     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
828     Util::run(&webAuthenticationPanelRan);
829     [webView waitForMessage:@"Operation timed out."];
830 }
831
832 #if HAVE(NEAR_FIELD)
833 TEST(WebAuthenticationPanel, PanelMultipleNFCTagsPresent)
834 {
835     reset();
836     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-nfc-multiple-tags" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
837
838     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
839     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
840
841     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
842     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
843     [webView setUIDelegate:delegate.get()];
844
845     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
846     Util::run(&webAuthenticationPanelRan);
847     Util::run(&webAuthenticationPanelUpdateMultipleNFCTagsPresent);
848 }
849 #endif
850
851 TEST(WebAuthenticationPanel, PanelHidCancelReloadNoCrash)
852 {
853     reset();
854     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-cancel" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
855
856     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
857     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
858
859     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
860     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
861     [webView setUIDelegate:delegate.get()];
862
863     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
864     Util::run(&webAuthenticationPanelRan);
865     [[delegate panel] cancel];
866     [webView reload];
867     [webView waitForMessage:@"Operation timed out."];
868 }
869
870 TEST(WebAuthenticationPanel, PanelHidSuccessCancelNoCrash)
871 {
872     reset();
873     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
874
875     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
876     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
877
878     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
879     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
880     [webView setUIDelegate:delegate.get()];
881     webAuthenticationPanelCancelImmediately = true;
882
883     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
884     [webView waitForMessage:@"Succeeded!"];
885 }
886
887 TEST(WebAuthenticationPanel, PanelHidCtapNoCredentialsFoundCancelNoCrash)
888 {
889     reset();
890     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-no-credentials" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
891
892     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
893     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
894
895     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
896     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
897     [webView setUIDelegate:delegate.get()];
898     webAuthenticationPanelCancelImmediately = true;
899
900     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
901     Util::run(&webAuthenticationPanelUpdateNoCredentialsFound);
902 }
903
904 TEST(WebAuthenticationPanel, PinGetRetriesError)
905 {
906     reset();
907     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-get-retries-error" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
908
909     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
910     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
911
912     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
913     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
914     [webView waitForMessage:@"Unknown internal error. Error code: 2"];
915 }
916
917 TEST(WebAuthenticationPanel, PinGetKeyAgreementError)
918 {
919     reset();
920     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-get-key-agreement-error" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
921
922     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
923     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
924
925     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
926     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
927     [webView waitForMessage:@"Unknown internal error. Error code: 2"];
928 }
929
930 TEST(WebAuthenticationPanel, PinRequestPinErrorNoDelegate)
931 {
932     reset();
933     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
934
935     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
936     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
937
938     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
939     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
940     [webView waitForMessage:@"Pin is null."];
941 }
942
943 TEST(WebAuthenticationPanel, PinRequestPinErrorNullDelegate)
944 {
945     reset();
946     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
947
948     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
949     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
950
951     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
952     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
953     [delegate setIsNull:true];
954     [webView setUIDelegate:delegate.get()];
955
956     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
957     [webView waitForMessage:@"Pin is null."];
958 }
959
960 TEST(WebAuthenticationPanel, PinRequestPinError)
961 {
962     reset();
963     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-get-pin-token-fake-pin-invalid-error-retry" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
964
965     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
966     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
967
968     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
969     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
970     [webView setUIDelegate:delegate.get()];
971
972     webAuthenticationPanelPin = "123";
973     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
974     Util::run(&webAuthenticationPanelUpdatePINInvalid);
975     webAuthenticationPanelPin = "1234";
976     [webView waitForMessage:@"Succeeded!"];
977 }
978
979 TEST(WebAuthenticationPanel, PinGetPinTokenPinBlockedError)
980 {
981     reset();
982     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-get-pin-token-pin-blocked-error" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
983
984     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
985     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
986
987     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
988     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
989     [webView setUIDelegate:delegate.get()];
990
991     webAuthenticationPanelPin = "1234";
992     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
993     [webView waitForMessage:@"Unknown internal error. Error code: 50"];
994     EXPECT_FALSE(webAuthenticationPanelUpdatePINInvalid);
995     EXPECT_TRUE(webAuthenticationPanelUpdatePINBlocked);
996 }
997
998 TEST(WebAuthenticationPanel, PinGetPinTokenPinAuthBlockedError)
999 {
1000     reset();
1001     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-get-pin-token-pin-auth-blocked-error" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1002
1003     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1004     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1005
1006     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1007     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1008     [webView setUIDelegate:delegate.get()];
1009
1010     webAuthenticationPanelPin = "1234";
1011     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1012     [webView waitForMessage:@"Unknown internal error. Error code: 52"];
1013     EXPECT_FALSE(webAuthenticationPanelUpdatePINInvalid);
1014     EXPECT_TRUE(webAuthenticationPanelUpdatePINAuthBlocked);
1015 }
1016
1017 TEST(WebAuthenticationPanel, PinGetPinTokenPinInvalidErrorAndRetry)
1018 {
1019     reset();
1020     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-get-pin-token-pin-invalid-error-retry" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1021
1022     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1023     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1024
1025     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1026     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1027     [webView setUIDelegate:delegate.get()];
1028
1029     webAuthenticationPanelPin = "1234";
1030     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1031     [webView waitForMessage:@"Succeeded!"];
1032     EXPECT_TRUE(webAuthenticationPanelUpdatePINInvalid);
1033 }
1034
1035 TEST(WebAuthenticationPanel, PinGetPinTokenPinAuthInvalidErrorAndRetry)
1036 {
1037     reset();
1038     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-get-pin-token-pin-auth-invalid-error-retry" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1039
1040     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1041     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1042
1043     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1044     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1045     [webView setUIDelegate:delegate.get()];
1046
1047     webAuthenticationPanelPin = "1234";
1048     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1049     [webView waitForMessage:@"Succeeded!"];
1050     EXPECT_TRUE(webAuthenticationPanelUpdatePINInvalid);
1051 }
1052
1053 TEST(WebAuthenticationPanel, MakeCredentialPin)
1054 {
1055     reset();
1056     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1057
1058     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1059     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1060
1061     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1062     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1063     [webView setUIDelegate:delegate.get()];
1064
1065     webAuthenticationPanelPin = "1234";
1066     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1067     [webView waitForMessage:@"Succeeded!"];
1068 }
1069
1070 TEST(WebAuthenticationPanel, MakeCredentialPinAuthBlockedError)
1071 {
1072     reset();
1073     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-auth-blocked-error" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1074
1075     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1076     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1077
1078     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1079     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1080     [webView setUIDelegate:delegate.get()];
1081
1082     webAuthenticationPanelPin = "1234";
1083     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1084     [webView waitForMessage:@"Unknown internal error. Error code: 52"];
1085     EXPECT_FALSE(webAuthenticationPanelUpdatePINInvalid);
1086     EXPECT_TRUE(webAuthenticationPanelUpdatePINAuthBlocked);
1087 }
1088
1089 TEST(WebAuthenticationPanel, MakeCredentialPinInvalidErrorAndRetry)
1090 {
1091     reset();
1092     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-invalid-error-retry" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1093
1094     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1095     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1096
1097     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1098     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1099     [webView setUIDelegate:delegate.get()];
1100
1101     webAuthenticationPanelPin = "1234";
1102     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1103     [webView waitForMessage:@"Succeeded!"];
1104     EXPECT_TRUE(webAuthenticationPanelUpdatePINInvalid);
1105 }
1106
1107 TEST(WebAuthenticationPanel, GetAssertionPin)
1108 {
1109     reset();
1110     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-pin" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1111
1112     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1113     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1114
1115     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1116     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1117     [webView setUIDelegate:delegate.get()];
1118
1119     webAuthenticationPanelPin = "1234";
1120     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1121     [webView waitForMessage:@"Succeeded!"];
1122 }
1123
1124 TEST(WebAuthenticationPanel, GetAssertionPinAuthBlockedError)
1125 {
1126     reset();
1127     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-pin-auth-blocked-error" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1128
1129     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1130     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1131
1132     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1133     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1134     [webView setUIDelegate:delegate.get()];
1135
1136     webAuthenticationPanelPin = "1234";
1137     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1138     [webView waitForMessage:@"Unknown internal error. Error code: 52"];
1139     EXPECT_FALSE(webAuthenticationPanelUpdatePINInvalid);
1140     EXPECT_TRUE(webAuthenticationPanelUpdatePINAuthBlocked);
1141 }
1142
1143 TEST(WebAuthenticationPanel, GetAssertionPinInvalidErrorAndRetry)
1144 {
1145     reset();
1146     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-pin-invalid-error-retry" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1147
1148     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1149     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1150
1151     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1152     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1153     [webView setUIDelegate:delegate.get()];
1154
1155     webAuthenticationPanelPin = "1234";
1156     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1157     [webView waitForMessage:@"Succeeded!"];
1158     EXPECT_TRUE(webAuthenticationPanelUpdatePINInvalid);
1159 }
1160
1161 TEST(WebAuthenticationPanel, MultipleAccountsNullDelegate)
1162 {
1163     reset();
1164     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-multiple-accounts" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1165
1166     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1167     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1168
1169     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1170     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1171     [delegate setIsNull:true];
1172     [webView setUIDelegate:delegate.get()];
1173
1174     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1175     [webView waitForMessage:@"Operation timed out."];
1176 }
1177
1178 TEST(WebAuthenticationPanel, MultipleAccounts)
1179 {
1180     reset();
1181     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-multiple-accounts" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1182
1183     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1184     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1185
1186     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1187     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1188     [webView setUIDelegate:delegate.get()];
1189
1190     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1191     [webView waitForMessage:@"Succeeded!"];
1192     EXPECT_EQ([[webView stringByEvaluatingJavaScript:@"userHandle"] isEqualToString:@"<null>"], webAuthenticationPanelNullUserHandle);
1193 }
1194
1195 // For macOS, only internal builds can sign keychain entitlemnets
1196 // which are required to run local authenticator tests.
1197 #if USE(APPLE_INTERNAL_SDK) || PLATFORM(IOS)
1198
1199 TEST(WebAuthenticationPanel, LAError)
1200 {
1201     reset();
1202     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-la-error" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1203
1204     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1205     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1206
1207     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1208     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1209     [webView setUIDelegate:delegate.get()];
1210
1211     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1212     Util::run(&webAuthenticationPanelUpdateLAError);
1213 }
1214
1215 TEST(WebAuthenticationPanel, LADuplicateCredential)
1216 {
1217     reset();
1218     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-la-duplicate-credential" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1219
1220     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1221     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1222
1223     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1224     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1225     [webView setUIDelegate:delegate.get()];
1226
1227     ASSERT_TRUE(addKeyToKeychain(testES256PrivateKeyBase64, "", testUserEntityBundleBase64));
1228     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1229     Util::run(&webAuthenticationPanelUpdateLAExcludeCredentialsMatched);
1230     cleanUpKeychain("");
1231 }
1232
1233 TEST(WebAuthenticationPanel, LANoCredential)
1234 {
1235     reset();
1236     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-la" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1237
1238     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1239     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1240
1241     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1242     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1243     [webView setUIDelegate:delegate.get()];
1244
1245     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1246     Util::run(&webAuthenticationPanelUpdateLANoCredential);
1247 }
1248
1249 TEST(WebAuthenticationPanel, LAMakeCredentialNullDelegate)
1250 {
1251     reset();
1252     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-la" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1253
1254     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1255     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1256
1257     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1258     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1259     [delegate setIsNull:true];
1260     [webView setUIDelegate:delegate.get()];
1261
1262     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1263     [webView waitForMessage:@"Disallow local authenticator."];
1264 }
1265
1266 TEST(WebAuthenticationPanel, LAMakeCredentialDisallowLocalAuthenticator)
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
1274     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1275     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1276     [webView setUIDelegate:delegate.get()];
1277
1278     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1279     [webView waitForMessage:@"Disallow local authenticator."];
1280 }
1281
1282 TEST(WebAuthenticationPanel, LAMakeCredentialAllowLocalAuthenticator)
1283 {
1284     reset();
1285     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-la" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1286
1287     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1288     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1289
1290     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1291     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1292     [webView setUIDelegate:delegate.get()];
1293
1294     localAuthenticatorPolicy = _WKLocalAuthenticatorPolicyAllow;
1295     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1296     [webView waitForMessage:@"Succeeded!"];
1297     checkPanel([delegate panel], @"", @[adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportUSB]).get(), adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportInternal]).get()], _WKWebAuthenticationTypeCreate);
1298     cleanUpKeychain("");
1299 }
1300
1301 TEST(WebAuthenticationPanel, LANoMockDefaultOff)
1302 {
1303     reset();
1304     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-la-no-mock" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1305
1306     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1307     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1308
1309     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1310     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1311     [webView setUIDelegate:delegate.get()];
1312
1313     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1314     Util::run(&webAuthenticationPanelRan);
1315     checkPanel([delegate panel], @"", @[adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportUSB]).get()], _WKWebAuthenticationTypeCreate);
1316 }
1317
1318 TEST(WebAuthenticationPanel, LAMakeCredentialNoMockNoUserGesture)
1319 {
1320     reset();
1321     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-la-no-mock" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1322
1323     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1324     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1325     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationLocalAuthenticatorExperimentalFeature()];
1326
1327     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1328     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1329     [webView setUIDelegate:delegate.get()];
1330
1331     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1332     Util::run(&webAuthenticationPanelRan);
1333     checkPanel([delegate panel], @"", @[adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportUSB]).get()], _WKWebAuthenticationTypeCreate);
1334 }
1335
1336 TEST(WebAuthenticationPanel, LAMakeCredentialRollBackCredential)
1337 {
1338     reset();
1339     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-la-no-attestation" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1340
1341     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1342     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1343
1344     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1345     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1346     [webView setUIDelegate:delegate.get()];
1347
1348     localAuthenticatorPolicy = _WKLocalAuthenticatorPolicyAllow;
1349     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1350     [webView waitForMessage:@"Couldn't attest: The operation couldn't complete."];
1351
1352     NSDictionary *query = @{
1353         (id)kSecClass: (id)kSecClassKey,
1354         (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
1355         (id)kSecAttrLabel: @"",
1356 #if HAVE(DATA_PROTECTION_KEYCHAIN)
1357         (id)kSecUseDataProtectionKeychain: @YES
1358 #else
1359         (id)kSecAttrNoLegacy: @YES
1360 #endif
1361     };
1362     OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, nullptr);
1363     EXPECT_EQ(status, errSecItemNotFound);
1364 }
1365
1366 // Skip the test because of <rdar://problem/59635486>.
1367 #if PLATFORM(MAC)
1368
1369 TEST(WebAuthenticationPanel, LAGetAssertion)
1370 {
1371     reset();
1372     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-la" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1373
1374     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1375     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1376
1377     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1378     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1379     [webView setUIDelegate:delegate.get()];
1380
1381     ASSERT_TRUE(addKeyToKeychain(testES256PrivateKeyBase64, "", testUserEntityBundleBase64));
1382     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1383     [webView waitForMessage:@"Succeeded!"];
1384     checkPanel([delegate panel], @"", @[adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportUSB]).get(), adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportInternal]).get()], _WKWebAuthenticationTypeGet);
1385     cleanUpKeychain("");
1386 }
1387
1388 TEST(WebAuthenticationPanel, LAGetAssertionNoMockNoUserGesture)
1389 {
1390     reset();
1391     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-la-no-mock" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1392
1393     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1394     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1395     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationLocalAuthenticatorExperimentalFeature()];
1396
1397     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1398     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1399     [webView setUIDelegate:delegate.get()];
1400
1401     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1402     Util::run(&webAuthenticationPanelRan);
1403     checkPanel([delegate panel], @"", @[adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportUSB]).get()], _WKWebAuthenticationTypeGet);
1404 }
1405
1406 TEST(WebAuthenticationPanel, LAGetAssertionMultipleOrder)
1407 {
1408     reset();
1409     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-la" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1410
1411     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1412     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1413     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationLocalAuthenticatorExperimentalFeature()];
1414
1415     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1416     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1417     [webView setUIDelegate:delegate.get()];
1418
1419     ASSERT_TRUE(addKeyToKeychain(testES256PrivateKeyBase64, "", testUserEntityBundleBase64));
1420     ASSERT_TRUE(addKeyToKeychain("BBRoi2JbR0IXTeJmvXUp1YIuM4sph/Lu3eGf75F7n+HojHKG70a4R0rB2PQce5/SJle6T7OO5Cqet/LJZVM6NQ8yDDxWvayf71GTDp2yUtuIbqJLFVbpWymlj9WRizgX3A==", "", "omJpZEoAAQIDBAUGBwgJZG5hbWVkSmFuZQ=="/* { "id": h'00010203040506070809', "name": "Jane" } */));
1421
1422     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1423     [webView waitForMessage:@"Succeeded!"];
1424     EXPECT_WK_STREQ(webAuthenticationPanelSelectedCredentialName, "John");
1425
1426     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1427     [webView waitForMessage:@"Succeeded!"];
1428     EXPECT_WK_STREQ(webAuthenticationPanelSelectedCredentialName, "Jane");
1429
1430     cleanUpKeychain("");
1431 }
1432
1433 #endif // PLATFORM(MAC)
1434
1435 #endif // USE(APPLE_INTERNAL_SDK) || PLATFORM(IOS)
1436
1437 } // namespace TestWebKitAPI
1438
1439 #endif // ENABLE(WEB_AUTHN)