summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--packages/server/src/services/metadataService.test.ts12
-rw-r--r--packages/server/src/services/metadataService.ts38
2 files changed, 45 insertions, 5 deletions
diff --git a/packages/server/src/services/metadataService.test.ts b/packages/server/src/services/metadataService.test.ts
index d1984f5..b4b056e 100644
--- a/packages/server/src/services/metadataService.test.ts
+++ b/packages/server/src/services/metadataService.test.ts
@@ -79,6 +79,18 @@ describe('Method: getStatement()', () => {
expect(err).not.toBeUndefined();
}
});
+
+ test('should return undefined after initialization on AAGUID with no statement and verificationMode is "permissive"', async () => {
+ await MetadataService.initialize({
+ mdsServers: [],
+ statements: [],
+ verificationMode: 'permissive',
+ });
+
+ const statement = await MetadataService.getStatement('not-a-real-aaguid');
+
+ expect(statement).toBeUndefined();
+ });
});
const localStatementAAGUID = '91dfead7-959e-4475-ad26-9b0d482be089';
diff --git a/packages/server/src/services/metadataService.ts b/packages/server/src/services/metadataService.ts
index 58bfba5..3eac8a1 100644
--- a/packages/server/src/services/metadataService.ts
+++ b/packages/server/src/services/metadataService.ts
@@ -36,6 +36,10 @@ enum SERVICE_STATE {
READY,
}
+// Allow MetadataService to accommodate unregistered AAGUIDs ("permissive"), or only allow
+// registered AAGUIDs ("strict"). Currently primarily impacts how `getStatement()` operates
+type VerificationMode = 'permissive' | 'strict';
+
/**
* A basic service for coordinating interactions with the FIDO Metadata Service. This includes BLOB
* download and parsing, and on-demand requesting and caching of individual metadata statements.
@@ -46,17 +50,33 @@ export class BaseMetadataService {
private mdsCache: { [url: string]: CachedMDS } = {};
private statementCache: { [aaguid: string]: CachedBLOBEntry } = {};
private state: SERVICE_STATE = SERVICE_STATE.DISABLED;
+ private verificationMode: VerificationMode = 'strict';
/**
* Prepare the service to handle remote MDS servers and/or cache local metadata statements.
+ *
+ * **Options:**
+ *
+ * @param opts.mdsServers An array of URLs to FIDO Alliance Metadata Service
+ * (version 3.0)-compatible servers. Defaults to the official FIDO MDS server
+ * @param opts.statements An array of local metadata statements
+ * @param opts.verificationMode How MetadataService will handle unregistered AAGUIDs. Defaults to
+ * `"strict"` which throws errors during registration response verification when an
+ * unregistered AAGUID is encountered. Set to `"permissive"` to allow registration by
+ * authenticators with unregistered AAGUIDs
*/
async initialize(
opts: {
mdsServers?: string[];
statements?: MetadataStatement[];
+ verificationMode?: VerificationMode;
} = {},
): Promise<void> {
- const { mdsServers = [defaultURLMDS], statements } = opts;
+ const {
+ mdsServers = [defaultURLMDS],
+ statements,
+ verificationMode,
+ } = opts;
this.setState(SERVICE_STATE.REFRESHING);
@@ -104,11 +124,15 @@ export class BaseMetadataService {
// log('info', `Downloaded ${cacheDiff} statements from ${numServers} metadata servers`);
}
+ if (verificationMode) {
+ this.verificationMode = verificationMode;
+ }
+
this.setState(SERVICE_STATE.READY);
}
/**
- * Get a metadata statement for a given aaguid. Defaults to returning a cached statement.
+ * Get a metadata statement for a given AAGUID.
*
* This method will coordinate updating the cache as per the `nextUpdate` property in the initial
* BLOB download.
@@ -133,9 +157,13 @@ export class BaseMetadataService {
const cachedStatement = this.statementCache[aaguid];
if (!cachedStatement) {
- // TODO: FIDO conformance requires this, but it seems excessive for WebAuthn. Investigate
- // later
- throw new Error(`No metadata statement found for aaguid "${aaguid}"`);
+ if (this.verificationMode === 'strict') {
+ // FIDO conformance requires RP's to only support registered AAGUID's
+ throw new Error(`No metadata statement found for aaguid "${aaguid}"`);
+ }
+
+ // Allow registration verification to continue without using metadata
+ return;
}
// If the statement points to an MDS API, check the MDS' nextUpdate to see if we need to refresh