Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/javascript/selenium-webdriver/test/virtualAuthenticator_test.js
2884 views
1
// Licensed to the Software Freedom Conservancy (SFC) under one
2
// or more contributor license agreements. See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership. The SFC licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License. You may obtain a copy of the License at
8
//
9
// http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied. See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
'use strict'
19
20
const assert = require('node:assert')
21
const virtualAuthenticatorCredential = require('selenium-webdriver/lib/virtual_authenticator').Credential
22
const virtualAuthenticatorOptions = require('selenium-webdriver/lib/virtual_authenticator').VirtualAuthenticatorOptions
23
const Protocol = require('selenium-webdriver/lib/virtual_authenticator').Protocol
24
const { ignore, suite } = require('../lib/test')
25
const { Browser } = require('selenium-webdriver/lib/capabilities')
26
const fileServer = require('../lib/test/fileserver')
27
const invalidArgumentError = require('selenium-webdriver/lib/error').InvalidArgumentError
28
29
const REGISTER_CREDENTIAL = 'registerCredential().then(arguments[arguments.length - 1]);'
30
const GET_CREDENTIAL = `getCredential([{
31
"type": "public-key",
32
"id": Int8Array.from(arguments[0]),
33
}]).then(arguments[arguments.length - 1]);`
34
35
async function createRkEnabledU2fAuthenticator(driver) {
36
let options
37
options = new virtualAuthenticatorOptions()
38
options.setProtocol(Protocol['U2F'])
39
options.setHasResidentKey(true)
40
await driver.addVirtualAuthenticator(options)
41
return driver
42
}
43
44
async function createRkDisabledU2fAuthenticator(driver) {
45
let options
46
options = new virtualAuthenticatorOptions()
47
options.setProtocol(Protocol['U2F'])
48
options.setHasResidentKey(false)
49
await driver.addVirtualAuthenticator(options)
50
return driver
51
}
52
53
async function createRkEnabledCTAP2Authenticator(driver) {
54
let options
55
options = new virtualAuthenticatorOptions()
56
options.setProtocol(Protocol['CTAP2'])
57
options.setHasResidentKey(true)
58
options.setHasUserVerification(true)
59
options.setIsUserVerified(true)
60
await driver.addVirtualAuthenticator(options)
61
return driver
62
}
63
64
async function createRkDisabledCTAP2Authenticator(driver) {
65
let options
66
options = new virtualAuthenticatorOptions()
67
options.setProtocol(Protocol['CTAP2'])
68
options.setHasResidentKey(false)
69
options.setHasUserVerification(true)
70
options.setIsUserVerified(true)
71
await driver.addVirtualAuthenticator(options)
72
return driver
73
}
74
75
async function getAssertionFor(driver, credentialId) {
76
return await driver.executeAsyncScript(GET_CREDENTIAL, credentialId)
77
}
78
79
function extractRawIdFrom(response) {
80
return response.credential.rawId
81
}
82
83
function extractIdFrom(response) {
84
return response.credential.id
85
}
86
87
/**
88
* Checks if the two arrays are equal or not. Conditions to check are:
89
* 1. If the length of both arrays is equal
90
* 2. If all elements of array1 are present in array2
91
* 3. If all elements of array2 are present in array1
92
* @param array1 First array to be checked for equality
93
* @param array2 Second array to be checked for equality
94
* @returns true if equal, otherwise false.
95
*/
96
function arraysEqual(array1, array2) {
97
return (
98
array1.length == array2.length &&
99
array1.every((item) => array2.includes(item)) &&
100
array2.every((item) => array1.includes(item))
101
)
102
}
103
104
/**
105
* * * * * * TESTS * * * * *
106
*/
107
108
suite(function (env) {
109
/**
110
* A pkcs#8 encoded encrypted RSA private key as a base64url string.
111
*/
112
const BASE64_ENCODED_PK = `MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDbBOu5Lhs4vpowbCnmCyLUpIE7JM9sm9QXzye2G+jr+Kr
113
MsinWohEce47BFPJlTaDzHSvOW2eeunBO89ZcvvVc8RLz4qyQ8rO98xS1jtgqi1NcBPETDrtzthODu/gd0sjB2Tk3TLuBGV
114
oPXt54a+Oo4JbBJ6h3s0+5eAfGplCbSNq6hN3Jh9YOTw5ZA6GCEy5l8zBaOgjXytd2v2OdSVoEDNiNQRkjJd2rmS2oi9AyQ
115
FR3B7BrPSiDlCcITZFOWgLF5C31Wp/PSHwQhlnh7/6YhnE2y9tzsUvzx0wJXrBADW13+oMxrneDK3WGbxTNYgIi1PvSqXlq
116
GjHtCK+R2QkXAgMBAAECggEAVc6bu7VAnP6v0gDOeX4razv4FX/adCao9ZsHZ+WPX8PQxtmWYqykH5CY4TSfsuizAgyPuQ0
117
+j4Vjssr9VODLqFoanspT6YXsvaKanncUYbasNgUJnfnLnw3an2XpU2XdmXTNYckCPRX9nsAAURWT3/n9ljc/XYY22ecYxM
118
8sDWnHu2uKZ1B7M3X60bQYL5T/lVXkKdD6xgSNLeP4AkRx0H4egaop68hoW8FIwmDPVWYVAvo8etzWCtibRXz5FcNld9MgD
119
/Ai7ycKy4Q1KhX5GBFI79MVVaHkSQfxPHpr7/XcmpQOEAr+BMPon4s4vnKqAGdGB3j/E3d/+4F2swykoQKBgQD8hCsp6FIQ
120
5umJlk9/j/nGsMl85LgLaNVYpWlPRKPc54YNumtvj5vx1BG+zMbT7qIE3nmUPTCHP7qb5ERZG4CdMCS6S64/qzZEqijLCqe
121
pwj6j4fV5SyPWEcpxf6ehNdmcfgzVB3Wolfwh1ydhx/96L1jHJcTKchdJJzlfTvq8wwKBgQDeCnKws1t5GapfE1rmC/h4ol
122
L2qZTth9oQmbrXYohVnoqNFslDa43ePZwL9Jmd9kYb0axOTNMmyrP0NTj41uCfgDS0cJnNTc63ojKjegxHIyYDKRZNVUR/d
123
xAYB/vPfBYZUS7M89pO6LLsHhzS3qpu3/hppo/Uc/AM/r8PSflNHQKBgDnWgBh6OQncChPUlOLv9FMZPR1ZOfqLCYrjYEqi
124
uzGm6iKM13zXFO4AGAxu1P/IAd5BovFcTpg79Z8tWqZaUUwvscnl+cRlj+mMXAmdqCeO8VASOmqM1ml667axeZDIR867ZG8
125
K5V029Wg+4qtX5uFypNAAi6GfHkxIKrD04yOHAoGACdh4wXESi0oiDdkz3KOHPwIjn6BhZC7z8mx+pnJODU3cYukxv3WTct
126
lUhAsyjJiQ/0bK1yX87ulqFVgO0Knmh+wNajrb9wiONAJTMICG7tiWJOm7fW5cfTJwWkBwYADmkfTRmHDvqzQSSvoC2S7aa
127
9QulbC3C/qgGFNrcWgcT9kCgYAZTa1P9bFCDU7hJc2mHwJwAW7/FQKEJg8SL33KINpLwcR8fqaYOdAHWWz636osVEqosRrH
128
zJOGpf9x2RSWzQJ+dq8+6fACgfFZOVpN644+sAHfNPAI/gnNKU5OfUv+eav8fBnzlf1A3y3GIkyMyzFN3DE7e0n/lyqxE4H
129
BYGpI8g==`
130
131
const browsers = (...args) => env.browsers(...args)
132
let driver
133
134
beforeEach(async function () {
135
driver = await env.builder().build()
136
await driver.get(fileServer.Pages.virtualAuthenticator.replace('127.0.0.1', 'localhost'))
137
assert.strictEqual(await driver.getTitle(), 'Virtual Authenticator Tests')
138
})
139
140
afterEach(async function () {
141
if (driver.virtualAuthenticatorId() != null) {
142
await driver.removeVirtualAuthenticator()
143
}
144
await driver.quit()
145
})
146
147
describe('VirtualAuthenticator Test Suit 2', function () {
148
ignore(browsers(Browser.SAFARI, Browser.FIREFOX)).it('should test create authenticator', async function () {
149
/**
150
* Register a credential on the Virtual Authenticator.
151
*/
152
driver = await createRkDisabledU2fAuthenticator(driver)
153
assert((await driver.virtualAuthenticatorId()) != null)
154
155
let response = await driver.executeAsyncScript(REGISTER_CREDENTIAL)
156
assert(response['status'] === 'OK')
157
158
/**
159
* Attempt to use the credential to get an assertion.
160
*/
161
response = await getAssertionFor(driver, extractRawIdFrom(response))
162
assert(response['status'] === 'OK')
163
})
164
165
ignore(browsers(Browser.SAFARI, Browser.FIREFOX)).it('should test remove authenticator', async function () {
166
let options = new virtualAuthenticatorOptions()
167
await driver.addVirtualAuthenticator(options)
168
assert((await driver.virtualAuthenticatorId()) != null)
169
170
await driver.removeVirtualAuthenticator()
171
assert((await driver.virtualAuthenticatorId()) == null)
172
})
173
174
ignore(browsers(Browser.SAFARI, Browser.FIREFOX)).it('should test add non-resident credential', async function () {
175
/**
176
* Add a non-resident credential using the testing API.
177
*/
178
driver = await createRkDisabledCTAP2Authenticator(driver)
179
let credential = virtualAuthenticatorCredential.createNonResidentCredential(
180
new Uint8Array([1, 2, 3, 4]),
181
'localhost',
182
Buffer.from(BASE64_ENCODED_PK, 'base64').toString('binary'),
183
0,
184
)
185
await driver.addCredential(credential)
186
187
/**
188
* Attempt to use the credential to generate an assertion.
189
*/
190
let response = await getAssertionFor(driver, [1, 2, 3, 4])
191
assert(response['status'] === 'OK')
192
})
193
194
ignore(browsers(Browser.SAFARI, Browser.FIREFOX)).it(
195
'should test add non-resident credential when authenticator uses U2F protocol',
196
async function () {
197
/**
198
* Add a non-resident credential using the testing API.
199
*/
200
driver = await createRkDisabledU2fAuthenticator(driver)
201
202
/**
203
* A pkcs#8 encoded unencrypted EC256 private key as a base64url string.
204
*/
205
const base64EncodedPK =
206
'MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8_zMDQDYAxlU-Q' +
207
'hk1Dwkf0v18GZca1DMF3SaJ9HPdmShRANCAASNYX5lyVCOZLzFZzrIKmeZ2jwU' +
208
'RmgsJYxGP__fWN_S-j5sN4tT15XEpN_7QZnt14YvI6uvAgO0uJEboFaZlOEB'
209
210
let credential = virtualAuthenticatorCredential.createNonResidentCredential(
211
new Uint8Array([1, 2, 3, 4]),
212
'localhost',
213
Buffer.from(base64EncodedPK, 'base64').toString('binary'),
214
0,
215
)
216
await driver.addCredential(credential)
217
218
/**
219
* Attempt to use the credential to generate an assertion.
220
*/
221
let response = await getAssertionFor(driver, [1, 2, 3, 4])
222
assert(response['status'] === 'OK')
223
},
224
)
225
226
ignore(browsers(Browser.SAFARI, Browser.FIREFOX)).it('should test add resident credential', async function () {
227
/**
228
* Add a resident credential using the testing API.
229
*/
230
driver = await createRkEnabledCTAP2Authenticator(driver)
231
232
let credential = virtualAuthenticatorCredential.createResidentCredential(
233
new Uint8Array([1, 2, 3, 4]),
234
'localhost',
235
new Uint8Array([1]),
236
Buffer.from(BASE64_ENCODED_PK, 'base64').toString('binary'),
237
0,
238
)
239
await driver.addCredential(credential)
240
241
/**
242
* Attempt to use the credential to generate an assertion. Notice we use an
243
* empty allowCredentials array.
244
*/
245
let response = await driver.executeAsyncScript('getCredential([]).then(arguments[arguments.length - 1]);')
246
assert(response['status'] === 'OK')
247
assert(response.attestation.userHandle.includes(1))
248
})
249
250
ignore(browsers(Browser.SAFARI, Browser.FIREFOX)).it(
251
'should test add resident credential not supported when authenticator uses U2F protocol',
252
async function () {
253
/**
254
* Add a resident credential using the testing API.
255
*/
256
driver = await createRkEnabledU2fAuthenticator(driver)
257
258
/**
259
* A pkcs#8 encoded unencrypted EC256 private key as a base64url string.
260
*/
261
const base64EncodedPK =
262
'MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8_zMDQDYAxlU-Q' +
263
'hk1Dwkf0v18GZca1DMF3SaJ9HPdmShRANCAASNYX5lyVCOZLzFZzrIKmeZ2jwU' +
264
'RmgsJYxGP__fWN_S-j5sN4tT15XEpN_7QZnt14YvI6uvAgO0uJEboFaZlOEB'
265
266
let credential = virtualAuthenticatorCredential.createResidentCredential(
267
new Uint8Array([1, 2, 3, 4]),
268
'localhost',
269
new Uint8Array([1]),
270
Buffer.from(base64EncodedPK, 'base64').toString('binary'),
271
0,
272
)
273
274
/**
275
* Throws InvalidArgumentError
276
*/
277
try {
278
await driver.addCredential(credential)
279
} catch (e) {
280
if (e instanceof invalidArgumentError) {
281
assert(true)
282
} else {
283
assert(false)
284
}
285
}
286
},
287
)
288
289
ignore(browsers(Browser.SAFARI, Browser.FIREFOX)).it('should test get credentials', async function () {
290
/**
291
* Create an authenticator and add two credentials.
292
*/
293
driver = await createRkEnabledCTAP2Authenticator(driver)
294
295
/**
296
* Register a resident credential.
297
*/
298
let response1 = await driver.executeAsyncScript(
299
'registerCredential({authenticatorSelection: {requireResidentKey: true}})' +
300
' .then(arguments[arguments.length - 1]);',
301
)
302
assert(response1['status'] === 'OK')
303
304
/**
305
* Register a non resident credential.
306
*/
307
let response2 = await driver.executeAsyncScript(REGISTER_CREDENTIAL)
308
assert(response2['status'] === 'OK')
309
310
let credential1Id = extractRawIdFrom(response1)
311
let credential2Id = extractRawIdFrom(response2)
312
313
assert.notDeepStrictEqual(credential1Id.sort(), credential2Id.sort())
314
315
/**
316
* Retrieve the two credentials.
317
*/
318
let credentials = await driver.getCredentials()
319
assert.equal(credentials.length, 2)
320
321
let credential1 = null
322
let credential2 = null
323
324
credentials.forEach(function (credential) {
325
if (arraysEqual(credential.id(), credential1Id)) {
326
credential1 = credential
327
} else if (arraysEqual(credential.id(), credential2Id)) {
328
credential2 = credential
329
} else {
330
assert.fail(new Error('Unrecognized credential id'))
331
}
332
})
333
334
assert.equal(credential1.isResidentCredential(), true)
335
assert.notEqual(credential1.privateKey(), null)
336
337
assert.equal(credential2.isResidentCredential(), false)
338
assert.notEqual(credential2.privateKey(), null)
339
})
340
341
ignore(browsers(Browser.SAFARI, Browser.FIREFOX)).it('should test remove credential by rawID', async function () {
342
driver = await createRkDisabledU2fAuthenticator(driver)
343
344
/**
345
* Register credential.
346
*/
347
let response = await driver.executeAsyncScript(REGISTER_CREDENTIAL)
348
assert(response['status'] === 'OK')
349
350
/**
351
* Remove a credential by its ID as an array of bytes.
352
*/
353
let rawId = extractRawIdFrom(response)
354
await driver.removeCredential(rawId)
355
356
/**
357
* Trying to get an assertion should fail.
358
*/
359
response = await getAssertionFor(driver, rawId)
360
assert(response['status'].startsWith('NotAllowedError'))
361
})
362
363
ignore(browsers(Browser.SAFARI, Browser.FIREFOX)).it(
364
'should test remove credential by base64url Id',
365
async function () {
366
driver = await createRkDisabledU2fAuthenticator(driver)
367
368
/**
369
* Register credential.
370
*/
371
let response = await driver.executeAsyncScript(REGISTER_CREDENTIAL)
372
assert(response['status'] === 'OK')
373
374
let rawId = extractRawIdFrom(response)
375
let credentialId = extractIdFrom(response)
376
377
/**
378
* Remove a credential by its base64url ID.
379
*/
380
await driver.removeCredential(credentialId)
381
382
/**
383
* Trying to get an assertion should fail.
384
*/
385
response = await getAssertionFor(driver, rawId)
386
assert(response['status'].startsWith('NotAllowedError'))
387
},
388
)
389
390
ignore(browsers(Browser.SAFARI, Browser.FIREFOX)).it('should test remove all credentials', async function () {
391
driver = await createRkDisabledU2fAuthenticator(driver)
392
393
/**
394
* Register two credentials.
395
*/
396
let response1 = await driver.executeAsyncScript(REGISTER_CREDENTIAL)
397
assert(response1['status'] === 'OK')
398
let rawId1 = extractRawIdFrom(response1)
399
400
let response2 = await driver.executeAsyncScript(REGISTER_CREDENTIAL)
401
assert(response2['status'] === 'OK')
402
let rawId2 = extractRawIdFrom(response2)
403
404
/**
405
* Remove all credentials.
406
*/
407
await driver.removeAllCredentials()
408
409
/**
410
* Trying to get an assertion allowing for any of both should fail.
411
*/
412
let response = await driver.executeAsyncScript(
413
'getCredential([{' +
414
' "type": "public-key",' +
415
' "id": Int8Array.from(arguments[0]),' +
416
'}, {' +
417
' "type": "public-key",' +
418
' "id": Int8Array.from(arguments[1]),' +
419
'}]).then(arguments[arguments.length - 1]);',
420
rawId1,
421
rawId2,
422
)
423
assert(response['status'].startsWith('NotAllowedError'))
424
})
425
426
ignore(browsers(Browser.SAFARI, Browser.FIREFOX)).it('should test set user verified', async function () {
427
driver = await createRkEnabledCTAP2Authenticator(driver)
428
429
/**
430
* Register a credential requiring UV.
431
*/
432
let response = await driver.executeAsyncScript(
433
"registerCredential({authenticatorSelection: {userVerification: 'required'}})" +
434
' .then(arguments[arguments.length - 1]);',
435
)
436
assert(response['status'] === 'OK')
437
let rawId = extractRawIdFrom(response)
438
439
/**
440
* Getting an assertion requiring user verification should succeed.
441
*/
442
response = await driver.executeAsyncScript(GET_CREDENTIAL, rawId)
443
assert(response['status'] === 'OK')
444
445
/**
446
* Disable user verification.
447
*/
448
await driver.setUserVerified(false)
449
450
/**
451
* Getting an assertion requiring user verification should fail.
452
*/
453
response = await driver.executeAsyncScript(GET_CREDENTIAL, rawId)
454
assert(response['status'].startsWith('NotAllowedError'))
455
})
456
})
457
})
458
459