Changeset 236842 in webkit


Ignore:
Timestamp:
Oct 4, 2018 12:32:14 PM (6 years ago)
Author:
jiewen_tan@apple.com
Message:

[WebAuthN] Move time out control from WebProcess to UIProcess
https://bugs.webkit.org/show_bug.cgi?id=189642
<rdar://problem/44476765>

Reviewed by Chris Dumez.

Source/WebCore:

Since now the control unit of WebAuthN has been moved to UI Process, i.e. AuthenticatorManager,
the time out timer should move to UI Process as well.

Tests: http/wpt/webauthn/public-key-credential-create-failure-local-silent.https.html

http/wpt/webauthn/public-key-credential-get-failure-local-silent.https.html

  • Modules/webauthn/AuthenticatorCoordinator.cpp:

(WebCore::AuthenticatorCoordinator::create const):
(WebCore::AuthenticatorCoordinator::discoverFromExternalSource const):
(WebCore::AuthenticatorCoordinatorInternal::initTimeoutTimer): Deleted.
(WebCore::AuthenticatorCoordinatorInternal::didTimeoutTimerFire): Deleted.

  • Modules/webauthn/PublicKeyCredentialCreationOptions.h:

(WebCore::PublicKeyCredentialCreationOptions::encode const):
(WebCore::PublicKeyCredentialCreationOptions::decode):

  • Modules/webauthn/PublicKeyCredentialRequestOptions.h:

(WebCore::PublicKeyCredentialRequestOptions::encode const):
(WebCore::PublicKeyCredentialRequestOptions::decode):

Source/WebKit:

Besides adding a time out timer in the AuthenticatorManager, this patch also adds a new
option in MockWebAuthenticationConfiguration to turn on silent failure which is the
default policy of treating authenticators' error as suggested by spec.

  • UIProcess/API/C/WKWebsiteDataStoreRef.cpp:

(WKWebsiteDataStoreSetWebAuthenticationMockConfiguration):

  • UIProcess/WebAuthentication/AuthenticatorManager.cpp:

(WebKit::AuthenticatorManagerInternal::collectTransports):
(WebKit::AuthenticatorManager::makeCredential):
(WebKit::AuthenticatorManager::getAssertion):
(WebKit::AuthenticatorManager::respondReceived):
(WebKit::AuthenticatorManager::initTimeOutTimer):

  • UIProcess/WebAuthentication/AuthenticatorManager.h:

(WebKit::AuthenticatorManager::requestTimeOutTimer):

  • UIProcess/WebAuthentication/Mock/MockAuthenticatorManager.cpp:

(WebKit::MockAuthenticatorManager::respondReceivedInternal):

  • UIProcess/WebAuthentication/Mock/MockWebAuthenticationConfiguration.h:

Tools:

  • WebKitTestRunner/InjectedBundle/TestRunner.cpp:

(WTR::TestRunner::setWebAuthenticationMockConfiguration):

LayoutTests:

This patch also fixes some flaky behaviours regarding to the dirty ASN.1 decoder.

  • http/wpt/webauthn/public-key-credential-create-failure-local-silent.https-expected.txt: Added.
  • http/wpt/webauthn/public-key-credential-create-failure-local-silent.https.html: Copied from LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-local.https.html.
  • http/wpt/webauthn/public-key-credential-create-failure-local.https-expected.txt:
  • http/wpt/webauthn/public-key-credential-create-failure-local.https.html:
  • http/wpt/webauthn/public-key-credential-create-failure.https-expected.txt:
  • http/wpt/webauthn/public-key-credential-create-failure.https.html:
  • http/wpt/webauthn/public-key-credential-get-failure-local-silent.https-expected.txt: Added.
  • http/wpt/webauthn/public-key-credential-get-failure-local-silent.https.html: Copied from LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-local.https.html.
  • http/wpt/webauthn/public-key-credential-get-failure-local.https-expected.txt:
  • http/wpt/webauthn/public-key-credential-get-failure-local.https.html:
  • http/wpt/webauthn/public-key-credential-get-failure.https-expected.txt:
  • http/wpt/webauthn/public-key-credential-get-failure.https.html:
  • http/wpt/webauthn/resources/util.js:
Location:
trunk
Files:
2 added
23 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r236841 r236842  
     12018-10-04  Jiewen Tan  <jiewen_tan@apple.com>
     2
     3        [WebAuthN] Move time out control from WebProcess to UIProcess
     4        https://bugs.webkit.org/show_bug.cgi?id=189642
     5        <rdar://problem/44476765>
     6
     7        Reviewed by Chris Dumez.
     8
     9        This patch also fixes some flaky behaviours regarding to the dirty ASN.1 decoder.
     10
     11        * http/wpt/webauthn/public-key-credential-create-failure-local-silent.https-expected.txt: Added.
     12        * http/wpt/webauthn/public-key-credential-create-failure-local-silent.https.html: Copied from LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-local.https.html.
     13        * http/wpt/webauthn/public-key-credential-create-failure-local.https-expected.txt:
     14        * http/wpt/webauthn/public-key-credential-create-failure-local.https.html:
     15        * http/wpt/webauthn/public-key-credential-create-failure.https-expected.txt:
     16        * http/wpt/webauthn/public-key-credential-create-failure.https.html:
     17        * http/wpt/webauthn/public-key-credential-get-failure-local-silent.https-expected.txt: Added.
     18        * http/wpt/webauthn/public-key-credential-get-failure-local-silent.https.html: Copied from LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-local.https.html.
     19        * http/wpt/webauthn/public-key-credential-get-failure-local.https-expected.txt:
     20        * http/wpt/webauthn/public-key-credential-get-failure-local.https.html:
     21        * http/wpt/webauthn/public-key-credential-get-failure.https-expected.txt:
     22        * http/wpt/webauthn/public-key-credential-get-failure.https.html:
     23        * http/wpt/webauthn/resources/util.js:
     24
    1252018-10-04  Chris Dumez  <cdumez@apple.com>
    226
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-local-silent.https.html

    r236841 r236842  
    11<!DOCTYPE html>
    2 <title>Web Authentication API: PublicKeyCredential's [[create]] failure cases with a mock local authenticator.</title>
     2<title>Web Authentication API: PublicKeyCredential's [[create]] silent failure cases with a mock local authenticator.</title>
    33<script src="/resources/testharness.js"></script>
    44<script src="/resources/testharnessreport.js"></script>
     
    77    // Default mock configuration. Tests need to override if they need different configuration.
    88    if (window.testRunner)
    9         testRunner.setWebAuthenticationMockConfiguration({ local: { acceptAuthentication: false, acceptAttestation: false } });
     9        testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, local: { acceptAuthentication: false, acceptAttestation: false } });
    1010
    1111    promise_test(t => {
     
    2222                challenge: asciiToUint8Array("123456"),
    2323                pubKeyCredParams: [{ type: "public-key", alg: -35 }, { type: "public-key", alg: -257 }], // ES384, RS256
     24                timeout: 10
    2425            }
    2526        };
    26         return promiseRejects(t, "NotSupportedError", navigator.credentials.create(options), "The platform attached authenticator doesn't support any provided PublicKeyCredentialParameters.");
    27     }, "PublicKeyCredential's [[create]] with unsupported public key credential parameters in a mock local authenticator.");
     27        return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "Operation timed out.");
     28    }, "PublicKeyCredential's [[create]] with silent failure in a mock local authenticator.");
    2829
    2930    promise_test(t => {
     
    4041                challenge: asciiToUint8Array("123456"),
    4142                pubKeyCredParams: [{ type: "public-key", alg: -7 }],
    42                 excludeCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }]
     43                excludeCredentials: [{ type: "public-key", id: Base64URL.parse(testCredentialIdBase64) }],
     44                timeout: 10
    4345            }
    4446        };
    4547        if (window.testRunner)
    4648            testRunner.addTestKeyToKeychain(testES256PrivateKeyBase64, testRpId, testUserhandleBase64);
    47         return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "At least one credential matches an entry of the excludeCredentials list in the platform attached authenticator.").then(() => {
     49        return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "Operation timed out.").then(() => {
    4850            if (window.testRunner)
    4951                testRunner.cleanUpKeychain(testRpId);
    5052        });
    51     }, "PublicKeyCredential's [[create]] with matched exclude credentials in a mock local authenticator.");
     53    }, "PublicKeyCredential's [[create]] with silent failure in a mock local authenticator. 2");
    5254
    5355    promise_test(t => {
     
    6971                    { type: "public-key", id: Base64URL.parse(testCredentialIdBase64), transports: ["ble"] },
    7072                    { type: "public-key", id: Base64URL.parse(testCredentialIdBase64), transports: ["internal"] }
    71                 ]
     73                ],
     74                timeout: 10
    7275            }
    7376        };
    7477        if (window.testRunner)
    7578            testRunner.addTestKeyToKeychain(testES256PrivateKeyBase64, testRpId, testUserhandleBase64);
    76         return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "At least one credential matches an entry of the excludeCredentials list in the platform attached authenticator.").then(() => {
     79        return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "Operation timed out.").then(() => {
    7780            if (window.testRunner)
    7881                testRunner.cleanUpKeychain(testRpId);
    7982        });
    80     }, "PublicKeyCredential's [[create]] with matched exclude credentials in a mock local authenticator. 2nd");
     83    }, "PublicKeyCredential's [[create]] with silent failure in a mock local authenticator. 3");
    8184
    8285    promise_test(t => {
     
    9295                },
    9396                challenge: asciiToUint8Array("123456"),
    94                 pubKeyCredParams: [{ type: "public-key", alg: -7 }]
     97                pubKeyCredParams: [{ type: "public-key", alg: -7 }],
     98                timeout: 10
    9599            }
    96100        };
    97         return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "Couldn't get user consent.");
    98     }, "PublicKeyCredential's [[create]] without user consent in a mock local authenticator.");
     101        return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "Operation timed out.");
     102    }, "PublicKeyCredential's [[create]] with silent failure in a mock local authenticator. 4");
    99103
    100104    promise_test(t => {
     
    110114                },
    111115                challenge: asciiToUint8Array("123456"),
    112                 pubKeyCredParams: [{ type: "public-key", alg: -7 }]
     116                pubKeyCredParams: [{ type: "public-key", alg: -7 }],
     117                timeout: 10
    113118            }
    114119        };
    115120        if (window.testRunner)
    116             testRunner.setWebAuthenticationMockConfiguration({ local: { acceptAuthentication: true, acceptAttestation: false } });
    117         return promiseRejects(t, "UnknownError", navigator.credentials.create(options), "Unknown internal error.");
    118     }, "PublicKeyCredential's [[create]] without attestation in a mock local authenticator.");
     121            testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, local: { acceptAuthentication: true, acceptAttestation: false } });
     122        return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "Operation timed out.");
     123    }, "PublicKeyCredential's [[create]] with silent failure in a mock local authenticator. 5");
    119124
    120125    promise_test(t => {
     
    130135                },
    131136                challenge: asciiToUint8Array("123456"),
    132                 pubKeyCredParams: [{ type: "public-key", alg: -7 }]
     137                pubKeyCredParams: [{ type: "public-key", alg: -7 }],
     138                timeout: 10
    133139            }
    134140        };
    135141        if (window.testRunner) {
    136             testRunner.setWebAuthenticationMockConfiguration({ local: { acceptAuthentication: true, acceptAttestation: false } });
     142            testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, local: { acceptAuthentication: true, acceptAttestation: false } });
    137143            testRunner.addTestKeyToKeychain(testES256PrivateKeyBase64, testRpId, testUserhandleBase64);
    138144        }
    139         return promiseRejects(t, "UnknownError", navigator.credentials.create(options), "Unknown internal error.").then(() => {
     145        return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "Operation timed out.").then(() => {
    140146            if (window.testRunner)
    141147                assert_false(testRunner.keyExistsInKeychain(testRpId, testUserhandleBase64));
    142148        });
    143     }, "PublicKeyCredential's [[create]] deleting old credential in a mock local authenticator.");
     149    }, "PublicKeyCredential's [[create]] with silent failure in a mock local authenticator. 6");
    144150</script>
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-local.https-expected.txt

    r236481 r236842  
    66PASS PublicKeyCredential's [[create]] without attestation in a mock local authenticator.
    77PASS PublicKeyCredential's [[create]] deleting old credential in a mock local authenticator.
     8PASS PublicKeyCredential's [[create]] with timeout in a mock local authenticator.
    89
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure-local.https.html

    r236686 r236842  
    142142        });
    143143    }, "PublicKeyCredential's [[create]] deleting old credential in a mock local authenticator.");
     144
     145    promise_test(function(t) {
     146        const options = {
     147            publicKey: {
     148                rp: {
     149                    name: "example.com"
     150                },
     151                user: {
     152                    name: "John Appleseed",
     153                    id: asciiToUint8Array("123456"),
     154                    displayName: "John",
     155                },
     156                challenge: asciiToUint8Array("123456"),
     157                pubKeyCredParams: [{ type: "public-key", alg: -7 }],
     158                timeout: 10,
     159                authenticatorSelection: { authenticatorAttachment: "cross-platform" }
     160            }
     161        };
     162
     163        if (window.testRunner)
     164            testRunner.setWebAuthenticationMockConfiguration({ local: { acceptAuthentication: false, acceptAttestation: false } });
     165        return promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "Operation timed out.");
     166    }, "PublicKeyCredential's [[create]] with timeout in a mock local authenticator.");
    144167</script>
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure.https-expected.txt

    r236625 r236842  
    11
     2PASS PublicKeyCredential's [[create]] with timeout
    23PASS PublicKeyCredential's [[create]] with a mismatched RP ID
    34PASS PublicKeyCredential's [[create]] with an empty pubKeyCredParams
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure.https.html

    r236625 r236842  
    99        testRunner.setWebAuthenticationMockConfiguration({ });
    1010
    11     // FIXME(189642): Re-enable the following test.
    12     // promise_test(function(t) {
    13     //     const options = {
    14     //         publicKey: {
    15     //             rp: {
    16     //                 name: "example.com"
    17     //             },
    18     //             user: {
    19     //                 name: "John Appleseed",
    20     //                 id: asciiToUint8Array("123456"),
    21     //                 displayName: "John",
    22     //             },
    23     //             challenge: asciiToUint8Array("123456"),
    24     //             pubKeyCredParams: [{ type: "public-key", alg: -7 }],
    25     //             timeout: 0,
    26     //         }
    27     //     };
    28     //
    29     //     return promiseRejects(t, "NotAllowedError",
    30     //         navigator.credentials.create(options), "Operation timed out.");
    31     // }, "PublicKeyCredential's [[create]] with timeout");
     11    promise_test(function(t) {
     12        const options = {
     13            publicKey: {
     14                rp: {
     15                    name: "example.com"
     16                },
     17                user: {
     18                    name: "John Appleseed",
     19                    id: asciiToUint8Array("123456"),
     20                    displayName: "John",
     21                },
     22                challenge: asciiToUint8Array("123456"),
     23                pubKeyCredParams: [{ type: "public-key", alg: -7 }],
     24                timeout: 10,
     25            }
     26        };
     27
     28        return promiseRejects(t, "NotAllowedError",
     29            navigator.credentials.create(options), "Operation timed out.");
     30    }, "PublicKeyCredential's [[create]] with timeout");
    3231
    3332    promise_test(function(t) {
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-local-silent.https.html

    r236841 r236842  
    77    // Default mock configuration. Tests need to override if they need different configuration.
    88    if (window.testRunner)
    9         testRunner.setWebAuthenticationMockConfiguration({ local: { acceptAuthentication: false, acceptAttestation: false } });
     9        testRunner.setWebAuthenticationMockConfiguration({ silentFailure: true, local: { acceptAuthentication: false, acceptAttestation: false } });
    1010
    1111    promise_test(t => {
     
    1818                    { type: "public-key", id: Base64URL.parse(testCredentialIdBase64), transports: ["ble"] },
    1919                    { type: "public-key", id: Base64URL.parse(testCredentialIdBase64), transports: ["internal"] }
    20                 ]
     20                ],
     21                timeout: 10
    2122            }
    2223        };
    2324
    24         return promiseRejects(t, "NotAllowedError", navigator.credentials.get(options), "No matched credentials are found in the platform attached authenticator.");
    25     }, "PublicKeyCredential's [[get]] with no matched credentials in a mock local authenticator.");
     25        return promiseRejects(t, "NotAllowedError", navigator.credentials.get(options), "Operation timed out.");
     26    }, "PublicKeyCredential's [[get]] with silent failure in a mock local authenticator.");
    2627
    2728    promise_test(t => {
     
    3132                allowCredentials: [
    3233                    { type: "public-key", id: Base64URL.parse(testUserhandleBase64) }
    33                 ]
     34                ],
     35                timeout: 10
    3436            }
    3537        };
     
    3739        if (window.testRunner)
    3840            testRunner.addTestKeyToKeychain(testES256PrivateKeyBase64, testRpId, testUserhandleBase64);
    39         return promiseRejects(t, "NotAllowedError", navigator.credentials.get(options), "No matched credentials are found in the platform attached authenticator.").then(() => {
     41        return promiseRejects(t, "NotAllowedError", navigator.credentials.get(options), "Operation timed out.").then(() => {
    4042                if (window.testRunner)
    4143                    testRunner.cleanUpKeychain(testRpId);
    4244            });
    43     }, "PublicKeyCredential's [[get]] with no matched credentials in a mock local authenticator. 2nd");
     45    }, "PublicKeyCredential's [[get]] with silent failure in a mock local authenticator. 2");
    4446
    4547    promise_test(t => {
    4648        const options = {
    4749            publicKey: {
    48                 challenge: asciiToUint8Array("123456")
     50                challenge: asciiToUint8Array("123456"),
     51                timeout: 10
    4952            }
    5053        };
     
    5255        if (window.testRunner)
    5356            testRunner.addTestKeyToKeychain(testES256PrivateKeyBase64, testRpId, testUserhandleBase64);
    54         return promiseRejects(t, "NotAllowedError", navigator.credentials.get(options), "Couldn't get user consent.").then(() => {
     57        return promiseRejects(t, "NotAllowedError", navigator.credentials.get(options), "Operation timed out.").then(() => {
    5558            if (window.testRunner)
    5659                testRunner.cleanUpKeychain(testRpId);
    5760        });
    58     }, "PublicKeyCredential's [[get]] without user consent in a mock local authenticator.");
     61    }, "PublicKeyCredential's [[get]] with silent failure in a mock local authenticator. 3");
    5962</script>
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-local.https-expected.txt

    r236481 r236842  
    33PASS PublicKeyCredential's [[get]] with no matched credentials in a mock local authenticator. 2nd
    44PASS PublicKeyCredential's [[get]] without user consent in a mock local authenticator.
     5PASS PublicKeyCredential's [[get]] with timeout in a mock local authenticator.
    56
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure-local.https.html

    r236686 r236842  
    5757        });
    5858    }, "PublicKeyCredential's [[get]] without user consent in a mock local authenticator.");
     59
     60    promise_test(t => {
     61        const options = {
     62            publicKey: {
     63                challenge: asciiToUint8Array("123456"),
     64                allowCredentials: [
     65                    { type: "public-key", id: Base64URL.parse(testCredentialIdBase64), transports: ["usb"] },
     66                    { type: "public-key", id: Base64URL.parse(testCredentialIdBase64), transports: ["nfc"] },
     67                    { type: "public-key", id: Base64URL.parse(testCredentialIdBase64), transports: ["ble"] }
     68                ],
     69                timeout: 10
     70            }
     71        };
     72
     73        return promiseRejects(t, "NotAllowedError", navigator.credentials.get(options), "Operation timed out.");
     74    }, "PublicKeyCredential's [[get]] with timeout in a mock local authenticator.");
    5975</script>
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure.https-expected.txt

    r236625 r236842  
    11
     2PASS PublicKeyCredential's [[get]] with timeout
    23PASS PublicKeyCredential's [[get]] with a mismatched RP ID
    34
  • trunk/LayoutTests/http/wpt/webauthn/public-key-credential-get-failure.https.html

    r236625 r236842  
    99        testRunner.setWebAuthenticationMockConfiguration({ });
    1010
    11     // FIXME(189642): Re-enable the following test.
    12     // promise_test(function(t) {
    13     //     const options = {
    14     //         publicKey: {
    15     //             challenge: asciiToUint8Array("123456"),
    16     //             timeout: 0,
    17     //         }
    18     //     };
    19     //
    20     //     return promiseRejects(t, "NotAllowedError",
    21     //         navigator.credentials.get(options), "Operation timed out.");
    22     // }, "PublicKeyCredential's [[get]] with timeout");
     11    promise_test(t => {
     12        const options = {
     13            publicKey: {
     14                challenge: asciiToUint8Array("123456"),
     15                timeout: 10
     16            }
     17        };
    2318
    24     promise_test(function(t) {
     19        return promiseRejects(t, "NotAllowedError",
     20            navigator.credentials.get(options), "Operation timed out.");
     21    }, "PublicKeyCredential's [[get]] with timeout");
     22
     23    promise_test(t => {
    2524        const options = {
    2625            publicKey: {
    2726                rpId: "example.com",
    28                 challenge: asciiToUint8Array("123456"),
     27                challenge: asciiToUint8Array("123456")
    2928            }
    3029        };
     30
    3131        return promiseRejects(t, "SecurityError",
    3232            navigator.credentials.get(options), "The origin of the document is not a registrable domain suffix of the provided RP ID.");
  • trunk/LayoutTests/http/wpt/webauthn/resources/util.js

    r236686 r236842  
    173173    const signature = new Uint8Array(asn1signature);
    174174    let tmp = new Uint8Array(64);
     175
    175176    const rStart =  signature[3] - 32;
    176     tmp.set(new Uint8Array(signature.slice(4 + rStart, 36 + rStart)), 0);
     177    if (rStart >= 0)
     178        tmp.set(new Uint8Array(signature.slice(4 + rStart, 36 + rStart)), 0);
     179    else
     180        tmp.set(new Uint8Array(signature.slice(4, 36 + rStart)), -rStart);
     181
    177182    const sStart =  signature[37 + rStart] - 32;
    178     tmp.set(new Uint8Array(signature.slice(38 + rStart + sStart)), 32);
     183    if (sStart >= 0)
     184        tmp.set(new Uint8Array(signature.slice(38 + rStart + sStart)), 32);
     185    else
     186        tmp.set(new Uint8Array(signature.slice(38 + rStart)), 32 - sStart);
     187
    179188    return tmp.buffer;
    180189}
  • trunk/Source/WebCore/ChangeLog

    r236841 r236842  
     12018-10-04  Jiewen Tan  <jiewen_tan@apple.com>
     2
     3        [WebAuthN] Move time out control from WebProcess to UIProcess
     4        https://bugs.webkit.org/show_bug.cgi?id=189642
     5        <rdar://problem/44476765>
     6
     7        Reviewed by Chris Dumez.
     8
     9        Since now the control unit of WebAuthN has been moved to UI Process, i.e. AuthenticatorManager,
     10        the time out timer should move to UI Process as well.
     11
     12        Tests: http/wpt/webauthn/public-key-credential-create-failure-local-silent.https.html
     13               http/wpt/webauthn/public-key-credential-get-failure-local-silent.https.html
     14
     15        * Modules/webauthn/AuthenticatorCoordinator.cpp:
     16        (WebCore::AuthenticatorCoordinator::create const):
     17        (WebCore::AuthenticatorCoordinator::discoverFromExternalSource const):
     18        (WebCore::AuthenticatorCoordinatorInternal::initTimeoutTimer): Deleted.
     19        (WebCore::AuthenticatorCoordinatorInternal::didTimeoutTimerFire): Deleted.
     20        * Modules/webauthn/PublicKeyCredentialCreationOptions.h:
     21        (WebCore::PublicKeyCredentialCreationOptions::encode const):
     22        (WebCore::PublicKeyCredentialCreationOptions::decode):
     23        * Modules/webauthn/PublicKeyCredentialRequestOptions.h:
     24        (WebCore::PublicKeyCredentialRequestOptions::encode const):
     25        (WebCore::PublicKeyCredentialRequestOptions::decode):
     26
    1272018-10-04  Chris Dumez  <cdumez@apple.com>
    228
  • trunk/Source/WebCore/Modules/webauthn/AuthenticatorCoordinator.cpp

    r235888 r236842  
    3939#include "PublicKeyCredentialRequestOptions.h"
    4040#include "SecurityOrigin.h"
    41 #include "Timer.h"
    4241#include <pal/crypto/CryptoDigest.h>
    4342#include <wtf/JSONValues.h>
     
    8382}
    8483
    85 // FIXME(181947): We should probably trim timeOutInMs to some max allowable number.
    86 static std::unique_ptr<Timer> initTimeoutTimer(std::optional<unsigned long> timeOutInMs, const CredentialPromise& promise)
    87 {
    88     if (!timeOutInMs)
    89         return nullptr;
    90 
    91     auto timer = std::make_unique<Timer>([promise = promise] () mutable {
    92         promise.reject(Exception { NotAllowedError, "Operation timed out."_s });
    93     });
    94     timer->startOneShot(Seconds::fromMilliseconds(*timeOutInMs));
    95     return timer;
    96 }
    97 
    98 static bool didTimeoutTimerFire(Timer* timer)
    99 {
    100     if (!timer)
    101         return false;
    102     if (!timer->isActive())
    103         return true;
    104     timer->stop();
    105     return false;
    106 }
    107 
    10884} // namespace AuthenticatorCoordinatorInternal
    10985
     
    131107    }
    132108
    133     // Step 4 & 17.
    134     std::unique_ptr<Timer> timeoutTimer = initTimeoutTimer(options.timeout, promise);
    135 
    136109    // Step 5-7.
    137110    // FIXME(181950): We lack fundamental support from SecurityOrigin to determine if a host is a valid domain or not.
     
    157130    auto clientDataJsonHash = produceClientDataJsonHash(clientDataJson);
    158131
    159     // Step 18-21.
     132    // Step 4, 17-21.
    160133    // Only platform attachments will be supported at this stage. Assuming one authenticator per device.
    161134    // Also, resident keys, user verifications and direct attestation are enforced at this tage.
     
    166139    }
    167140
    168     auto completionHandler = [clientDataJson = WTFMove(clientDataJson), promise = WTFMove(promise), timeoutTimer = WTFMove(timeoutTimer), abortSignal = WTFMove(abortSignal)] (const WebCore::PublicKeyCredentialData& data, const WebCore::ExceptionData& exception) mutable {
    169         if (didTimeoutTimerFire(timeoutTimer.get()))
    170             return;
     141    auto completionHandler = [clientDataJson = WTFMove(clientDataJson), promise = WTFMove(promise), abortSignal = WTFMove(abortSignal)] (const WebCore::PublicKeyCredentialData& data, const WebCore::ExceptionData& exception) mutable {
    171142        if (abortSignal && abortSignal->aborted()) {
    172143            promise.reject(Exception { AbortError, "Aborted by AbortSignal."_s });
     
    199170    }
    200171
    201     // Step 4 & 16.
    202     std::unique_ptr<Timer> timeoutTimer = initTimeoutTimer(options.timeout, promise);
    203 
    204172    // Step 5-7.
    205173    // FIXME(181950): We lack fundamental support from SecurityOrigin to determine if a host is a valid domain or not.
     
    217185    auto clientDataJsonHash = produceClientDataJsonHash(clientDataJson);
    218186
    219     // Step 14-15, 17-19.
     187    // Step 4, 14-19.
    220188    // Only platform attachments will be supported at this stage. Assuming one authenticator per device.
    221189    // Also, resident keys, user verifications and direct attestation are enforced at this tage.
     
    226194    }
    227195
    228     auto completionHandler = [clientDataJson = WTFMove(clientDataJson), promise = WTFMove(promise), timeoutTimer = WTFMove(timeoutTimer), abortSignal = WTFMove(abortSignal)] (const WebCore::PublicKeyCredentialData& data, const WebCore::ExceptionData& exception) mutable {
    229         if (didTimeoutTimerFire(timeoutTimer.get()))
    230             return;
     196    auto completionHandler = [clientDataJson = WTFMove(clientDataJson), promise = WTFMove(promise), abortSignal = WTFMove(abortSignal)] (const WebCore::PublicKeyCredentialData& data, const WebCore::ExceptionData& exception) mutable {
    231197        if (abortSignal && abortSignal->aborted()) {
    232198            promise.reject(Exception { AbortError, "Aborted by AbortSignal."_s });
  • trunk/Source/WebCore/Modules/webauthn/PublicKeyCredentialCreationOptions.h

    r236481 r236842  
    7979    Vector<Parameters> pubKeyCredParams;
    8080
    81     std::optional<unsigned long> timeout;
     81    std::optional<unsigned> timeout;
    8282    Vector<PublicKeyCredentialDescriptor> excludeCredentials;
    8383    std::optional<AuthenticatorSelectionCriteria> authenticatorSelection;
     
    126126    encoder << static_cast<uint64_t>(user.id.length());
    127127    encoder.encodeFixedLengthData(user.id.data(), user.id.length(), 1);
    128     encoder << user.displayName << user.name << user.icon << pubKeyCredParams << excludeCredentials << authenticatorSelection;
     128    encoder << user.displayName << user.name << user.icon << pubKeyCredParams << timeout << excludeCredentials << authenticatorSelection;
    129129}
    130130
     
    149149    if (!decoder.decode(result.pubKeyCredParams))
    150150        return std::nullopt;
     151
     152    std::optional<std::optional<unsigned>> timeout;
     153    decoder >> timeout;
     154    if (!timeout)
     155        return std::nullopt;
     156    result.timeout = WTFMove(*timeout);
     157
    151158    if (!decoder.decode(result.excludeCredentials))
    152159        return std::nullopt;
     
    156163    if (!authenticatorSelection)
    157164        return std::nullopt;
    158     result.authenticatorSelection = WTFMove(authenticatorSelection.value());
     165    result.authenticatorSelection = WTFMove(*authenticatorSelection);
    159166
    160167    return result;
  • trunk/Source/WebCore/Modules/webauthn/PublicKeyCredentialRequestOptions.h

    r230012 r236842  
    3636struct PublicKeyCredentialRequestOptions {
    3737    BufferSource challenge;
    38     std::optional<unsigned long> timeout;
     38    std::optional<unsigned> timeout;
    3939    mutable String rpId;
    4040    Vector<PublicKeyCredentialDescriptor> allowCredentials;
     
    4848void PublicKeyCredentialRequestOptions::encode(Encoder& encoder) const
    4949{
    50     encoder << rpId << allowCredentials;
     50    encoder << timeout << rpId << allowCredentials;
    5151}
    5252
     
    5555{
    5656    PublicKeyCredentialRequestOptions result;
     57
     58    std::optional<std::optional<unsigned>> timeout;
     59    decoder >> timeout;
     60    if (!timeout)
     61        return std::nullopt;
     62    result.timeout = WTFMove(*timeout);
     63
    5764    if (!decoder.decode(result.rpId))
    5865        return std::nullopt;
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r236840 r236842  
    1882018820                        sourceTree = "<group>";
    1882118821                };
    18822                 574F55DD204F3744002948C6 /* cocoa */ = {
    18823                         isa = PBXGroup;
    18824                         children = (
    18825                         );
    18826                         path = cocoa;
    18827                         sourceTree = "<group>";
    18828                 };
    1882918822                57C7A6881E56946D00C67D71 /* credentialmanagement */ = {
    1883018823                        isa = PBXGroup;
     
    1886818861                        children = (
    1886918862                                57303BB32006C6ED00355965 /* cbor */,
    18870                                 574F55DD204F3744002948C6 /* cocoa */,
    1887118863                                57303C272009B2FC00355965 /* AuthenticatorAssertionResponse.h */,
    1887218864                                57303C292009B2FC00355965 /* AuthenticatorAssertionResponse.idl */,
  • trunk/Source/WebKit/ChangeLog

    r236840 r236842  
     12018-10-04  Jiewen Tan  <jiewen_tan@apple.com>
     2
     3        [WebAuthN] Move time out control from WebProcess to UIProcess
     4        https://bugs.webkit.org/show_bug.cgi?id=189642
     5        <rdar://problem/44476765>
     6
     7        Reviewed by Chris Dumez.
     8
     9        Besides adding a time out timer in the AuthenticatorManager, this patch also adds a new
     10        option in MockWebAuthenticationConfiguration to turn on silent failure which is the
     11        default policy of treating authenticators' error as suggested by spec.
     12
     13        * UIProcess/API/C/WKWebsiteDataStoreRef.cpp:
     14        (WKWebsiteDataStoreSetWebAuthenticationMockConfiguration):
     15        * UIProcess/WebAuthentication/AuthenticatorManager.cpp:
     16        (WebKit::AuthenticatorManagerInternal::collectTransports):
     17        (WebKit::AuthenticatorManager::makeCredential):
     18        (WebKit::AuthenticatorManager::getAssertion):
     19        (WebKit::AuthenticatorManager::respondReceived):
     20        (WebKit::AuthenticatorManager::initTimeOutTimer):
     21        * UIProcess/WebAuthentication/AuthenticatorManager.h:
     22        (WebKit::AuthenticatorManager::requestTimeOutTimer):
     23        * UIProcess/WebAuthentication/Mock/MockAuthenticatorManager.cpp:
     24        (WebKit::MockAuthenticatorManager::respondReceivedInternal):
     25        * UIProcess/WebAuthentication/Mock/MockWebAuthenticationConfiguration.h:
     26
    1272018-10-04  Yuhan Wu  <yuhan_wu@apple.com>
    228
  • trunk/Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.cpp

    r236686 r236842  
    578578    MockWebAuthenticationConfiguration configuration;
    579579
     580    auto silentFailureRef = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(configurationRef, adoptWK(WKStringCreateWithUTF8CString("SilentFailure")).get()));
     581    if (silentFailureRef)
     582        configuration.silentFailure = WKBooleanGetValue(silentFailureRef);
     583
    580584    auto localRef = static_cast<WKDictionaryRef>(WKDictionaryGetItemForKey(configurationRef, adoptWK(WKStringCreateWithUTF8CString("Local")).get()));
    581585    if (localRef) {
  • trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp

    r236481 r236842  
    3939
    4040const size_t maxTransportNumber = 1;
     41// Suggested by WebAuthN spec as of 7 August 2018.
     42const unsigned maxTimeOutValue = 120000;
    4143
    4244// FIXME(188623, 188624, 188625): Support USB, NFC and BLE authenticators.
     
    5052    }
    5153
    52     if (authenticatorSelection.value().authenticatorAttachment == PublicKeyCredentialCreationOptions::AuthenticatorAttachment::Platform) {
     54    if (authenticatorSelection->authenticatorAttachment == PublicKeyCredentialCreationOptions::AuthenticatorAttachment::Platform) {
    5355        auto addResult = result.add(AuthenticatorTransport::Internal);
    5456        ASSERT_UNUSED(addResult, addResult.isNewEntry);
    5557        return result;
    5658    }
    57     if (authenticatorSelection.value().authenticatorAttachment == PublicKeyCredentialCreationOptions::AuthenticatorAttachment::CrossPlatform)
     59    if (authenticatorSelection->authenticatorAttachment == PublicKeyCredentialCreationOptions::AuthenticatorAttachment::CrossPlatform)
    5860        return result;
    5961
     
    105107    m_pendingRequestData = { hash, true, options, { } };
    106108    m_pendingCompletionHandler = WTFMove(callback);
     109    initTimeOutTimer(options.timeout);
    107110
    108111    // 2. Get available transports and start discovering authenticators on them.
     
    122125    m_pendingRequestData = { hash, false, { }, options };
    123126    m_pendingCompletionHandler = WTFMove(callback);
     127    initTimeOutTimer(options.timeout);
    124128
    125129    // 2. Get available transports and start discovering authenticators on them.
     
    148152{
    149153    ASSERT(RunLoop::isMain());
     154    ASSERT(m_requestTimeOutTimer);
     155    if (!m_requestTimeOutTimer->isActive())
     156        return;
     157
    150158    ASSERT(m_pendingCompletionHandler);
    151     // FIXME(189642)
    152159    if (WTF::holds_alternative<PublicKeyCredentialData>(respond)) {
    153160        m_pendingCompletionHandler(WTFMove(respond));
    154161        clearState();
     162        m_requestTimeOutTimer->stop();
    155163        return;
    156164    }
     
    179187}
    180188
     189void AuthenticatorManager::initTimeOutTimer(const std::optional<unsigned>& timeOutInMs)
     190{
     191    using namespace AuthenticatorManagerInternal;
     192
     193    unsigned timeOutInMsValue = std::min(maxTimeOutValue, timeOutInMs.value_or(maxTimeOutValue));
     194
     195    m_requestTimeOutTimer = std::make_unique<Timer>([context = this]() mutable {
     196        context->m_pendingCompletionHandler((ExceptionData { NotAllowedError, "Operation timed out."_s }));
     197        context->clearState();
     198    });
     199    m_requestTimeOutTimer->startOneShot(Seconds::fromMilliseconds(timeOutInMsValue));
     200}
     201
    181202} // namespace WebKit
    182203
  • trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h

    r236481 r236842  
    3333#include <WebCore/ExceptionData.h>
    3434#include <WebCore/PublicKeyCredentialData.h>
     35#include <WebCore/Timer.h>
    3536#include <wtf/CompletionHandler.h>
    3637#include <wtf/HashSet.h>
     
    5859protected:
    5960    Callback& pendingCompletionHandler() { return m_pendingCompletionHandler; }
     61    WebCore::Timer* requestTimeOutTimer() { return m_requestTimeOutTimer.get(); }
    6062    void clearState();
    6163
     
    7375
    7476    void startDiscovery(const TransportSet&);
     77    void initTimeOutTimer(const std::optional<unsigned>& timeOutInMs);
    7578
    7679    // Request: We only allow one request per time.
    7780    WebAuthenticationRequestData m_pendingRequestData;
    7881    Callback m_pendingCompletionHandler;
     82    std::unique_ptr<WebCore::Timer> m_requestTimeOutTimer;
    7983
    8084    Vector<UniqueRef<AuthenticatorTransportService>> m_services;
  • trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockAuthenticatorManager.cpp

    r236481 r236842  
    4343void MockAuthenticatorManager::respondReceivedInternal(Respond&& respond)
    4444{
     45    if (m_testConfiguration.silentFailure)
     46        return;
     47
    4548    pendingCompletionHandler()(WTFMove(respond));
    4649    clearState();
     50    requestTimeOutTimer()->stop();
    4751}
    4852
  • trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockWebAuthenticationConfiguration.h

    r236686 r236842  
    3939    };
    4040
     41    bool silentFailure { false };
    4142    std::optional<Local> local;
    4243};
  • trunk/Tools/ChangeLog

    r236840 r236842  
     12018-10-04  Jiewen Tan  <jiewen_tan@apple.com>
     2
     3        [WebAuthN] Move time out control from WebProcess to UIProcess
     4        https://bugs.webkit.org/show_bug.cgi?id=189642
     5        <rdar://problem/44476765>
     6
     7        Reviewed by Chris Dumez.
     8
     9        * WebKitTestRunner/InjectedBundle/TestRunner.cpp:
     10        (WTR::TestRunner::setWebAuthenticationMockConfiguration):
     11
    1122018-10-04  YUHAN WU  <yuhan_wu@apple.com>
    213
  • trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp

    r236690 r236842  
    23562356    Vector<WKRetainPtr<WKTypeRef>> configurationValues;
    23572357
     2358    JSRetainPtr<JSStringRef> silentFailurePropertyName(Adopt, JSStringCreateWithUTF8CString("silentFailure"));
     2359    JSValueRef silentFailureValue = JSObjectGetProperty(context, configuration, silentFailurePropertyName.get(), 0);
     2360    if (!JSValueIsUndefined(context, silentFailureValue)) {
     2361        if (!JSValueIsBoolean(context, silentFailureValue))
     2362            return;
     2363        bool silentFailure = JSValueToBoolean(context, silentFailureValue);
     2364        configurationKeys.append({ AdoptWK, WKStringCreateWithUTF8CString("SilentFailure") });
     2365        configurationValues.append(adoptWK(WKBooleanCreate(silentFailure)).get());
     2366    }
     2367
    23582368    JSRetainPtr<JSStringRef> localPropertyName(Adopt, JSStringCreateWithUTF8CString("local"));
    23592369    JSValueRef localValue = JSObjectGetProperty(context, configuration, localPropertyName.get(), 0);
    2360     if (!JSValueIsNull(context, localValue)) {
     2370    if (!JSValueIsUndefined(context, localValue) && !JSValueIsNull(context, localValue)) {
    23612371        if (!JSValueIsObject(context, localValue))
    23622372            return;
Note: See TracChangeset for help on using the changeset viewer.