summaryrefslogtreecommitdiffhomepage
path: root/packages/server/src
diff options
context:
space:
mode:
authorMatthew Miller <matthew@millerti.me>2022-08-18 18:39:33 -0700
committerGitHub <noreply@github.com>2022-08-18 18:39:33 -0700
commit9e68a48067878b6523bba9d75391a637fcf1d395 (patch)
treec497937dd69f91f5d67a0a7f66a14c7402a11791 /packages/server/src
parent24d1442dd57db66038ce42575d387f86511b7bfb (diff)
parentff0e52ceb8162192998b4550b388b988f143b6a0 (diff)
Merge pull request #259 from MasterKale/fix/improve-resident-key-registration-options
Fix/improve resident key registration options
Diffstat (limited to 'packages/server/src')
-rw-r--r--packages/server/src/registration/generateRegistrationOptions.test.ts87
-rw-r--r--packages/server/src/registration/generateRegistrationOptions.ts34
2 files changed, 114 insertions, 7 deletions
diff --git a/packages/server/src/registration/generateRegistrationOptions.test.ts b/packages/server/src/registration/generateRegistrationOptions.test.ts
index db4e11e..7b64434 100644
--- a/packages/server/src/registration/generateRegistrationOptions.test.ts
+++ b/packages/server/src/registration/generateRegistrationOptions.test.ts
@@ -166,3 +166,90 @@ test('should use custom supported algorithm IDs as-is when provided', () => {
{ alg: -65535, type: 'public-key' },
]);
});
+
+test('should require resident key if residentKey option is absent but requireResidentKey is set to true', () => {
+ const options = generateRegistrationOptions({
+ rpID: 'not.real',
+ rpName: 'SimpleWebAuthn',
+ userID: '1234',
+ userName: 'usernameHere',
+ authenticatorSelection: {
+ requireResidentKey: true,
+ }
+ });
+
+ expect(options.authenticatorSelection?.requireResidentKey).toEqual(true);
+ expect(options.authenticatorSelection?.residentKey).toEqual('required');
+});
+
+test('should discourage resident key if residentKey option is absent but requireResidentKey is set to false', () => {
+ const options = generateRegistrationOptions({
+ rpID: 'not.real',
+ rpName: 'SimpleWebAuthn',
+ userID: '1234',
+ userName: 'usernameHere',
+ authenticatorSelection: {
+ requireResidentKey: false,
+ }
+ });
+
+ expect(options.authenticatorSelection?.requireResidentKey).toEqual(false);
+ expect(options.authenticatorSelection?.residentKey).toBeUndefined();
+});
+
+test('should not set resident key if both residentKey and requireResidentKey options are absent', () => {
+ const options = generateRegistrationOptions({
+ rpID: 'not.real',
+ rpName: 'SimpleWebAuthn',
+ userID: '1234',
+ userName: 'usernameHere',
+ });
+
+ expect(options.authenticatorSelection?.requireResidentKey).toEqual(false);
+ expect(options.authenticatorSelection?.residentKey).toBeUndefined();
+});
+
+test('should set requireResidentKey to true if residentKey if set to required', () => {
+ const options = generateRegistrationOptions({
+ rpID: 'not.real',
+ rpName: 'SimpleWebAuthn',
+ userID: '1234',
+ userName: 'usernameHere',
+ authenticatorSelection: {
+ residentKey: 'required',
+ },
+ });
+
+ expect(options.authenticatorSelection?.requireResidentKey).toEqual(true);
+ expect(options.authenticatorSelection?.residentKey).toEqual('required');
+});
+
+test('should set requireResidentKey to false if residentKey if set to preferred', () => {
+ const options = generateRegistrationOptions({
+ rpID: 'not.real',
+ rpName: 'SimpleWebAuthn',
+ userID: '1234',
+ userName: 'usernameHere',
+ authenticatorSelection: {
+ residentKey: 'preferred',
+ },
+ });
+
+ expect(options.authenticatorSelection?.requireResidentKey).toEqual(false);
+ expect(options.authenticatorSelection?.residentKey).toEqual('preferred');
+});
+
+test('should set requireResidentKey to false if residentKey if set to discouraged', () => {
+ const options = generateRegistrationOptions({
+ rpID: 'not.real',
+ rpName: 'SimpleWebAuthn',
+ userID: '1234',
+ userName: 'usernameHere',
+ authenticatorSelection: {
+ residentKey: 'discouraged',
+ },
+ });
+
+ expect(options.authenticatorSelection?.requireResidentKey).toEqual(false);
+ expect(options.authenticatorSelection?.residentKey).toEqual('discouraged');
+});
diff --git a/packages/server/src/registration/generateRegistrationOptions.ts b/packages/server/src/registration/generateRegistrationOptions.ts
index d8d0ab5..0f281f2 100644
--- a/packages/server/src/registration/generateRegistrationOptions.ts
+++ b/packages/server/src/registration/generateRegistrationOptions.ts
@@ -120,15 +120,35 @@ export function generateRegistrationOptions(
}));
/**
- * "Relying Parties SHOULD set [requireResidentKey] to true if, and only if, residentKey is set
- * to "required""
- *
- * See https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-requireresidentkey
+ * Capture some of the nuances of how `residentKey` and `requireResidentKey` how either is set
+ * depending on when either is defined in the options
*/
- if (authenticatorSelection.residentKey === 'required') {
- authenticatorSelection.requireResidentKey = true;
+ if (authenticatorSelection.residentKey === undefined) {
+ /**
+ * `residentKey`: "If no value is given then the effective value is `required` if
+ * requireResidentKey is true or `discouraged` if it is false or absent."
+ *
+ * See https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-residentkey
+ */
+ if (authenticatorSelection.requireResidentKey) {
+ authenticatorSelection.residentKey = 'required';
+ } else {
+ /**
+ * FIDO Conformance v1.7.2 fails the first test if we do this, even though this is
+ * technically compatible with the WebAuthn L2 spec...
+ */
+ // authenticatorSelection.residentKey = 'discouraged';
+ }
} else {
- authenticatorSelection.requireResidentKey = false;
+ /**
+ * `requireResidentKey`: "Relying Parties SHOULD set it to true if, and only if, residentKey is
+ * set to "required""
+ *
+ * Spec says this property defaults to `false` so we should still be okay to assign `false` too
+ *
+ * See https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-requireresidentkey
+ */
+ authenticatorSelection.requireResidentKey = authenticatorSelection.residentKey === 'required';
}
return {