From 20cd2d2377777b570cc7d405bb713074c1975a57 Mon Sep 17 00:00:00 2001 From: nkomonen-amazon Date: Thu, 5 Dec 2024 17:33:24 -0500 Subject: [PATCH] fix(auth): malformed SSO cache didn't prompt reauth Problem: When we loaded sso cache from disk, we would only invalidate (leading to a reauth prompt) if the cache file was missing. But if the cache file was present, though its content was malformed, we would incorrectly treat it as recoverable by throwing instead of returning undefined. Solution: If we detect a SyntaxError treat it as non-recoverable, meaning it will trigger a reauth. Also added some code to validate the content of the SSO cache we loaded from disk to ensure it is what we expected. Signed-off-by: nkomonen-amazon --- packages/core/src/auth/sso/cache.ts | 9 ++++++++- packages/core/src/shared/utilities/cacheUtils.ts | 13 +++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/core/src/auth/sso/cache.ts b/packages/core/src/auth/sso/cache.ts index 1c2be980630..88131fdc8ca 100644 --- a/packages/core/src/auth/sso/cache.ts +++ b/packages/core/src/auth/sso/cache.ts @@ -10,11 +10,12 @@ import { getLogger } from '../../shared/logger/logger' import fs from '../../shared/fs/fs' import { createDiskCache, KeyedCache, mapCache } from '../../shared/utilities/cacheUtils' import { stripUndefined } from '../../shared/utilities/collectionUtils' -import { hasProps, selectFrom } from '../../shared/utilities/tsUtils' +import { getMissingProps, hasProps, selectFrom } from '../../shared/utilities/tsUtils' import { SsoToken, ClientRegistration } from './model' import { DevSettings } from '../../shared/settings' import { onceChanged } from '../../shared/utilities/functionUtils' import globals from '../../shared/extensionGlobals' +import { ToolkitError } from '../../shared' interface RegistrationKey { readonly startUrl: string @@ -92,6 +93,12 @@ export function getTokenCache(directory = getCacheDir()): KeyedCache stripUndefined(token) + // Validate data is not missing. + const missingProps = getMissingProps(token, 'accessToken', 'refreshToken') + if (missingProps.length > 0) { + throw new ToolkitError(`SSO cache data unexpectedly missing props: ${JSON.stringify(missingProps)}`) + } + return { token, registration, diff --git a/packages/core/src/shared/utilities/cacheUtils.ts b/packages/core/src/shared/utilities/cacheUtils.ts index df2478df2c5..a3ccb5e55f5 100644 --- a/packages/core/src/shared/utilities/cacheUtils.ts +++ b/packages/core/src/shared/utilities/cacheUtils.ts @@ -116,10 +116,23 @@ export function createDiskCache( log('loaded', key) return result } catch (error) { + // Non-recoverable errors mean there is no usable data. + // Recoverable errors mean we can possibly use the data for something like + // an SSO token refresh, or to just retry. + // Returning undefined implies non-recoverable. + + // -- Non-recoverable Errors -- if (isFileNotFoundError(error)) { log('read failed (file not found)', key) return } + if (error instanceof SyntaxError) { + // file content was malformed or empty + log(`read failed (invalid JSON)`, key) + return + } + + // -- Recoverable Errors -- log(`read failed ${error}`, key) throw createDiskCacheError(error, 'LOAD', target, key) }