259289bb77fb91a17cac1a83b3e1c310dbe404f2
[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 not valid: "];
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 not valid: "];
958 }
959
960 TEST(WebAuthenticationPanel, PinRequestPinError)
961 {
962     reset();
963     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin" 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     [webView waitForMessage:@"Pin is not valid: 123"];
975 }
976
977 TEST(WebAuthenticationPanel, PinGetPinTokenPinBlockedError)
978 {
979     reset();
980     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-get-pin-token-pin-blocked-error" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
981
982     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
983     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
984
985     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
986     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
987     [webView setUIDelegate:delegate.get()];
988
989     webAuthenticationPanelPin = "1234";
990     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
991     [webView waitForMessage:@"Unknown internal error. Error code: 50"];
992     EXPECT_FALSE(webAuthenticationPanelUpdatePINInvalid);
993     EXPECT_TRUE(webAuthenticationPanelUpdatePINBlocked);
994 }
995
996 TEST(WebAuthenticationPanel, PinGetPinTokenPinAuthBlockedError)
997 {
998     reset();
999     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-get-pin-token-pin-auth-blocked-error" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1000
1001     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1002     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1003
1004     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1005     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1006     [webView setUIDelegate:delegate.get()];
1007
1008     webAuthenticationPanelPin = "1234";
1009     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1010     [webView waitForMessage:@"Unknown internal error. Error code: 52"];
1011     EXPECT_FALSE(webAuthenticationPanelUpdatePINInvalid);
1012     EXPECT_TRUE(webAuthenticationPanelUpdatePINAuthBlocked);
1013 }
1014
1015 TEST(WebAuthenticationPanel, PinGetPinTokenPinInvalidErrorAndRetry)
1016 {
1017     reset();
1018     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-get-pin-token-pin-invalid-error-retry" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1019
1020     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1021     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1022
1023     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1024     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1025     [webView setUIDelegate:delegate.get()];
1026
1027     webAuthenticationPanelPin = "1234";
1028     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1029     [webView waitForMessage:@"Succeeded!"];
1030     EXPECT_TRUE(webAuthenticationPanelUpdatePINInvalid);
1031 }
1032
1033 TEST(WebAuthenticationPanel, PinGetPinTokenPinAuthInvalidErrorAndRetry)
1034 {
1035     reset();
1036     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"];
1037
1038     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1039     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1040
1041     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1042     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1043     [webView setUIDelegate:delegate.get()];
1044
1045     webAuthenticationPanelPin = "1234";
1046     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1047     [webView waitForMessage:@"Succeeded!"];
1048     EXPECT_TRUE(webAuthenticationPanelUpdatePINInvalid);
1049 }
1050
1051 TEST(WebAuthenticationPanel, MakeCredentialPin)
1052 {
1053     reset();
1054     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1055
1056     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1057     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1058
1059     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1060     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1061     [webView setUIDelegate:delegate.get()];
1062
1063     webAuthenticationPanelPin = "1234";
1064     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1065     [webView waitForMessage:@"Succeeded!"];
1066 }
1067
1068 TEST(WebAuthenticationPanel, MakeCredentialPinAuthBlockedError)
1069 {
1070     reset();
1071     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-auth-blocked-error" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1072
1073     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1074     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1075
1076     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1077     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1078     [webView setUIDelegate:delegate.get()];
1079
1080     webAuthenticationPanelPin = "1234";
1081     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1082     [webView waitForMessage:@"Unknown internal error. Error code: 52"];
1083     EXPECT_FALSE(webAuthenticationPanelUpdatePINInvalid);
1084     EXPECT_TRUE(webAuthenticationPanelUpdatePINAuthBlocked);
1085 }
1086
1087 TEST(WebAuthenticationPanel, MakeCredentialPinInvalidErrorAndRetry)
1088 {
1089     reset();
1090     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-hid-pin-invalid-error-retry" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1091
1092     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1093     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1094
1095     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1096     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1097     [webView setUIDelegate:delegate.get()];
1098
1099     webAuthenticationPanelPin = "1234";
1100     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1101     [webView waitForMessage:@"Succeeded!"];
1102     EXPECT_TRUE(webAuthenticationPanelUpdatePINInvalid);
1103 }
1104
1105 TEST(WebAuthenticationPanel, GetAssertionPin)
1106 {
1107     reset();
1108     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-pin" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1109
1110     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1111     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1112
1113     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1114     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1115     [webView setUIDelegate:delegate.get()];
1116
1117     webAuthenticationPanelPin = "1234";
1118     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1119     [webView waitForMessage:@"Succeeded!"];
1120 }
1121
1122 TEST(WebAuthenticationPanel, GetAssertionPinAuthBlockedError)
1123 {
1124     reset();
1125     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-pin-auth-blocked-error" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1126
1127     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1128     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1129
1130     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1131     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1132     [webView setUIDelegate:delegate.get()];
1133
1134     webAuthenticationPanelPin = "1234";
1135     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1136     [webView waitForMessage:@"Unknown internal error. Error code: 52"];
1137     EXPECT_FALSE(webAuthenticationPanelUpdatePINInvalid);
1138     EXPECT_TRUE(webAuthenticationPanelUpdatePINAuthBlocked);
1139 }
1140
1141 TEST(WebAuthenticationPanel, GetAssertionPinInvalidErrorAndRetry)
1142 {
1143     reset();
1144     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-pin-invalid-error-retry" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1145
1146     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1147     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1148
1149     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1150     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1151     [webView setUIDelegate:delegate.get()];
1152
1153     webAuthenticationPanelPin = "1234";
1154     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1155     [webView waitForMessage:@"Succeeded!"];
1156     EXPECT_TRUE(webAuthenticationPanelUpdatePINInvalid);
1157 }
1158
1159 TEST(WebAuthenticationPanel, MultipleAccountsNullDelegate)
1160 {
1161     reset();
1162     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-multiple-accounts" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1163
1164     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1165     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1166
1167     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1168     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1169     [delegate setIsNull:true];
1170     [webView setUIDelegate:delegate.get()];
1171
1172     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1173     [webView waitForMessage:@"Operation timed out."];
1174 }
1175
1176 TEST(WebAuthenticationPanel, MultipleAccounts)
1177 {
1178     reset();
1179     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-multiple-accounts" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1180
1181     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1182     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1183
1184     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1185     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1186     [webView setUIDelegate:delegate.get()];
1187
1188     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1189     [webView waitForMessage:@"Succeeded!"];
1190     EXPECT_EQ([[webView stringByEvaluatingJavaScript:@"userHandle"] isEqualToString:@"<null>"], webAuthenticationPanelNullUserHandle);
1191 }
1192
1193 // For macOS, only internal builds can sign keychain entitlemnets
1194 // which are required to run local authenticator tests.
1195 #if USE(APPLE_INTERNAL_SDK) || PLATFORM(IOS)
1196
1197 TEST(WebAuthenticationPanel, LAError)
1198 {
1199     reset();
1200     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-la-error" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1201
1202     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1203     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1204
1205     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1206     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1207     [webView setUIDelegate:delegate.get()];
1208
1209     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1210     Util::run(&webAuthenticationPanelUpdateLAError);
1211 }
1212
1213 TEST(WebAuthenticationPanel, LADuplicateCredential)
1214 {
1215     reset();
1216     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-la-duplicate-credential" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1217
1218     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1219     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1220
1221     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1222     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1223     [webView setUIDelegate:delegate.get()];
1224
1225     ASSERT_TRUE(addKeyToKeychain(testES256PrivateKeyBase64, "", testUserEntityBundleBase64));
1226     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1227     Util::run(&webAuthenticationPanelUpdateLAExcludeCredentialsMatched);
1228     cleanUpKeychain("");
1229 }
1230
1231 TEST(WebAuthenticationPanel, LANoCredential)
1232 {
1233     reset();
1234     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-la" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1235
1236     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1237     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1238
1239     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1240     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1241     [webView setUIDelegate:delegate.get()];
1242
1243     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1244     Util::run(&webAuthenticationPanelUpdateLANoCredential);
1245 }
1246
1247 TEST(WebAuthenticationPanel, LAMakeCredentialNullDelegate)
1248 {
1249     reset();
1250     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-la" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1251
1252     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1253     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1254
1255     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1256     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1257     [delegate setIsNull:true];
1258     [webView setUIDelegate:delegate.get()];
1259
1260     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1261     [webView waitForMessage:@"Disallow local authenticator."];
1262 }
1263
1264 TEST(WebAuthenticationPanel, LAMakeCredentialDisallowLocalAuthenticator)
1265 {
1266     reset();
1267     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-la" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1268
1269     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1270     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1271
1272     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1273     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1274     [webView setUIDelegate:delegate.get()];
1275
1276     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1277     [webView waitForMessage:@"Disallow local authenticator."];
1278 }
1279
1280 TEST(WebAuthenticationPanel, LAMakeCredentialAllowLocalAuthenticator)
1281 {
1282     reset();
1283     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-la" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1284
1285     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1286     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1287
1288     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1289     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1290     [webView setUIDelegate:delegate.get()];
1291
1292     localAuthenticatorPolicy = _WKLocalAuthenticatorPolicyAllow;
1293     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1294     [webView waitForMessage:@"Succeeded!"];
1295     checkPanel([delegate panel], @"", @[adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportUSB]).get(), adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportInternal]).get()], _WKWebAuthenticationTypeCreate);
1296     cleanUpKeychain("");
1297 }
1298
1299 TEST(WebAuthenticationPanel, LANoMockDefaultOff)
1300 {
1301     reset();
1302     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-la-no-mock" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1303
1304     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1305     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1306
1307     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1308     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1309     [webView setUIDelegate:delegate.get()];
1310
1311     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1312     Util::run(&webAuthenticationPanelRan);
1313     checkPanel([delegate panel], @"", @[adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportUSB]).get()], _WKWebAuthenticationTypeCreate);
1314 }
1315
1316 TEST(WebAuthenticationPanel, LAMakeCredentialNoMockNoUserGesture)
1317 {
1318     reset();
1319     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-la-no-mock" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1320
1321     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1322     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1323     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationLocalAuthenticatorExperimentalFeature()];
1324
1325     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1326     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1327     [webView setUIDelegate:delegate.get()];
1328
1329     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1330     Util::run(&webAuthenticationPanelRan);
1331     checkPanel([delegate panel], @"", @[adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportUSB]).get()], _WKWebAuthenticationTypeCreate);
1332 }
1333
1334 TEST(WebAuthenticationPanel, LAMakeCredentialRollBackCredential)
1335 {
1336     reset();
1337     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-make-credential-la-no-attestation" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1338
1339     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1340     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1341
1342     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1343     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1344     [webView setUIDelegate:delegate.get()];
1345
1346     localAuthenticatorPolicy = _WKLocalAuthenticatorPolicyAllow;
1347     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1348     [webView waitForMessage:@"Couldn't attest: The operation couldn't complete."];
1349
1350     NSDictionary *query = @{
1351         (id)kSecClass: (id)kSecClassKey,
1352         (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
1353         (id)kSecAttrLabel: @"",
1354 #if HAVE(DATA_PROTECTION_KEYCHAIN)
1355         (id)kSecUseDataProtectionKeychain: @YES
1356 #else
1357         (id)kSecAttrNoLegacy: @YES
1358 #endif
1359     };
1360     OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, nullptr);
1361     EXPECT_EQ(status, errSecItemNotFound);
1362 }
1363
1364 // Skip the test because of <rdar://problem/59635486>.
1365 #if PLATFORM(MAC)
1366
1367 TEST(WebAuthenticationPanel, LAGetAssertion)
1368 {
1369     reset();
1370     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-la" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1371
1372     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1373     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1374
1375     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1376     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1377     [webView setUIDelegate:delegate.get()];
1378
1379     ASSERT_TRUE(addKeyToKeychain(testES256PrivateKeyBase64, "", testUserEntityBundleBase64));
1380     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1381     [webView waitForMessage:@"Succeeded!"];
1382     checkPanel([delegate panel], @"", @[adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportUSB]).get(), adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportInternal]).get()], _WKWebAuthenticationTypeGet);
1383     cleanUpKeychain("");
1384 }
1385
1386 TEST(WebAuthenticationPanel, LAGetAssertionNoMockNoUserGesture)
1387 {
1388     reset();
1389     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-la-no-mock" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1390
1391     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1392     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1393     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationLocalAuthenticatorExperimentalFeature()];
1394
1395     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1396     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1397     [webView setUIDelegate:delegate.get()];
1398
1399     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1400     Util::run(&webAuthenticationPanelRan);
1401     checkPanel([delegate panel], @"", @[adoptNS([[NSNumber alloc] initWithInt:_WKWebAuthenticationTransportUSB]).get()], _WKWebAuthenticationTypeGet);
1402 }
1403
1404 TEST(WebAuthenticationPanel, LAGetAssertionMultipleOrder)
1405 {
1406     reset();
1407     RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-la" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
1408
1409     auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
1410     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
1411     [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationLocalAuthenticatorExperimentalFeature()];
1412
1413     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
1414     auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
1415     [webView setUIDelegate:delegate.get()];
1416
1417     ASSERT_TRUE(addKeyToKeychain(testES256PrivateKeyBase64, "", testUserEntityBundleBase64));
1418     ASSERT_TRUE(addKeyToKeychain("BBRoi2JbR0IXTeJmvXUp1YIuM4sph/Lu3eGf75F7n+HojHKG70a4R0rB2PQce5/SJle6T7OO5Cqet/LJZVM6NQ8yDDxWvayf71GTDp2yUtuIbqJLFVbpWymlj9WRizgX3A==", "", "omJpZEoAAQIDBAUGBwgJZG5hbWVkSmFuZQ=="/* { "id": h'00010203040506070809', "name": "Jane" } */));
1419
1420     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1421     [webView waitForMessage:@"Succeeded!"];
1422     EXPECT_WK_STREQ(webAuthenticationPanelSelectedCredentialName, "John");
1423
1424     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
1425     [webView waitForMessage:@"Succeeded!"];
1426     EXPECT_WK_STREQ(webAuthenticationPanelSelectedCredentialName, "Jane");
1427
1428     cleanUpKeychain("");
1429 }
1430
1431 #endif // PLATFORM(MAC)
1432
1433 #endif // USE(APPLE_INTERNAL_SDK) || PLATFORM(IOS)
1434
1435 } // namespace TestWebKitAPI
1436
1437 #endif // ENABLE(WEB_AUTHN)