From ebbe74f76d466d3c0d5e7de1ec620daf5cd41114 Mon Sep 17 00:00:00 2001 From: Thomas Norling Date: Thu, 9 Jul 2020 16:48:11 -0700 Subject: [PATCH 01/14] Implement Telemetry in Node --- lib/msal-node/src/client/ClientApplication.ts | 83 ++++++++++++------- .../src/client/PublicClientApplication.ts | 22 +++-- lib/msal-node/src/utils/Constants.ts | 8 ++ 3 files changed, 76 insertions(+), 37 deletions(-) diff --git a/lib/msal-node/src/client/ClientApplication.ts b/lib/msal-node/src/client/ClientApplication.ts index b8ef2e485a..098511207e 100644 --- a/lib/msal-node/src/client/ClientApplication.ts +++ b/lib/msal-node/src/client/ClientApplication.ts @@ -19,20 +19,21 @@ import { BaseAuthRequest, SilentFlowRequest, SilentFlowClient, - Logger + Logger, + TelemetryManager } from '@azure/msal-common'; import { Configuration, buildAppConfiguration } from '../config/Configuration'; import { CryptoProvider } from '../crypto/CryptoProvider'; import { Storage } from '../cache/Storage'; import { version } from '../../package.json'; -import { Constants as NodeConstants } from './../utils/Constants'; +import { Constants as NodeConstants, ApiId } from './../utils/Constants'; import { TokenCache } from '../cache/TokenCache'; export abstract class ClientApplication { private config: Configuration; private _authority: Authority; private readonly cryptoProvider: CryptoProvider; - private storage: Storage; + protected storage: Storage; private tokenCache: TokenCache; protected logger: Logger; @@ -70,7 +71,7 @@ export abstract class ClientApplication { const authorizationCodeClient = new AuthorizationCodeClient( authClientConfig ); - return authorizationCodeClient.getAuthCodeUrl(this.initializeRequestScopes(request) as AuthorizationUrlRequest); + return authorizationCodeClient.getAuthCodeUrl(this.initializeRequest(request) as AuthorizationUrlRequest); } /** @@ -83,14 +84,21 @@ export abstract class ClientApplication { */ async acquireTokenByCode(request: AuthorizationCodeRequest): Promise { this.logger.info("acquireTokenByCode called"); - const authClientConfig = await this.buildOauthClientConfiguration( - request.authority - ); - this.logger.verbose("Auth client config generated"); - const authorizationCodeClient = new AuthorizationCodeClient( - authClientConfig - ); - return authorizationCodeClient.acquireToken(this.initializeRequestScopes(request) as AuthorizationCodeRequest); + const validRequest = this.initializeRequest(request) as AuthorizationCodeRequest; + const telemetryManager = new TelemetryManager(this.storage, ApiId.acquireTokenByCode, validRequest.correlationId!); + try { + const authClientConfig = await this.buildOauthClientConfiguration( + request.authority + ); + this.logger.verbose("Auth client config generated"); + const authorizationCodeClient = new AuthorizationCodeClient( + authClientConfig + ); + return authorizationCodeClient.acquireToken(validRequest, telemetryManager); + } catch (e) { + telemetryManager.cacheFailedRequest(e); + throw e; + } } /** @@ -102,14 +110,21 @@ export abstract class ClientApplication { */ async acquireTokenByRefreshToken(request: RefreshTokenRequest): Promise { this.logger.info("acquireTokenByRefreshToken called"); - const refreshTokenClientConfig = await this.buildOauthClientConfiguration( - request.authority - ); - this.logger.verbose("Auth client config generated"); - const refreshTokenClient = new RefreshTokenClient( - refreshTokenClientConfig - ); - return refreshTokenClient.acquireToken(this.initializeRequestScopes(request) as RefreshTokenRequest); + const validRequest = this.initializeRequest(request) as RefreshTokenRequest; + const telemetryManager = new TelemetryManager(this.storage, ApiId.acquireTokenByRefreshToken, validRequest.correlationId!); + try { + const refreshTokenClientConfig = await this.buildOauthClientConfiguration( + request.authority + ); + this.logger.verbose("Auth client config generated"); + const refreshTokenClient = new RefreshTokenClient( + refreshTokenClientConfig + ); + return refreshTokenClient.acquireToken(validRequest, telemetryManager); + } catch (e) { + telemetryManager.cacheFailedRequest(e); + throw e; + } } /** @@ -121,13 +136,20 @@ export abstract class ClientApplication { * and the guidance is for the user to call any interactive token acquisition API (eg: `acquireTokenByCode()`). */ async acquireTokenSilent(request: SilentFlowRequest): Promise { - const silentFlowClientConfig = await this.buildOauthClientConfiguration( - request.authority - ); - const silentFlowClient = new SilentFlowClient( - silentFlowClientConfig - ); - return silentFlowClient.acquireToken(this.initializeRequestScopes(request) as SilentFlowRequest); + const validRequest = this.initializeRequest(request) as SilentFlowRequest; + const telemetryManager = new TelemetryManager(this.storage, ApiId.acquireTokenSilent, validRequest.correlationId!); + try { + const silentFlowClientConfig = await this.buildOauthClientConfiguration( + request.authority + ); + const silentFlowClient = new SilentFlowClient( + silentFlowClientConfig + ); + return silentFlowClient.acquireToken(validRequest, telemetryManager); + } catch (e) { + telemetryManager.cacheFailedRequest(e); + throw e; + } } /** @@ -167,15 +189,16 @@ export abstract class ClientApplication { } /** - * Generates a request with the default scopes. + * Generates a request with the default scopes & generates a correlationId. * @param authRequest */ - protected initializeRequestScopes(authRequest: BaseAuthRequest): BaseAuthRequest { + protected initializeRequest(authRequest: BaseAuthRequest): BaseAuthRequest { this.logger.verbose("initializeRequestScopes called"); return { ...authRequest, - scopes: [...((authRequest && authRequest.scopes) || []), Constants.OPENID_SCOPE, Constants.PROFILE_SCOPE, Constants.OFFLINE_ACCESS_SCOPE] + scopes: [...((authRequest && authRequest.scopes) || []), Constants.OPENID_SCOPE, Constants.PROFILE_SCOPE, Constants.OFFLINE_ACCESS_SCOPE], + correlationId: authRequest && authRequest.correlationId || this.cryptoProvider.createNewGuid() }; } diff --git a/lib/msal-node/src/client/PublicClientApplication.ts b/lib/msal-node/src/client/PublicClientApplication.ts index f55bbf4a20..b9bfce5d68 100644 --- a/lib/msal-node/src/client/PublicClientApplication.ts +++ b/lib/msal-node/src/client/PublicClientApplication.ts @@ -3,9 +3,10 @@ * Licensed under the MIT License. */ -import { DeviceCodeClient, DeviceCodeRequest } from '@azure/msal-common'; +import { DeviceCodeClient, DeviceCodeRequest, TelemetryManager } from '@azure/msal-common'; import { Configuration } from '../config/Configuration'; import { ClientApplication } from './ClientApplication'; +import { ApiId } from 'utils/Constants'; /** * This class is to be used to acquire tokens for public client applications (desktop, mobile). Public client applications @@ -44,11 +45,18 @@ export class PublicClientApplication extends ClientApplication { */ public async acquireTokenByDeviceCode(request: DeviceCodeRequest): Promise { this.logger.info("acquireTokenByDeviceCode called"); - const deviceCodeConfig = await this.buildOauthClientConfiguration( - request.authority - ); - this.logger.verbose("Auth client config generated"); - const deviceCodeClient = new DeviceCodeClient(deviceCodeConfig); - return deviceCodeClient.acquireToken(this.initializeRequestScopes(request) as DeviceCodeRequest); + const validRequest = this.initializeRequest(request) as DeviceCodeRequest; + const telemetryManager = new TelemetryManager(this.storage, ApiId.acquireTokenByDeviceCode, validRequest.correlationId); + try { + const deviceCodeConfig = await this.buildOauthClientConfiguration( + request.authority + ); + this.logger.verbose("Auth client config generated"); + const deviceCodeClient = new DeviceCodeClient(deviceCodeConfig); + return deviceCodeClient.acquireToken(validRequest, telemetryManager); + } catch (e) { + telemetryManager.createFailedRequest(e); + throw e; + } } } diff --git a/lib/msal-node/src/utils/Constants.ts b/lib/msal-node/src/utils/Constants.ts index 3f04c00b96..dd40d86e57 100644 --- a/lib/msal-node/src/utils/Constants.ts +++ b/lib/msal-node/src/utils/Constants.ts @@ -45,3 +45,11 @@ export const CACHE = { export const Constants = { MSAL_SKU: 'msal.js.node', }; + +// Telemetry Constants +export enum ApiId { + acquireTokenSilent = 62, + acquireTokenByCode = 871, + acquireTokenByRefreshToken = 872, + acquireTokenByDeviceCode = 671 +}; From eb280599fff994d782d40bff55adde44ad53ae5a Mon Sep 17 00:00:00 2001 From: Thomas Norling Date: Thu, 9 Jul 2020 16:50:32 -0700 Subject: [PATCH 02/14] Add forceRefresh to acquireTokenSilent Telemetry --- lib/msal-node/src/client/ClientApplication.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msal-node/src/client/ClientApplication.ts b/lib/msal-node/src/client/ClientApplication.ts index 098511207e..d24a6a00ed 100644 --- a/lib/msal-node/src/client/ClientApplication.ts +++ b/lib/msal-node/src/client/ClientApplication.ts @@ -137,7 +137,7 @@ export abstract class ClientApplication { */ async acquireTokenSilent(request: SilentFlowRequest): Promise { const validRequest = this.initializeRequest(request) as SilentFlowRequest; - const telemetryManager = new TelemetryManager(this.storage, ApiId.acquireTokenSilent, validRequest.correlationId!); + const telemetryManager = new TelemetryManager(this.storage, ApiId.acquireTokenSilent, validRequest.correlationId!, validRequest.forceRefresh); try { const silentFlowClientConfig = await this.buildOauthClientConfiguration( request.authority From 7dc2daf44e2128b04141a9559c71c700d1ba64c0 Mon Sep 17 00:00:00 2001 From: Thomas Norling Date: Mon, 13 Jul 2020 10:22:17 -0700 Subject: [PATCH 03/14] Add comment to API codes --- lib/msal-node/src/utils/Constants.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/msal-node/src/utils/Constants.ts b/lib/msal-node/src/utils/Constants.ts index dd40d86e57..d0b9d32256 100644 --- a/lib/msal-node/src/utils/Constants.ts +++ b/lib/msal-node/src/utils/Constants.ts @@ -46,7 +46,13 @@ export const Constants = { MSAL_SKU: 'msal.js.node', }; -// Telemetry Constants +/** + * API Codes for Telemetry purposes. + * Before adding a new code you must claim it in the MSAL Telemetry tracker as these number spaces are shared across all MSALs + * 0-99 Silent Flow + * 600-699 Device Code Flow + * 800-899 Auth Code Flow + */ export enum ApiId { acquireTokenSilent = 62, acquireTokenByCode = 871, From da6bede5f0ec8a915de7de8918ef35b1bd09d4be Mon Sep 17 00:00:00 2001 From: Thomas Norling Date: Mon, 13 Jul 2020 11:41:03 -0700 Subject: [PATCH 04/14] Null assert correaltionId --- lib/msal-node/src/client/PublicClientApplication.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msal-node/src/client/PublicClientApplication.ts b/lib/msal-node/src/client/PublicClientApplication.ts index b9bfce5d68..0a1e343fc4 100644 --- a/lib/msal-node/src/client/PublicClientApplication.ts +++ b/lib/msal-node/src/client/PublicClientApplication.ts @@ -46,7 +46,7 @@ export class PublicClientApplication extends ClientApplication { public async acquireTokenByDeviceCode(request: DeviceCodeRequest): Promise { this.logger.info("acquireTokenByDeviceCode called"); const validRequest = this.initializeRequest(request) as DeviceCodeRequest; - const telemetryManager = new TelemetryManager(this.storage, ApiId.acquireTokenByDeviceCode, validRequest.correlationId); + const telemetryManager = new TelemetryManager(this.storage, ApiId.acquireTokenByDeviceCode, validRequest.correlationId!); try { const deviceCodeConfig = await this.buildOauthClientConfiguration( request.authority From d2b18074110e6634e994be1bee4952cfd17cb9eb Mon Sep 17 00:00:00 2001 From: Thomas Norling Date: Tue, 14 Jul 2020 16:17:59 -0700 Subject: [PATCH 05/14] Fix function name --- lib/msal-node/src/client/PublicClientApplication.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msal-node/src/client/PublicClientApplication.ts b/lib/msal-node/src/client/PublicClientApplication.ts index 0a1e343fc4..a29b4dd552 100644 --- a/lib/msal-node/src/client/PublicClientApplication.ts +++ b/lib/msal-node/src/client/PublicClientApplication.ts @@ -55,7 +55,7 @@ export class PublicClientApplication extends ClientApplication { const deviceCodeClient = new DeviceCodeClient(deviceCodeConfig); return deviceCodeClient.acquireToken(validRequest, telemetryManager); } catch (e) { - telemetryManager.createFailedRequest(e); + telemetryManager.cacheFailedRequest(e); throw e; } } From 75cb78ef3d2551fe684c50a2cacbfe18d868e13f Mon Sep 17 00:00:00 2001 From: Thomas Norling Date: Tue, 14 Jul 2020 17:55:29 -0700 Subject: [PATCH 06/14] Fix import --- lib/msal-node/src/client/PublicClientApplication.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msal-node/src/client/PublicClientApplication.ts b/lib/msal-node/src/client/PublicClientApplication.ts index a29b4dd552..2ce4136ccd 100644 --- a/lib/msal-node/src/client/PublicClientApplication.ts +++ b/lib/msal-node/src/client/PublicClientApplication.ts @@ -6,7 +6,7 @@ import { DeviceCodeClient, DeviceCodeRequest, TelemetryManager } from '@azure/msal-common'; import { Configuration } from '../config/Configuration'; import { ClientApplication } from './ClientApplication'; -import { ApiId } from 'utils/Constants'; +import { ApiId } from '../utils/Constants'; /** * This class is to be used to acquire tokens for public client applications (desktop, mobile). Public client applications From 561bdfe9aa32f50436886fc95450c4f77c138311 Mon Sep 17 00:00:00 2001 From: Thomas Norling Date: Thu, 16 Jul 2020 17:07:45 -0700 Subject: [PATCH 07/14] Update to ServerTelemetryManager --- lib/msal-node/src/client/ClientApplication.ts | 8 ++++---- lib/msal-node/src/client/PublicClientApplication.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/msal-node/src/client/ClientApplication.ts b/lib/msal-node/src/client/ClientApplication.ts index d24a6a00ed..c055f3f47b 100644 --- a/lib/msal-node/src/client/ClientApplication.ts +++ b/lib/msal-node/src/client/ClientApplication.ts @@ -20,7 +20,7 @@ import { SilentFlowRequest, SilentFlowClient, Logger, - TelemetryManager + ServerTelemetryManager } from '@azure/msal-common'; import { Configuration, buildAppConfiguration } from '../config/Configuration'; import { CryptoProvider } from '../crypto/CryptoProvider'; @@ -85,7 +85,7 @@ export abstract class ClientApplication { async acquireTokenByCode(request: AuthorizationCodeRequest): Promise { this.logger.info("acquireTokenByCode called"); const validRequest = this.initializeRequest(request) as AuthorizationCodeRequest; - const telemetryManager = new TelemetryManager(this.storage, ApiId.acquireTokenByCode, validRequest.correlationId!); + const telemetryManager = new ServerTelemetryManager(this.storage, ApiId.acquireTokenByCode, validRequest.correlationId!); try { const authClientConfig = await this.buildOauthClientConfiguration( request.authority @@ -111,7 +111,7 @@ export abstract class ClientApplication { async acquireTokenByRefreshToken(request: RefreshTokenRequest): Promise { this.logger.info("acquireTokenByRefreshToken called"); const validRequest = this.initializeRequest(request) as RefreshTokenRequest; - const telemetryManager = new TelemetryManager(this.storage, ApiId.acquireTokenByRefreshToken, validRequest.correlationId!); + const telemetryManager = new ServerTelemetryManager(this.storage, ApiId.acquireTokenByRefreshToken, validRequest.correlationId!); try { const refreshTokenClientConfig = await this.buildOauthClientConfiguration( request.authority @@ -137,7 +137,7 @@ export abstract class ClientApplication { */ async acquireTokenSilent(request: SilentFlowRequest): Promise { const validRequest = this.initializeRequest(request) as SilentFlowRequest; - const telemetryManager = new TelemetryManager(this.storage, ApiId.acquireTokenSilent, validRequest.correlationId!, validRequest.forceRefresh); + const telemetryManager = new ServerTelemetryManager(this.storage, ApiId.acquireTokenSilent, validRequest.correlationId!, validRequest.forceRefresh); try { const silentFlowClientConfig = await this.buildOauthClientConfiguration( request.authority diff --git a/lib/msal-node/src/client/PublicClientApplication.ts b/lib/msal-node/src/client/PublicClientApplication.ts index 2ce4136ccd..14a2c7e91c 100644 --- a/lib/msal-node/src/client/PublicClientApplication.ts +++ b/lib/msal-node/src/client/PublicClientApplication.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. */ -import { DeviceCodeClient, DeviceCodeRequest, TelemetryManager } from '@azure/msal-common'; +import { DeviceCodeClient, DeviceCodeRequest, ServerTelemetryManager } from '@azure/msal-common'; import { Configuration } from '../config/Configuration'; import { ClientApplication } from './ClientApplication'; import { ApiId } from '../utils/Constants'; @@ -46,7 +46,7 @@ export class PublicClientApplication extends ClientApplication { public async acquireTokenByDeviceCode(request: DeviceCodeRequest): Promise { this.logger.info("acquireTokenByDeviceCode called"); const validRequest = this.initializeRequest(request) as DeviceCodeRequest; - const telemetryManager = new TelemetryManager(this.storage, ApiId.acquireTokenByDeviceCode, validRequest.correlationId!); + const telemetryManager = new ServerTelemetryManager(this.storage, ApiId.acquireTokenByDeviceCode, validRequest.correlationId!); try { const deviceCodeConfig = await this.buildOauthClientConfiguration( request.authority From 8888eb283debc8d8737af9061e5e4025e0bbd7f1 Mon Sep 17 00:00:00 2001 From: Thomas Norling Date: Wed, 22 Jul 2020 17:37:55 -0700 Subject: [PATCH 08/14] Add telemetryManager to authCodeClient --- lib/msal-node/src/client/ClientApplication.ts | 44 +++++++++++++------ .../src/client/PublicClientApplication.ts | 11 ++--- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/lib/msal-node/src/client/ClientApplication.ts b/lib/msal-node/src/client/ClientApplication.ts index c055f3f47b..36643a459f 100644 --- a/lib/msal-node/src/client/ClientApplication.ts +++ b/lib/msal-node/src/client/ClientApplication.ts @@ -20,7 +20,8 @@ import { SilentFlowRequest, SilentFlowClient, Logger, - ServerTelemetryManager + ServerTelemetryManager, + ServerTelemetryRequest } from '@azure/msal-common'; import { Configuration, buildAppConfiguration } from '../config/Configuration'; import { CryptoProvider } from '../crypto/CryptoProvider'; @@ -85,18 +86,19 @@ export abstract class ClientApplication { async acquireTokenByCode(request: AuthorizationCodeRequest): Promise { this.logger.info("acquireTokenByCode called"); const validRequest = this.initializeRequest(request) as AuthorizationCodeRequest; - const telemetryManager = new ServerTelemetryManager(this.storage, ApiId.acquireTokenByCode, validRequest.correlationId!); + const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenByCode, validRequest.correlationId!); try { const authClientConfig = await this.buildOauthClientConfiguration( - request.authority + request.authority, + serverTelemetryManager ); this.logger.verbose("Auth client config generated"); const authorizationCodeClient = new AuthorizationCodeClient( authClientConfig ); - return authorizationCodeClient.acquireToken(validRequest, telemetryManager); + return authorizationCodeClient.acquireToken(validRequest); } catch (e) { - telemetryManager.cacheFailedRequest(e); + serverTelemetryManager.cacheFailedRequest(e); throw e; } } @@ -111,18 +113,19 @@ export abstract class ClientApplication { async acquireTokenByRefreshToken(request: RefreshTokenRequest): Promise { this.logger.info("acquireTokenByRefreshToken called"); const validRequest = this.initializeRequest(request) as RefreshTokenRequest; - const telemetryManager = new ServerTelemetryManager(this.storage, ApiId.acquireTokenByRefreshToken, validRequest.correlationId!); + const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenByRefreshToken, validRequest.correlationId!); try { const refreshTokenClientConfig = await this.buildOauthClientConfiguration( - request.authority + request.authority, + serverTelemetryManager ); this.logger.verbose("Auth client config generated"); const refreshTokenClient = new RefreshTokenClient( refreshTokenClientConfig ); - return refreshTokenClient.acquireToken(validRequest, telemetryManager); + return refreshTokenClient.acquireToken(validRequest); } catch (e) { - telemetryManager.cacheFailedRequest(e); + serverTelemetryManager.cacheFailedRequest(e); throw e; } } @@ -137,17 +140,18 @@ export abstract class ClientApplication { */ async acquireTokenSilent(request: SilentFlowRequest): Promise { const validRequest = this.initializeRequest(request) as SilentFlowRequest; - const telemetryManager = new ServerTelemetryManager(this.storage, ApiId.acquireTokenSilent, validRequest.correlationId!, validRequest.forceRefresh); + const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenSilent, validRequest.correlationId!, validRequest.forceRefresh); try { const silentFlowClientConfig = await this.buildOauthClientConfiguration( - request.authority + request.authority, + serverTelemetryManager ); const silentFlowClient = new SilentFlowClient( silentFlowClientConfig ); - return silentFlowClient.acquireToken(validRequest, telemetryManager); + return silentFlowClient.acquireToken(validRequest); } catch (e) { - telemetryManager.cacheFailedRequest(e); + serverTelemetryManager.cacheFailedRequest(e); throw e; } } @@ -160,7 +164,7 @@ export abstract class ClientApplication { return this.tokenCache; } - protected async buildOauthClientConfiguration(authority?: string): Promise { + protected async buildOauthClientConfiguration(authority?: string, serverTelemetryManager?: ServerTelemetryManager): Promise { this.logger.verbose("buildOauthClientConfiguration called"); // using null assertion operator as we ensure that all config values have default values in buildConfiguration() return { @@ -179,6 +183,7 @@ export abstract class ClientApplication { cryptoInterface: this.cryptoProvider, networkInterface: this.config.system!.networkClient, storageInterface: this.storage, + serverTelemetryManager: serverTelemetryManager, libraryInfo: { sku: NodeConstants.MSAL_SKU, version: version, @@ -202,6 +207,17 @@ export abstract class ClientApplication { }; } + protected initializeServerTelemetryManager(apiId: number, correlationId: string, forceRefresh?: boolean): ServerTelemetryManager { + const telemetryPayload: ServerTelemetryRequest = { + clientId: this.config.auth.clientId, + correlationId: correlationId, + apiId: apiId, + forceRefresh: forceRefresh || false + }; + + return new ServerTelemetryManager(telemetryPayload, this.storage); + } + /** * Create authority instance. If authority not passed in request, default to authority set on the application * object. If no authority set in application object, then default to common authority. diff --git a/lib/msal-node/src/client/PublicClientApplication.ts b/lib/msal-node/src/client/PublicClientApplication.ts index 042350e4a1..2031b33dfc 100644 --- a/lib/msal-node/src/client/PublicClientApplication.ts +++ b/lib/msal-node/src/client/PublicClientApplication.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. */ -import { DeviceCodeClient, DeviceCodeRequest, AuthenticationResult, ServerTelemetryManager } from '@azure/msal-common'; +import { DeviceCodeClient, DeviceCodeRequest, AuthenticationResult } from '@azure/msal-common'; import { Configuration } from '../config/Configuration'; import { ClientApplication } from './ClientApplication'; import { ApiId } from '../utils/Constants'; @@ -46,16 +46,17 @@ export class PublicClientApplication extends ClientApplication { public async acquireTokenByDeviceCode(request: DeviceCodeRequest): Promise { this.logger.info("acquireTokenByDeviceCode called"); const validRequest = this.initializeRequest(request) as DeviceCodeRequest; - const telemetryManager = new ServerTelemetryManager(this.storage, ApiId.acquireTokenByDeviceCode, validRequest.correlationId!); + const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenByDeviceCode, validRequest.correlationId!); try { const deviceCodeConfig = await this.buildOauthClientConfiguration( - request.authority + request.authority, + serverTelemetryManager ); this.logger.verbose("Auth client config generated"); const deviceCodeClient = new DeviceCodeClient(deviceCodeConfig); - return deviceCodeClient.acquireToken(validRequest, telemetryManager); + return deviceCodeClient.acquireToken(validRequest); } catch (e) { - telemetryManager.cacheFailedRequest(e); + serverTelemetryManager.cacheFailedRequest(e); throw e; } } From 24ed043c5abf43d8e50ee021a0e17cc302aef06c Mon Sep 17 00:00:00 2001 From: Thomas Norling Date: Thu, 6 Aug 2020 10:17:41 -0700 Subject: [PATCH 09/14] Track suberror if it is present --- lib/msal-common/src/error/AuthError.ts | 4 +++- .../src/telemetry/server/ServerTelemetryManager.ts | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/msal-common/src/error/AuthError.ts b/lib/msal-common/src/error/AuthError.ts index 598c1dd5df..fcfcde4313 100644 --- a/lib/msal-common/src/error/AuthError.ts +++ b/lib/msal-common/src/error/AuthError.ts @@ -22,14 +22,16 @@ export class AuthError extends Error { errorCode: string; // Detailed description of error errorMessage: string; + suberror: string; - constructor(errorCode: string, errorMessage?: string) { + constructor(errorCode: string, errorMessage?: string, suberror?: string) { const errorString = errorMessage ? `${errorCode}: ${errorMessage}` : errorCode; super(errorString); Object.setPrototypeOf(this, AuthError.prototype); this.errorCode = errorCode; this.errorMessage = errorMessage; + this.suberror = suberror; this.name = "AuthError"; } diff --git a/lib/msal-common/src/telemetry/server/ServerTelemetryManager.ts b/lib/msal-common/src/telemetry/server/ServerTelemetryManager.ts index 31be2a91b2..e5c7ce9875 100644 --- a/lib/msal-common/src/telemetry/server/ServerTelemetryManager.ts +++ b/lib/msal-common/src/telemetry/server/ServerTelemetryManager.ts @@ -8,6 +8,7 @@ import { CacheManager } from "../../cache/CacheManager"; import { ServerTelemetryCacheValue } from "./ServerTelemetryCacheValue"; import { AuthError } from "../../error/AuthError"; import { ServerTelemetryRequest } from "./ServerTelemetryRequest"; +import { StringUtils } from '../../utils/StringUtils'; export class ServerTelemetryManager { private cacheManager: CacheManager; @@ -49,7 +50,7 @@ export class ServerTelemetryManager { cacheFailedRequest(error: AuthError): void { const lastRequests = this.getLastRequests(); lastRequests.failedRequests.push(this.apiId, this.correlationId); - lastRequests.errors.push(error.errorCode); + lastRequests.errors.push(StringUtils.isEmpty(error.suberror)? error.errorCode: error.suberror); lastRequests.errorCount += 1; if (lastRequests.errors.length > SERVER_TELEM_CONSTANTS.FAILURE_LIMIT) { From f3c6baa306477b0d8d613260f869fadf6464f3ca Mon Sep 17 00:00:00 2001 From: Thomas Norling Date: Thu, 6 Aug 2020 10:32:53 -0700 Subject: [PATCH 10/14] Fix lint --- lib/msal-common/src/telemetry/server/ServerTelemetryManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msal-common/src/telemetry/server/ServerTelemetryManager.ts b/lib/msal-common/src/telemetry/server/ServerTelemetryManager.ts index e5c7ce9875..869cb379ff 100644 --- a/lib/msal-common/src/telemetry/server/ServerTelemetryManager.ts +++ b/lib/msal-common/src/telemetry/server/ServerTelemetryManager.ts @@ -8,7 +8,7 @@ import { CacheManager } from "../../cache/CacheManager"; import { ServerTelemetryCacheValue } from "./ServerTelemetryCacheValue"; import { AuthError } from "../../error/AuthError"; import { ServerTelemetryRequest } from "./ServerTelemetryRequest"; -import { StringUtils } from '../../utils/StringUtils'; +import { StringUtils } from "../../utils/StringUtils"; export class ServerTelemetryManager { private cacheManager: CacheManager; From 7d760ac30b61854db745dedd96007b05935117f3 Mon Sep 17 00:00:00 2001 From: Thomas Norling Date: Wed, 2 Sep 2020 13:00:21 -0700 Subject: [PATCH 11/14] Fix build --- lib/msal-node/src/client/ClientApplication.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/msal-node/src/client/ClientApplication.ts b/lib/msal-node/src/client/ClientApplication.ts index bac3f49cbd..0df66112c6 100644 --- a/lib/msal-node/src/client/ClientApplication.ts +++ b/lib/msal-node/src/client/ClientApplication.ts @@ -26,7 +26,6 @@ import { import { Configuration, buildAppConfiguration } from '../config/Configuration'; import { CryptoProvider } from '../crypto/CryptoProvider'; import { Storage } from '../cache/Storage'; -import { version } from '../../package.json'; import { Constants as NodeConstants, ApiId } from './../utils/Constants'; import { TokenCache } from '../cache/TokenCache'; import { ClientAssertion } from "../client/ClientAssertion"; From 1872900d149b60436ef59fd41ab542c58c32e8f1 Mon Sep 17 00:00:00 2001 From: Thomas Norling Date: Wed, 2 Sep 2020 13:01:47 -0700 Subject: [PATCH 12/14] Change files --- ...mmon-2020-09-02-13-01-47-msal-node-MSER-Telemetry.json | 8 ++++++++ ...node-2020-09-02-13-01-47-msal-node-MSER-Telemetry.json | 8 ++++++++ 2 files changed, 16 insertions(+) create mode 100644 change/@azure-msal-common-2020-09-02-13-01-47-msal-node-MSER-Telemetry.json create mode 100644 change/@azure-msal-node-2020-09-02-13-01-47-msal-node-MSER-Telemetry.json diff --git a/change/@azure-msal-common-2020-09-02-13-01-47-msal-node-MSER-Telemetry.json b/change/@azure-msal-common-2020-09-02-13-01-47-msal-node-MSER-Telemetry.json new file mode 100644 index 0000000000..9f56153702 --- /dev/null +++ b/change/@azure-msal-common-2020-09-02-13-01-47-msal-node-MSER-Telemetry.json @@ -0,0 +1,8 @@ +{ + "type": "patch", + "comment": "Track Suberrors in Telemetry (#1921)", + "packageName": "@azure/msal-common", + "email": "thomas.norling@microsoft.com", + "dependentChangeType": "patch", + "date": "2020-09-02T20:01:33.353Z" +} diff --git a/change/@azure-msal-node-2020-09-02-13-01-47-msal-node-MSER-Telemetry.json b/change/@azure-msal-node-2020-09-02-13-01-47-msal-node-MSER-Telemetry.json new file mode 100644 index 0000000000..e1aa28f620 --- /dev/null +++ b/change/@azure-msal-node-2020-09-02-13-01-47-msal-node-MSER-Telemetry.json @@ -0,0 +1,8 @@ +{ + "type": "prerelease", + "comment": "Implement Telemetry in msal-node (#1921)", + "packageName": "@azure/msal-node", + "email": "thomas.norling@microsoft.com", + "dependentChangeType": "patch", + "date": "2020-09-02T20:01:47.198Z" +} From 01897d5ec6c0b9a28d3de63a5faff52b478ae6be Mon Sep 17 00:00:00 2001 From: Thomas Norling Date: Thu, 3 Sep 2020 16:09:07 -0700 Subject: [PATCH 13/14] Add Client Credential flow --- .../client/ConfidentialClientApplication.ts | 21 +++++++++++++------ lib/msal-node/src/utils/Constants.ts | 3 ++- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/msal-node/src/client/ConfidentialClientApplication.ts b/lib/msal-node/src/client/ConfidentialClientApplication.ts index e91e4afe13..203816983c 100644 --- a/lib/msal-node/src/client/ConfidentialClientApplication.ts +++ b/lib/msal-node/src/client/ConfidentialClientApplication.ts @@ -7,6 +7,7 @@ import { ClientApplication } from './ClientApplication'; import { Configuration } from "../config/Configuration"; import { ClientAssertion } from "../client/ClientAssertion"; import { ClientCredentialRequest, ClientCredentialClient, AuthenticationResult, StringUtils, ClientAuthError } from '@azure/msal-common'; +import { ApiId } from "../utils/Constants"; export class ConfidentialClientApplication extends ClientApplication { @@ -40,12 +41,20 @@ export class ConfidentialClientApplication extends ClientApplication { */ public async acquireTokenByClientCredential(request: ClientCredentialRequest): Promise { this.logger.info("acquireTokenByClientCredential called"); - const clientCredentialConfig = await this.buildOauthClientConfiguration( - request.authority - ); - this.logger.verbose("Auth client config generated"); - const clientCredentialClient = new ClientCredentialClient(clientCredentialConfig); - return clientCredentialClient.acquireToken(request); + const validRequest = this.initializeRequest(request) as ClientCredentialRequest; + const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenByClientCredential, validRequest.correlationId!, validRequest.skipCache); + try { + const clientCredentialConfig = await this.buildOauthClientConfiguration( + request.authority, + serverTelemetryManager + ); + this.logger.verbose("Auth client config generated"); + const clientCredentialClient = new ClientCredentialClient(clientCredentialConfig); + return clientCredentialClient.acquireToken(request); + } catch(e) { + serverTelemetryManager.cacheFailedRequest(e); + throw e; + } } private setClientCredential(configuration: Configuration): void { diff --git a/lib/msal-node/src/utils/Constants.ts b/lib/msal-node/src/utils/Constants.ts index cedf4ecb24..ae3e076dac 100644 --- a/lib/msal-node/src/utils/Constants.ts +++ b/lib/msal-node/src/utils/Constants.ts @@ -58,7 +58,8 @@ export enum ApiId { acquireTokenSilent = 62, acquireTokenByCode = 871, acquireTokenByRefreshToken = 872, - acquireTokenByDeviceCode = 671 + acquireTokenByDeviceCode = 671, + acquireTokenByClientCredential = 771 }; /** From 0475b8d79799c4bb1b983434f8a83272fb836740 Mon Sep 17 00:00:00 2001 From: Thomas Norling Date: Thu, 10 Sep 2020 10:48:49 -0700 Subject: [PATCH 14/14] Fix lint --- lib/msal-node/src/client/PublicClientApplication.ts | 2 +- lib/msal-node/src/utils/Constants.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/msal-node/src/client/PublicClientApplication.ts b/lib/msal-node/src/client/PublicClientApplication.ts index 0f683177c6..9acb132e7c 100644 --- a/lib/msal-node/src/client/PublicClientApplication.ts +++ b/lib/msal-node/src/client/PublicClientApplication.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. */ -import { ApiId } from '../utils/Constants'; +import { ApiId } from "../utils/Constants"; import { DeviceCodeClient, DeviceCodeRequest, AuthenticationResult } from "@azure/msal-common"; import { Configuration } from "../config/Configuration"; import { ClientApplication } from "./ClientApplication"; diff --git a/lib/msal-node/src/utils/Constants.ts b/lib/msal-node/src/utils/Constants.ts index a7b2c556d4..7df7dc1202 100644 --- a/lib/msal-node/src/utils/Constants.ts +++ b/lib/msal-node/src/utils/Constants.ts @@ -60,7 +60,7 @@ export enum ApiId { acquireTokenByRefreshToken = 872, acquireTokenByDeviceCode = 671, acquireTokenByClientCredential = 771 -}; +} /** * JWT constants