browser_clientAuth_ui.js (6582B)
1 // -*- indent-tabs-mode: nil; js-indent-level: 2 -*- 2 // Any copyright is dedicated to the Public Domain. 3 // http://creativecommons.org/publicdomain/zero/1.0/ 4 "use strict"; 5 6 // Tests that the client authentication certificate chooser correctly displays 7 // provided information and correctly returns user input. 8 9 const TEST_HOSTNAME = "Test Hostname"; 10 const TEST_ORG = "Test Org"; 11 const TEST_ISSUER_ORG = "Test Issuer Org"; 12 const TEST_PORT = 123; 13 14 var certDB = Cc["@mozilla.org/security/x509certdb;1"].getService( 15 Ci.nsIX509CertDB 16 ); 17 18 ChromeUtils.defineESModuleGetters(this, { 19 PromptUtils: "resource://gre/modules/PromptUtils.sys.mjs", 20 }); 21 22 /** 23 * Test certificate (i.e. build/pgo/certs/mochitest.client). 24 * 25 * @type {nsIX509Cert} 26 */ 27 var cert; 28 29 /** 30 * Opens the client auth cert chooser dialog. 31 * 32 * @param {nsIX509Cert} cert The cert to pass to the dialog for display. 33 * @returns {Promise} 34 * A promise that resolves when the dialog has finished loading, with 35 * an array consisting of: 36 * 1. The window of the opened dialog. 37 * 2. The return value nsIWritablePropertyBag2 passed to the dialog. 38 */ 39 function openClientAuthDialog(cert) { 40 let certArray = [cert]; 41 let retVals = { cert: undefined, rememberDuration: undefined }; 42 let args = PromptUtils.objectToPropBag({ 43 hostname: TEST_HOSTNAME, 44 certArray, 45 retVals, 46 }); 47 let win = window.openDialog( 48 "chrome://pippki/content/clientauthask.xhtml", 49 "", 50 "", 51 args 52 ); 53 return TestUtils.topicObserved("cert-dialog-loaded").then(() => { 54 return { win, retVals }; 55 }); 56 } 57 58 /** 59 * Checks that the contents of the given cert chooser dialog match the details 60 * of build/pgo/certs/mochitest.client. 61 * 62 * @param {window} win The cert chooser window. 63 * @param {string} notBefore 64 * The formatted notBefore date of mochitest.client. 65 * @param {string} notAfter 66 * The formatted notAfter date of mochitest.client. 67 */ 68 async function checkDialogContents(win, notBefore, notAfter) { 69 await TestUtils.waitForCondition(() => { 70 return win.document 71 .getElementById("clientAuthSiteIdentification") 72 .textContent.includes(`${TEST_HOSTNAME}`); 73 }); 74 let nicknames = win.document.getElementById("nicknames"); 75 await TestUtils.waitForCondition(() => { 76 return nicknames.label == "Mochitest client [03]"; 77 }); 78 await TestUtils.waitForCondition(() => { 79 return nicknames.itemCount == 1; 80 }); 81 let subject = win.document.getElementById("clientAuthCertDetailsIssuedTo"); 82 await TestUtils.waitForCondition(() => { 83 return subject.textContent == "Issued to: CN=Mochitest client"; 84 }); 85 let serialNum = win.document.getElementById( 86 "clientAuthCertDetailsSerialNumber" 87 ); 88 await TestUtils.waitForCondition(() => { 89 return serialNum.textContent == "Serial number: 03"; 90 }); 91 let validity = win.document.getElementById( 92 "clientAuthCertDetailsValidityPeriod" 93 ); 94 await TestUtils.waitForCondition(() => { 95 return validity.textContent == `Valid from ${notBefore} to ${notAfter}`; 96 }); 97 let issuer = win.document.getElementById("clientAuthCertDetailsIssuedBy"); 98 await TestUtils.waitForCondition(() => { 99 return ( 100 issuer.textContent == 101 "Issued by: OU=Profile Guided Optimization,O=Mozilla Testing,CN=Temporary Certificate Authority" 102 ); 103 }); 104 let tokenName = win.document.getElementById("clientAuthCertDetailsStoredOn"); 105 await TestUtils.waitForCondition(() => { 106 return tokenName.textContent == "Stored on: Software Security Device"; 107 }); 108 } 109 110 function findCertByCommonName(commonName) { 111 for (let cert of certDB.getCerts()) { 112 if (cert.commonName == commonName) { 113 return cert; 114 } 115 } 116 return null; 117 } 118 119 add_setup(async function () { 120 cert = findCertByCommonName("Mochitest client"); 121 isnot(cert, null, "Should be able to find the test client cert"); 122 }); 123 124 // Test that the contents of the dialog correspond to the details of the 125 // provided cert. 126 add_task(async function testContents() { 127 const formatter = new Intl.DateTimeFormat(undefined, { 128 dateStyle: "medium", 129 timeStyle: "long", 130 }); 131 let { win } = await openClientAuthDialog(cert); 132 await checkDialogContents( 133 win, 134 formatter.format(new Date(cert.validity.notBefore / 1000)), 135 formatter.format(new Date(cert.validity.notAfter / 1000)) 136 ); 137 await BrowserTestUtils.closeWindow(win); 138 }); 139 140 // Test that the right values are returned when the dialog is accepted. 141 add_task(async function testAcceptDialogReturnValues() { 142 let { win, retVals } = await openClientAuthDialog(cert); 143 win.document.getElementById("rememberSetting").value = 1; 144 info("Accepting dialog"); 145 win.document.getElementById("certAuthAsk").acceptDialog(); 146 await BrowserTestUtils.windowClosed(win); 147 148 is(retVals.cert, cert, "cert should be returned as chosen cert"); 149 is( 150 retVals.rememberDuration, 151 1, 152 "Return value should signal 'Remember persistently' option was selected" 153 ); 154 }); 155 156 // Test that the right values are returned when the dialog is canceled. 157 add_task(async function testCancelDialogReturnValues() { 158 let { win, retVals } = await openClientAuthDialog(cert); 159 win.document.getElementById("rememberSetting").value = 0; 160 info("Canceling dialog"); 161 win.document.getElementById("certAuthAsk").cancelDialog(); 162 await BrowserTestUtils.windowClosed(win); 163 164 ok( 165 !retVals.cert, 166 "Return value should signal user did not choose a certificate" 167 ); 168 is( 169 retVals.rememberDuration, 170 0, 171 "Return value should signal 'Remember once' was selected" 172 ); 173 }); 174 175 async function testDefaultRememberSettingFromPreference( 176 preferenceValue, 177 expectedSetting 178 ) { 179 Services.prefs.setIntPref( 180 "security.client_auth_certificate_default_remember_setting", 181 preferenceValue 182 ); 183 let { win } = await openClientAuthDialog(cert); 184 is( 185 win.document.getElementById("rememberSetting").value, 186 expectedSetting, 187 "remember setting should default to value specified by preference" 188 ); 189 info("Canceling dialog"); 190 win.document.getElementById("certAuthAsk").cancelDialog(); 191 await BrowserTestUtils.windowClosed(win); 192 } 193 194 // Test that the preference to set the default remember duration works. 195 add_task(async function testDefaultRememberSettingFromAllPreferenceValues() { 196 await testDefaultRememberSettingFromPreference(0, "0"); 197 await testDefaultRememberSettingFromPreference(1, "1"); 198 await testDefaultRememberSettingFromPreference(2, "2"); 199 // Setting the preference to an invalid value will result in the default of "2". 200 await testDefaultRememberSettingFromPreference(3, "2"); 201 });