Skip to content

Commit fe84ca7

Browse files
committed
[java] Add virtual authenticator test case for U2F protocol. Formatting changes.
1 parent 9546dba commit fe84ca7

File tree

1 file changed

+139
-50
lines changed

1 file changed

+139
-50
lines changed

‎java/test/org/openqa/selenium/virtualauthenticator/VirtualAuthenticatorTest.java

Lines changed: 139 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@
2424

2525
import java.security.spec.PKCS8EncodedKeySpec;
2626
import java.util.Base64;
27+
2728
import org.junit.After;
2829
import org.junit.Before;
2930
import org.junit.Test;
31+
import org.openqa.selenium.InvalidArgumentException;
3032
import org.openqa.selenium.JavascriptExecutor;
3133
import org.openqa.selenium.environment.webserver.Page;
3234
import org.openqa.selenium.testing.JUnit4TestBase;
@@ -39,18 +41,33 @@
3941
public class VirtualAuthenticatorTest extends JUnit4TestBase {
4042

4143
/**
42-
* A pkcs#8 encoded unencrypted EC256 private key as a base64url string.
44+
* A pkcs#8 encoded encrypted RSA private key as a base64url string.
4345
*/
4446
private final static String base64EncodedPK =
45-
"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8_zMDQDYAxlU-Q"
46-
+ "hk1Dwkf0v18GZca1DMF3SaJ9HPdmShRANCAASNYX5lyVCOZLzFZzrIKmeZ2jwU"
47-
+ "RmgsJYxGP__fWN_S-j5sN4tT15XEpN_7QZnt14YvI6uvAgO0uJEboFaZlOEB";
47+
"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDbBOu5Lhs4vpowbCnmCyLUpIE7JM9sm9QXzye2G+jr+Kr"
48+
+ "MsinWohEce47BFPJlTaDzHSvOW2eeunBO89ZcvvVc8RLz4qyQ8rO98xS1jtgqi1NcBPETDrtzthODu/gd0sjB2Tk3TLuB"
49+
+ "GVoPXt54a+Oo4JbBJ6h3s0+5eAfGplCbSNq6hN3Jh9YOTw5ZA6GCEy5l8zBaOgjXytd2v2OdSVoEDNiNQRkjJd2rmS2oi"
50+
+ "9AyQFR3B7BrPSiDlCcITZFOWgLF5C31Wp/PSHwQhlnh7/6YhnE2y9tzsUvzx0wJXrBADW13+oMxrneDK3WGbxTNYgIi1P"
51+
+ "vSqXlqGjHtCK+R2QkXAgMBAAECggEAVc6bu7VAnP6v0gDOeX4razv4FX/adCao9ZsHZ+WPX8PQxtmWYqykH5CY4TSfsui"
52+
+ "zAgyPuQ0+j4Vjssr9VODLqFoanspT6YXsvaKanncUYbasNgUJnfnLnw3an2XpU2XdmXTNYckCPRX9nsAAURWT3/n9ljc/"
53+
+ "XYY22ecYxM8sDWnHu2uKZ1B7M3X60bQYL5T/lVXkKdD6xgSNLeP4AkRx0H4egaop68hoW8FIwmDPVWYVAvo8etzWCtib"
54+
+ "RXz5FcNld9MgD/Ai7ycKy4Q1KhX5GBFI79MVVaHkSQfxPHpr7/XcmpQOEAr+BMPon4s4vnKqAGdGB3j/E3d/+4F2swyko"
55+
+ "QKBgQD8hCsp6FIQ5umJlk9/j/nGsMl85LgLaNVYpWlPRKPc54YNumtvj5vx1BG+zMbT7qIE3nmUPTCHP7qb5ERZG4CdMC"
56+
+ "S6S64/qzZEqijLCqepwj6j4fV5SyPWEcpxf6ehNdmcfgzVB3Wolfwh1ydhx/96L1jHJcTKchdJJzlfTvq8wwKBgQDeCnK"
57+
+ "ws1t5GapfE1rmC/h4olL2qZTth9oQmbrXYohVnoqNFslDa43ePZwL9Jmd9kYb0axOTNMmyrP0NTj41uCfgDS0cJnNTc63"
58+
+ "ojKjegxHIyYDKRZNVUR/dxAYB/vPfBYZUS7M89pO6LLsHhzS3qpu3/hppo/Uc/AM /r8PSflNHQKBgDnWgBh6OQncChPUl"
59+
+ "OLv9FMZPR1ZOfqLCYrjYEqiuzGm6iKM13zXFO4AGAxu1P/IAd5BovFcTpg79Z8tWqZaUUwvscnl+cRlj+mMXAmdqCeO8V"
60+
+ "ASOmqM1ml667axeZDIR867ZG8K5V029Wg+4qtX5uFypNAAi6GfHkxIKrD04yOHAoGACdh4wXESi0oiDdkz3KOHPwIjn6B"
61+
+ "hZC7z8mx+pnJODU3cYukxv3WTctlUhAsyjJiQ/0bK1yX87ulqFVgO0Knmh+wNajrb9wiONAJTMICG7tiWJOm7fW5cfTJw"
62+
+ "WkBwYADmkfTRmHDvqzQSSvoC2S7aa9QulbC3C/qgGFNrcWgcT9kCgYAZTa1P9bFCDU7hJc2mHwJwAW7/FQKEJg8SL33KI"
63+
+ "NpLwcR8fqaYOdAHWWz636osVEqosRrHzJOGpf9x2RSWzQJ+dq8+6fACgfFZOVpN644+sAHfNPAI/gnNKU5OfUv+eav8fB"
64+
+ "nzlf1A3y3GIkyMyzFN3DE7e0n/lyqxE4HBYGpI8g==";
4865

4966
private final static PKCS8EncodedKeySpec privateKey =
50-
new PKCS8EncodedKeySpec(Base64.getUrlDecoder().decode(base64EncodedPK));
67+
new PKCS8EncodedKeySpec(Base64.getMimeDecoder().decode(base64EncodedPK));
5168

5269
private final static String script =
53-
"async function registerCredential(options = {}) {"
70+
"async function registerCredential(options = {}) {"
5471
+ " options = Object.assign({"
5572
+ " authenticatorSelection: {"
5673
+ " requireResidentKey: false,"
@@ -114,22 +131,39 @@ public void setup() {
114131
assumeThat(driver).isInstanceOf(HasVirtualAuthenticator.class);
115132
jsAwareDriver = (JavascriptExecutor) driver;
116133
driver.get(appServer.create(new Page()
117-
.withTitle("Virtual Authenticator Test")
118-
.withScripts(script)));
134+
.withTitle("Virtual Authenticator Test")
135+
.withScripts(script)));
136+
}
137+
138+
private void createRKEnabledU2FAuthenticator() {
139+
VirtualAuthenticatorOptions options = new VirtualAuthenticatorOptions()
140+
.setProtocol(Protocol.U2F)
141+
.setHasResidentKey(true);
142+
authenticator = ((HasVirtualAuthenticator) driver).addVirtualAuthenticator(options);
143+
}
144+
145+
private void createRKDisabledU2FAuthenticator() {
146+
VirtualAuthenticatorOptions options = new VirtualAuthenticatorOptions()
147+
.setProtocol(Protocol.U2F)
148+
.setHasResidentKey(false);
149+
authenticator = ((HasVirtualAuthenticator) driver).addVirtualAuthenticator(options);
119150
}
120151

121-
private void createSimpleU2FAuthenticator() {
152+
private void createRKEnabledCTAP2Authenticator() {
122153
VirtualAuthenticatorOptions options = new VirtualAuthenticatorOptions()
123-
.setProtocol(Protocol.U2F);
154+
.setProtocol(Protocol.CTAP2)
155+
.setHasResidentKey(true)
156+
.setHasUserVerification(true)
157+
.setIsUserVerified(true);
124158
authenticator = ((HasVirtualAuthenticator) driver).addVirtualAuthenticator(options);
125159
}
126160

127-
private void createRKEnabledAuthenticator() {
161+
private void createRKDisabledCTAP2Authenticator() {
128162
VirtualAuthenticatorOptions options = new VirtualAuthenticatorOptions()
129-
.setProtocol(Protocol.CTAP2)
130-
.setHasResidentKey(true)
131-
.setHasUserVerification(true)
132-
.setIsUserVerified(true);
163+
.setProtocol(Protocol.CTAP2)
164+
.setHasResidentKey(false)
165+
.setHasUserVerification(true)
166+
.setIsUserVerified(true);
133167
authenticator = ((HasVirtualAuthenticator) driver).addVirtualAuthenticator(options);
134168
}
135169

@@ -139,8 +173,9 @@ private void createRKEnabledAuthenticator() {
139173
*/
140174
private byte[] convertListIntoArrayOfBytes(List<Long> list) {
141175
byte[] ret = new byte[list.size()];
142-
for (int i = 0; i < list.size(); ++i)
176+
for (int i = 0; i < list.size(); ++i) {
143177
ret[i] = list.get(i).byteValue();
178+
}
144179
return ret;
145180
}
146181

@@ -160,7 +195,7 @@ private String extractIdFrom(Object response) {
160195

161196
private Object getAssertionFor(Object credentialId) {
162197
return jsAwareDriver.executeAsyncScript(
163-
"getCredential([{"
198+
"getCredential([{"
164199
+ " \"type\": \"public-key\","
165200
+ " \"id\": Int8Array.from(arguments[0]),"
166201
+ "}]).then(arguments[arguments.length - 1]);", credentialId);
@@ -176,16 +211,16 @@ public void tearDown() {
176211
@Test
177212
public void testCreateAuthenticator() {
178213
// Register a credential on the Virtual Authenticator.
179-
createSimpleU2FAuthenticator();
214+
createRKDisabledU2FAuthenticator();
180215
Object response = jsAwareDriver.executeAsyncScript(
181-
"registerCredential().then(arguments[arguments.length - 1]);");
216+
"registerCredential().then(arguments[arguments.length - 1]);");
182217
assertThat(response).asInstanceOf(MAP).containsEntry("status", "OK");
183218

184219
// Attempt to use the credential to get an assertion.
185220
assertThat(response)
186-
.extracting("credential.rawId")
187-
.extracting(this::getAssertionFor).asInstanceOf(MAP)
188-
.containsEntry("status", "OK");
221+
.extracting("credential.rawId")
222+
.extracting(this::getAssertionFor).asInstanceOf(MAP)
223+
.containsEntry("status", "OK");
189224
}
190225

191226
@Test
@@ -200,10 +235,37 @@ public void testRemoveAuthenticator() {
200235
@Test
201236
public void testAddNonResidentCredential() {
202237
// Add a non-resident credential using the testing API.
203-
createSimpleU2FAuthenticator();
238+
createRKDisabledCTAP2Authenticator();
204239
byte[] credentialId = {1, 2, 3, 4};
205240
Credential credential = Credential.createNonResidentCredential(
206-
credentialId, "localhost", privateKey, /*signCount=*/0);
241+
credentialId, "localhost", privateKey, /*signCount=*/0);
242+
authenticator.addCredential(credential);
243+
244+
// Attempt to use the credential to generate an assertion.
245+
Object response = getAssertionFor(Arrays.asList(1, 2, 3, 4));
246+
assertThat(response).asInstanceOf(MAP).containsEntry("status", "OK");
247+
}
248+
249+
@Test
250+
public void testAddNonResidentCredentialWhenAuthenticatorUsesU2FProtocol() {
251+
// Add a non-resident credential using the testing API.
252+
253+
createRKDisabledU2FAuthenticator();
254+
255+
/**
256+
* A pkcs#8 encoded unencrypted EC256 private key as a base64url string.
257+
*/
258+
String base64EncodedPK =
259+
"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8_zMDQDYAxlU-Q"
260+
+ "hk1Dwkf0v18GZca1DMF3SaJ9HPdmShRANCAASNYX5lyVCOZLzFZzrIKmeZ2jwU"
261+
+ "RmgsJYxGP__fWN_S-j5sN4tT15XEpN_7QZnt14YvI6uvAgO0uJEboFaZlOEB";
262+
263+
PKCS8EncodedKeySpec privateKey =
264+
new PKCS8EncodedKeySpec(Base64.getUrlDecoder().decode(base64EncodedPK));
265+
266+
byte[] credentialId = {1, 2, 3, 4};
267+
Credential credential = Credential.createNonResidentCredential(
268+
credentialId, "localhost", privateKey, /*signCount=*/0);
207269
authenticator.addCredential(credential);
208270

209271
// Attempt to use the credential to generate an assertion.
@@ -214,36 +276,59 @@ public void testAddNonResidentCredential() {
214276
@Test
215277
public void testAddResidentCredential() {
216278
// Add a resident credential using the testing API.
217-
createRKEnabledAuthenticator();
279+
createRKEnabledCTAP2Authenticator();
218280
byte[] credentialId = {1, 2, 3, 4};
219281
byte[] userHandle = {1};
220282
Credential credential = Credential.createResidentCredential(
221-
credentialId, "localhost", privateKey, userHandle, /*signCount=*/0);
283+
credentialId, "localhost", privateKey, userHandle, /*signCount=*/0);
222284
authenticator.addCredential(credential);
223285

224286
// Attempt to use the credential to generate an assertion. Notice we use an
225287
// empty allowCredentials array.
226288
Object response = jsAwareDriver.executeAsyncScript(
227-
"getCredential([]).then(arguments[arguments.length - 1]);");
289+
"getCredential([]).then(arguments[arguments.length - 1]);");
228290

229291
assertThat(response).asInstanceOf(MAP).containsEntry("status", "OK");
230292
assertThat(response).extracting("attestation.userHandle").asList().containsExactly(1L);
231293
}
232294

295+
@Test(expected = InvalidArgumentException.class)
296+
public void testAddResidentCredentialNotSupportedWhenAuthenticatorUsesU2FProtocol() {
297+
// Add a resident credential using the testing API.
298+
createRKEnabledU2FAuthenticator();
299+
300+
/**
301+
* A pkcs#8 encoded unencrypted EC256 private key as a base64url string.
302+
*/
303+
String base64EncodedPK =
304+
"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8_zMDQDYAxlU-Q"
305+
+ "hk1Dwkf0v18GZca1DMF3SaJ9HPdmShRANCAASNYX5lyVCOZLzFZzrIKmeZ2jwU"
306+
+ "RmgsJYxGP__fWN_S-j5sN4tT15XEpN_7QZnt14YvI6uvAgO0uJEboFaZlOEB";
307+
308+
PKCS8EncodedKeySpec privateKey =
309+
new PKCS8EncodedKeySpec(Base64.getUrlDecoder().decode(base64EncodedPK));
310+
311+
byte[] credentialId = {1, 2, 3, 4};
312+
byte[] userHandle = {1};
313+
Credential credential = Credential.createResidentCredential(
314+
credentialId, "localhost", privateKey, userHandle, /*signCount=*/0);
315+
authenticator.addCredential(credential);
316+
}
317+
233318
@Test
234319
public void testGetCredentials() {
235320
// Create an authenticator and add two credentials.
236-
createRKEnabledAuthenticator();
321+
createRKEnabledCTAP2Authenticator();
237322

238323
// Register a resident credential.
239324
Object response1 = jsAwareDriver.executeAsyncScript(
240-
"registerCredential({authenticatorSelection: {requireResidentKey: true}})"
325+
"registerCredential({authenticatorSelection: {requireResidentKey: true}})"
241326
+ " .then(arguments[arguments.length - 1]);");
242327
assertThat(response1).asInstanceOf(MAP).containsEntry("status", "OK");
243328

244329
// Register a non resident credential.
245330
Object response2 = jsAwareDriver.executeAsyncScript(
246-
"registerCredential().then(arguments[arguments.length - 1]);");
331+
"registerCredential().then(arguments[arguments.length - 1]);");
247332
assertThat(response2).asInstanceOf(MAP).containsEntry("status", "OK");
248333

249334
byte[] credential1Id = convertListIntoArrayOfBytes(extractRawIdFrom(response1));
@@ -270,7 +355,7 @@ public void testGetCredentials() {
270355
assertThat(credential1.isResidentCredential()).isTrue();
271356
assertThat(credential1.getPrivateKey()).isNotNull();
272357
assertThat(credential1.getRpId()).isEqualTo("localhost");
273-
assertThat(credential1.getUserHandle()).isEqualTo(new byte[] {1});
358+
assertThat(credential1.getUserHandle()).isEqualTo(new byte[]{1});
274359
assertThat(credential1.getSignCount()).isEqualTo(1);
275360

276361
assertThat(credential2.isResidentCredential()).isFalse();
@@ -283,11 +368,11 @@ public void testGetCredentials() {
283368

284369
@Test
285370
public void testRemoveCredentialByRawId() {
286-
createSimpleU2FAuthenticator();
371+
createRKDisabledU2FAuthenticator();
287372

288373
// Register credential.
289374
Object response = jsAwareDriver.executeAsyncScript(
290-
"registerCredential().then(arguments[arguments.length - 1]);");
375+
"registerCredential().then(arguments[arguments.length - 1]);");
291376
assertThat(response).asInstanceOf(MAP).containsEntry("status", "OK");
292377

293378
// Remove a credential by its ID as an array of bytes.
@@ -297,16 +382,17 @@ public void testRemoveCredentialByRawId() {
297382

298383
// Trying to get an assertion should fail.
299384
response = getAssertionFor(rawId);
300-
assertThat(response).asInstanceOf(MAP).extracting("status").asString().startsWith("NotAllowedError");
385+
assertThat(response).asInstanceOf(MAP).extracting("status").asString()
386+
.startsWith("NotAllowedError");
301387
}
302388

303389
@Test
304390
public void testRemoveCredentialByBase64UrlId() {
305-
createSimpleU2FAuthenticator();
391+
createRKDisabledU2FAuthenticator();
306392

307393
// Register credential.
308394
Object response = jsAwareDriver.executeAsyncScript(
309-
"registerCredential().then(arguments[arguments.length - 1]);");
395+
"registerCredential().then(arguments[arguments.length - 1]);");
310396
assertThat(response).asInstanceOf(MAP).containsEntry("status", "OK");
311397
List<Long> rawId = extractRawIdFrom(response);
312398

@@ -316,21 +402,22 @@ public void testRemoveCredentialByBase64UrlId() {
316402

317403
// Trying to get an assertion should fail.
318404
response = getAssertionFor(rawId);
319-
assertThat(response).asInstanceOf(MAP).extracting("status").asString().startsWith("NotAllowedError");
405+
assertThat(response).asInstanceOf(MAP).extracting("status").asString()
406+
.startsWith("NotAllowedError");
320407
}
321408

322409
@Test
323410
public void testRemoveAllCredentials() {
324-
createSimpleU2FAuthenticator();
411+
createRKDisabledU2FAuthenticator();
325412

326413
// Register two credentials.
327414
Object response1 = jsAwareDriver.executeAsyncScript(
328-
"registerCredential().then(arguments[arguments.length - 1]);");
415+
"registerCredential().then(arguments[arguments.length - 1]);");
329416
assertThat(response1).asInstanceOf(MAP).containsEntry("status", "OK");
330417
List<Long> rawId1 = extractRawIdFrom(response1);
331418

332419
Object response2 = jsAwareDriver.executeAsyncScript(
333-
"registerCredential().then(arguments[arguments.length - 1]);");
420+
"registerCredential().then(arguments[arguments.length - 1]);");
334421
assertThat(response2).asInstanceOf(MAP).containsEntry("status", "OK");
335422
List<Long> rawId2 = extractRawIdFrom(response1);
336423

@@ -339,47 +426,49 @@ public void testRemoveAllCredentials() {
339426

340427
// Trying to get an assertion allowing for any of both should fail.
341428
Object response = jsAwareDriver.executeAsyncScript(
342-
"getCredential([{"
429+
"getCredential([{"
343430
+ " \"type\": \"public-key\","
344431
+ " \"id\": Int8Array.from(arguments[0]),"
345432
+ "}, {"
346433
+ " \"type\": \"public-key\","
347434
+ " \"id\": Int8Array.from(arguments[1]),"
348435
+ "}]).then(arguments[arguments.length - 1]);",
349-
rawId1, rawId2);
350-
assertThat(response).asInstanceOf(MAP).extracting("status").asString().startsWith("NotAllowedError");
436+
rawId1, rawId2);
437+
assertThat(response).asInstanceOf(MAP).extracting("status").asString()
438+
.startsWith("NotAllowedError");
351439
}
352440

353441
@Test
354442
public void testSetUserVerified() {
355-
createRKEnabledAuthenticator();
443+
createRKEnabledCTAP2Authenticator();
356444

357445
// Register a credential requiring UV.
358446
Object response = jsAwareDriver.executeAsyncScript(
359-
"registerCredential({authenticatorSelection: {userVerification: 'required'}})"
447+
"registerCredential({authenticatorSelection: {userVerification: 'required'}})"
360448
+ " .then(arguments[arguments.length - 1]);");
361449
assertThat(response).asInstanceOf(MAP).containsEntry("status", "OK");
362450
List<Long> rawId = extractRawIdFrom(response);
363451

364452
// Getting an assertion requiring user verification should succeed.
365453
response = jsAwareDriver.executeAsyncScript(
366-
"getCredential([{"
454+
"getCredential([{"
367455
+ " \"type\": \"public-key\","
368456
+ " \"id\": Int8Array.from(arguments[0]),"
369457
+ "}], {userVerification: 'required'}).then(arguments[arguments.length - 1]);",
370-
rawId);
458+
rawId);
371459
assertThat(response).asInstanceOf(MAP).containsEntry("status", "OK");
372460

373461
// Disable user verification.
374462
authenticator.setUserVerified(false);
375463

376464
// Getting an assertion requiring user verification should fail.
377465
response = jsAwareDriver.executeAsyncScript(
378-
"getCredential([{"
466+
"getCredential([{"
379467
+ " \"type\": \"public-key\","
380468
+ " \"id\": Int8Array.from(arguments[0]),"
381469
+ "}], {userVerification: 'required'}).then(arguments[arguments.length - 1]);",
382-
rawId);
383-
assertThat(response).asInstanceOf(MAP).extracting("status").asString().startsWith("NotAllowedError");
470+
rawId);
471+
assertThat(response).asInstanceOf(MAP).extracting("status").asString()
472+
.startsWith("NotAllowedError");
384473
}
385474
}

0 commit comments

Comments
 (0)