From 384d287ab02c1955641d7bfe757528dd5ae6e1c2 Mon Sep 17 00:00:00 2001 From: Nikolas Komonen <118216176+nkomonen-amazon@users.noreply.github.com> Date: Thu, 14 Nov 2024 12:24:35 -0500 Subject: [PATCH] telemetry(auth): report sessionDuration on reauth `aws_loginWithBrowser` (#6013) Depends on https://github.com/aws/aws-toolkit-common/pull/914 ## Problem On the condition of: - SSO session is BuilderID or Internal Amazon IdC - Subsequent login for same SSO session happened earlier than 90 days (the expected session expiration) We need to know on the client side to be able to report this information so that CloudWatch alarms can consume this. ## Solution By adding the existing sessionDuration field, which is `currentTime - whenThePreviousSessionWasCreated`, to `aws_loginWithBrowser` we will have all the information we need to alarm on. --- License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --------- Signed-off-by: nkomonen-amazon --- package-lock.json | 10 ++--- package.json | 3 +- .../src/auth/sso/ssoAccessTokenProvider.ts | 3 +- .../sso/ssoAccessTokenProvider.test.ts | 44 +++++++++++++++++++ 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 335f510f9ef..0518d72adc8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,13 +15,12 @@ "plugins/*" ], "dependencies": { - "@aws-toolkits/telemetry": "^1.0.242", "@types/node": "^22.7.5", "vscode-nls": "^5.2.0", "vscode-nls-dev": "^4.0.4" }, "devDependencies": { - "@aws-toolkits/telemetry": "^1.0.274", + "@aws-toolkits/telemetry": "^1.0.282", "@playwright/browser-chromium": "^1.43.1", "@types/he": "^1.2.3", "@types/vscode": "^1.68.0", @@ -5136,10 +5135,11 @@ } }, "node_modules/@aws-toolkits/telemetry": { - "version": "1.0.275", - "resolved": "https://registry.npmjs.org/@aws-toolkits/telemetry/-/telemetry-1.0.275.tgz", - "integrity": "sha512-wy8L1xerMwBq+p/fcMkmR5pmPbZ17hG1dPgmThAaKEj6qYJ42pxEWjsCa+VqftA4FtXj4yEtSdja+M0d6Qd4bQ==", + "version": "1.0.282", + "resolved": "https://registry.npmjs.org/@aws-toolkits/telemetry/-/telemetry-1.0.282.tgz", + "integrity": "sha512-MHktYmucYHvEm4Sscr93UmKr83D9pKJIvETo1bZiNtCsE0jxcNglxZwqZruy13Fks5uk523ZhaIALW22TF0Zpg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "ajv": "^6.12.6", "fs-extra": "^11.1.0", diff --git a/package.json b/package.json index dae76a7a8c2..70f9d0f4c35 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "generateNonCodeFiles": "npm run generateNonCodeFiles -w packages/ --if-present" }, "devDependencies": { - "@aws-toolkits/telemetry": "^1.0.274", + "@aws-toolkits/telemetry": "^1.0.282", "@playwright/browser-chromium": "^1.43.1", "@types/he": "^1.2.3", "@types/vscode": "^1.68.0", @@ -71,7 +71,6 @@ }, "dependencies": { "@types/node": "^22.7.5", - "@aws-toolkits/telemetry": "^1.0.242", "vscode-nls": "^5.2.0", "vscode-nls-dev": "^4.0.4" } diff --git a/packages/core/src/auth/sso/ssoAccessTokenProvider.ts b/packages/core/src/auth/sso/ssoAccessTokenProvider.ts index 135cc1b605f..bf9c620c2f3 100644 --- a/packages/core/src/auth/sso/ssoAccessTokenProvider.ts +++ b/packages/core/src/auth/sso/ssoAccessTokenProvider.ts @@ -256,6 +256,7 @@ export abstract class SsoAccessTokenProvider { awsRegion: this.profile.region, ssoRegistrationExpiresAt: args?.registrationExpiresAt, ssoRegistrationClientId: args?.registrationClientId, + sessionDuration: getSessionDuration(this.tokenCacheKey), }) // Reset source in case there is a case where browser login was called but we forgot to set the source. @@ -396,7 +397,7 @@ async function pollForTokenWithProgress( */ function getSessionDuration(id: string) { const creationDate = globals.globalState.getSsoSessionCreationDate(id) - return creationDate !== undefined ? Date.now() - creationDate : undefined + return creationDate !== undefined ? globals.clock.Date.now() - creationDate : undefined } /** diff --git a/packages/core/src/test/credentials/sso/ssoAccessTokenProvider.test.ts b/packages/core/src/test/credentials/sso/ssoAccessTokenProvider.test.ts index a307c11d667..1bde91b26d8 100644 --- a/packages/core/src/test/credentials/sso/ssoAccessTokenProvider.test.ts +++ b/packages/core/src/test/credentials/sso/ssoAccessTokenProvider.test.ts @@ -265,6 +265,50 @@ describe('SsoAccessTokenProvider', function () { assert.notDeepStrictEqual(await sut.getToken(), cachedToken) }) + it(`emits session duration between logins of the same startUrl`, async function () { + setupFlow() + stubOpen() + + await sut.createToken() + clock.tick(5000) + await sut.createToken() + clock.tick(10_000) + await sut.createToken() + + // Mimic when we sign out then in again with the same region+startUrl. The ID is the only thing different. + sut = SsoAccessTokenProvider.create( + { region, startUrl, identifier: 'bbb' }, + cache, + oidcClient, + reAuthState, + () => true + ) + await sut.createToken() + + assertTelemetry('aws_loginWithBrowser', [ + { + credentialStartUrl: startUrl, + awsRegion: region, + sessionDuration: undefined, // A new login. + }, + { + credentialStartUrl: startUrl, + awsRegion: region, + sessionDuration: 5000, // A reauth. 5000 - 0, is the diff between this and previous login + }, + { + credentialStartUrl: startUrl, + awsRegion: region, + sessionDuration: 10000, // A reauth. 15_000 - 5000 is the diff between this and previous login + }, + { + credentialStartUrl: startUrl, + awsRegion: region, + sessionDuration: undefined, // A new login, since we signed out of the last. + }, + ]) + }) + it('respects the device authorization expiration time', async function () { // XXX: Don't know how to fix this "unhandled rejection" caused by this test: // rejected promise not handled within 1 second: Error: Timed-out waiting for browser login flow to complete